From adc3bebe08818631d72f2110d65592f0d3e815c7 Mon Sep 17 00:00:00 2001 From: Amit Aryeh Levy Date: Wed, 25 Jul 2018 10:04:22 -0400 Subject: [PATCH] Allow MapCell's `new` to be const Uses a trick stolen from @japaric here: https://github.com/rust-lang/rust/pull/50150 to avoid using `mem::uninitialized`, which isn't currently marked `const` --- libraries/tock-cells/src/lib.rs | 2 +- libraries/tock-cells/src/map_cell.rs | 28 ++++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/libraries/tock-cells/src/lib.rs b/libraries/tock-cells/src/lib.rs index 5098d7555b..c6e53df7aa 100644 --- a/libraries/tock-cells/src/lib.rs +++ b/libraries/tock-cells/src/lib.rs @@ -1,6 +1,6 @@ //! Tock Cell types. -#![feature(const_fn)] +#![feature(const_fn, untagged_unions)] #![no_std] pub mod map_cell; diff --git a/libraries/tock-cells/src/map_cell.rs b/libraries/tock-cells/src/map_cell.rs index 62e72d0492..1abff2772b 100644 --- a/libraries/tock-cells/src/map_cell.rs +++ b/libraries/tock-cells/src/map_cell.rs @@ -16,10 +16,34 @@ pub struct MapCell { occupied: Cell, } +// This function allows us to mimic `mem::uninitialized` in a way that can be marked `const`. +// Specifically, we just want to allocate some memory the size of some particular `T` and we don't +// care what's there---this happens to not be marked `cost` in the core library right now since +// it's an LLVM intrinsic. +// +// This uses an unsafe union to do basically the same thing: the union will have the size of the +// larger of the two fields (`T`, since `()` is zero-sized). It then initializes the union with the +// `none` variant (of type `()`), but returns the `some` variant (which is of type `T`), thus +// giving us back something of type `T` with some uninitialized memory. +// +// This is of course wildly unsafe, and should be used with the utmost caution---the value returned +// is _not_ valid! +// +// Credit to @japaric: https://github.com/rust-lang/rust/pull/50150 +const unsafe fn uninitialized() -> T { + #[allow(unions_with_drop_fields)] + union U { + none: (), + some: T, + } + + U { none: () }.some +} + impl MapCell { - pub fn empty() -> MapCell { + pub const fn empty() -> MapCell { MapCell { - val: unsafe { mem::uninitialized() }, + val: unsafe { uninitialized() }, occupied: Cell::new(false), } }