about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>2017-07-28 16:48:43 +0200
committerOliver Schneider <git-spam-no-reply9815368754983@oli-obk.de>2017-08-01 09:56:21 +0200
commitadfea61665385428b9c9aced9442dba65464c3c8 (patch)
treed0b1bf5d67af2175cf65737c60be83c57ef8fdb3
parent7ed706d09c68469a7540f01efbfa5c4f6e3603b9 (diff)
downloadrust-adfea61665385428b9c9aced9442dba65464c3c8.tar.gz
rust-adfea61665385428b9c9aced9442dba65464c3c8.zip
Allow machines to create new memory kinds
-rw-r--r--miri/fn_call.rs20
-rw-r--r--miri/lib.rs26
-rw-r--r--miri/memory.rs16
-rw-r--r--src/librustc_mir/interpret/const_eval.rs12
-rw-r--r--src/librustc_mir/interpret/error.rs14
-rw-r--r--src/librustc_mir/interpret/eval_context.rs13
-rw-r--r--src/librustc_mir/interpret/machine.rs14
-rw-r--r--src/librustc_mir/interpret/memory.rs75
-rw-r--r--src/librustc_mir/lib.rs1
-rw-r--r--tests/compile-fail/stack_free.rs2
10 files changed, 131 insertions, 62 deletions
diff --git a/miri/fn_call.rs b/miri/fn_call.rs
index d8e92e7291f..cf3464ce3af 100644
--- a/miri/fn_call.rs
+++ b/miri/fn_call.rs
@@ -15,6 +15,8 @@ use super::{
     MemoryExt,
 };
 
+use super::memory::Kind;
+
 pub trait EvalContextExt<'tcx> {
     fn call_c_abi(
         &mut self,
@@ -110,7 +112,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
                     self.write_null(dest, dest_ty)?;
                 } else {
                     let align = self.memory.pointer_size();
-                    let ptr = self.memory.allocate(size, align, Kind::C)?;
+                    let ptr = self.memory.allocate(size, align, Kind::C.into())?;
                     self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
                 }
             }
@@ -118,7 +120,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
             "free" => {
                 let ptr = args[0].into_ptr(&mut self.memory)?;
                 if !ptr.is_null()? {
-                    self.memory.deallocate(ptr.to_ptr()?, None, Kind::C)?;
+                    self.memory.deallocate(ptr.to_ptr()?, None, Kind::C.into())?;
                 }
             }
 
@@ -242,7 +244,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
                 }
                 if let Some(old) = success {
                     if let Some(var) = old {
-                        self.memory.deallocate(var, None, Kind::Env)?;
+                        self.memory.deallocate(var, None, Kind::Env.into())?;
                     }
                     self.write_null(dest, dest_ty)?;
                 } else {
@@ -265,12 +267,12 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
                 }
                 if let Some((name, value)) = new {
                     // +1 for the null terminator
-                    let value_copy = self.memory.allocate((value.len() + 1) as u64, 1, Kind::Env)?;
+                    let value_copy = self.memory.allocate((value.len() + 1) as u64, 1, Kind::Env.into())?;
                     self.memory.write_bytes(value_copy.into(), &value)?;
                     let trailing_zero_ptr = value_copy.offset(value.len() as u64, &self)?.into();
                     self.memory.write_bytes(trailing_zero_ptr, &[0])?;
                     if let Some(var) = self.machine_data.env_vars.insert(name.to_owned(), value_copy) {
-                        self.memory.deallocate(var, None, Kind::Env)?;
+                        self.memory.deallocate(var, None, Kind::Env.into())?;
                     }
                     self.write_null(dest, dest_ty)?;
                 } else {
@@ -491,7 +493,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
                 if !align.is_power_of_two() {
                     return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(align));
                 }
-                let ptr = self.memory.allocate(size, align, Kind::Rust)?;
+                let ptr = self.memory.allocate(size, align, Kind::Rust.into())?;
                 self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
             }
             "alloc::heap::::__rust_alloc_zeroed" => {
@@ -503,7 +505,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
                 if !align.is_power_of_two() {
                     return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(align));
                 }
-                let ptr = self.memory.allocate(size, align, Kind::Rust)?;
+                let ptr = self.memory.allocate(size, align, Kind::Rust.into())?;
                 self.memory.write_repeat(ptr.into(), 0, size)?;
                 self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
             }
@@ -517,7 +519,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
                 if !align.is_power_of_two() {
                     return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(align));
                 }
-                self.memory.deallocate(ptr, Some((old_size, align)), Kind::Rust)?;
+                self.memory.deallocate(ptr, Some((old_size, align)), Kind::Rust.into())?;
             }
             "alloc::heap::::__rust_realloc" => {
                 let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
@@ -534,7 +536,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
                 if !new_align.is_power_of_two() {
                     return Err(EvalError::HeapAllocNonPowerOfTwoAlignment(new_align));
                 }
-                let new_ptr = self.memory.reallocate(ptr, old_size, old_align, new_size, new_align, Kind::Rust)?;
+                let new_ptr = self.memory.reallocate(ptr, old_size, old_align, new_size, new_align, Kind::Rust.into())?;
                 self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?;
             }
 
diff --git a/miri/lib.rs b/miri/lib.rs
index c32c8105e33..89985593bc7 100644
--- a/miri/lib.rs
+++ b/miri/lib.rs
@@ -32,6 +32,7 @@ mod fn_call;
 mod operator;
 mod intrinsic;
 mod helpers;
+mod memory;
 
 use fn_call::EvalContextExt as MissingFnsEvalContextExt;
 use operator::EvalContextExt as OperatorEvalContextExt;
@@ -278,6 +279,7 @@ impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator> {
 impl<'tcx> Machine<'tcx> for Evaluator {
     type Data = EvaluatorData;
     type MemoryData = MemoryData<'tcx>;
+    type MemoryKinds = memory::Kind;
 
     /// Returns Ok() when the function was handled, fail otherwise
     fn eval_fn_call<'a>(
@@ -313,4 +315,28 @@ impl<'tcx> Machine<'tcx> for Evaluator {
     ) -> EvalResult<'tcx, Option<(PrimVal, bool)>> {
         ecx.ptr_op(bin_op, left, left_ty, right, right_ty)
     }
+
+    fn mark_static_initialized(m: memory::Kind) -> EvalResult<'tcx> {
+        use memory::Kind::*;
+        match m {
+            // FIXME: This could be allowed, but not for env vars set during miri execution
+            Env => Err(EvalError::Unimplemented("statics can't refer to env vars".to_owned())),
+            _ => Ok(()),
+        }
+    }
+
+    fn box_alloc<'a>(
+        ecx: &mut EvalContext<'a, 'tcx, Self>,
+        ty: ty::Ty<'tcx>,
+    ) -> EvalResult<'tcx, PrimVal> {
+        let size = ecx.type_size(ty)?.expect("box only works with sized types");
+        let align = ecx.type_align(ty)?;
+        if size == 0 {
+            Ok(PrimVal::Bytes(align.into()))
+        } else {
+            ecx.memory
+                .allocate(size, align, Kind::Machine(memory::Kind::Rust))
+                .map(PrimVal::Ptr)
+        }
+    }
 }
diff --git a/miri/memory.rs b/miri/memory.rs
new file mode 100644
index 00000000000..55e6026280c
--- /dev/null
+++ b/miri/memory.rs
@@ -0,0 +1,16 @@
+
+#[derive(Debug, PartialEq, Copy, Clone)]
+pub enum Kind {
+    /// Error if deallocated any other way than `rust_deallocate`
+    Rust,
+    /// Error if deallocated any other way than `free`
+    C,
+    /// Part of env var emulation
+    Env,
+}
+
+impl Into<::rustc_miri::interpret::Kind<Kind>> for Kind {
+    fn into(self) -> ::rustc_miri::interpret::Kind<Kind> {
+        ::rustc_miri::interpret::Kind::Machine(self)
+    }
+}
diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs
index 604ef15e904..8a0b6d5b692 100644
--- a/src/librustc_mir/interpret/const_eval.rs
+++ b/src/librustc_mir/interpret/const_eval.rs
@@ -128,6 +128,7 @@ impl Error for ConstEvalError {
 impl<'tcx> super::Machine<'tcx> for CompileTimeFunctionEvaluator {
     type Data = ();
     type MemoryData = ();
+    type MemoryKinds = !;
     fn eval_fn_call<'a>(
         ecx: &mut EvalContext<'a, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
@@ -185,4 +186,15 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeFunctionEvaluator {
     ) -> EvalResult<'tcx, Option<(PrimVal, bool)>> {
         Err(ConstEvalError::NeedsRfc("Pointer arithmetic or comparison".to_string()).into())
     }
+
+    fn mark_static_initialized(m: !) -> EvalResult<'tcx> {
+        m
+    }
+
+    fn box_alloc<'a>(
+        _ecx: &mut EvalContext<'a, 'tcx, Self>,
+        _ty: ty::Ty<'tcx>,
+    ) -> EvalResult<'tcx, PrimVal> {
+        Err(ConstEvalError::NeedsRfc("Heap allocations via `box` keyword".to_string()).into())
+    }
 }
diff --git a/src/librustc_mir/interpret/error.rs b/src/librustc_mir/interpret/error.rs
index dd718c737af..7d62d59fcd7 100644
--- a/src/librustc_mir/interpret/error.rs
+++ b/src/librustc_mir/interpret/error.rs
@@ -4,7 +4,7 @@ use rustc::mir;
 use rustc::ty::{FnSig, Ty, layout};
 
 use super::{
-    MemoryPointer, Kind, LockInfo, AccessKind
+    MemoryPointer, LockInfo, AccessKind
 };
 
 use rustc_const_math::ConstMathErr;
@@ -88,8 +88,8 @@ pub enum EvalError<'tcx> {
     AssumptionNotHeld,
     InlineAsm,
     TypeNotPrimitive(Ty<'tcx>),
-    ReallocatedWrongMemoryKind(Kind, Kind),
-    DeallocatedWrongMemoryKind(Kind, Kind),
+    ReallocatedWrongMemoryKind(String, String),
+    DeallocatedWrongMemoryKind(String, String),
     ReallocateNonBasePtr,
     DeallocateNonBasePtr,
     IncorrectAllocationInformation,
@@ -262,10 +262,10 @@ impl<'tcx> fmt::Display for EvalError<'tcx> {
                 write!(f, "tried to call a function with sig {} through a function pointer of type {}", sig, got),
             ArrayIndexOutOfBounds(span, len, index) =>
                 write!(f, "index out of bounds: the len is {} but the index is {} at {:?}", len, index, span),
-            ReallocatedWrongMemoryKind(old, new) =>
-                write!(f, "tried to reallocate memory from {:?} to {:?}", old, new),
-            DeallocatedWrongMemoryKind(old, new) =>
-                write!(f, "tried to deallocate {:?} memory but gave {:?} as the kind", old, new),
+            ReallocatedWrongMemoryKind(ref old, ref new) =>
+                write!(f, "tried to reallocate memory from {} to {}", old, new),
+            DeallocatedWrongMemoryKind(ref old, ref new) =>
+                write!(f, "tried to deallocate {} memory but gave {} as the kind", old, new),
             Math(span, ref err) =>
                 write!(f, "{:?} at {:?}", err, span),
             Intrinsic(ref err) =>
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index f5082a4d2d8..277e6e99e75 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -782,17 +782,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             }
 
             NullaryOp(mir::NullOp::Box, ty) => {
-                // FIXME(CTFE): don't allow heap allocations in const eval
-                // FIXME: call the `exchange_malloc` lang item if available
-                let size = self.type_size(ty)?.expect("box only works with sized types");
-                if size == 0 {
-                    let align = self.type_align(ty)?;
-                    self.write_primval(dest, PrimVal::Bytes(align.into()), dest_ty)?;
-                } else {
-                    let align = self.type_align(ty)?;
-                    let ptr = self.memory.allocate(size, align, MemoryKind::Rust)?;
-                    self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
-                }
+                let ptr = M::box_alloc(self, ty)?;
+                self.write_primval(dest, ptr, dest_ty)?;
             }
 
             NullaryOp(mir::NullOp::SizeOf, ty) => {
diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs
index adb1054af1d..140bd946c78 100644
--- a/src/librustc_mir/interpret/machine.rs
+++ b/src/librustc_mir/interpret/machine.rs
@@ -21,6 +21,9 @@ pub trait Machine<'tcx>: Sized {
     /// Additional data that can be accessed via the Memory
     type MemoryData;
 
+    /// Additional memory kinds a machine wishes to distinguish from the builtin ones
+    type MemoryKinds: ::std::fmt::Debug + PartialEq + Copy + Clone;
+
     /// Entry point to all function calls.
     ///
     /// Returns Ok(true) when the function was handled completely
@@ -61,5 +64,16 @@ pub trait Machine<'tcx>: Sized {
         right: PrimVal,
         right_ty: ty::Ty<'tcx>,
     ) -> EvalResult<'tcx, Option<(PrimVal, bool)>>;
+
+    /// Called when trying to mark machine defined `MemoryKinds` as static
+    fn mark_static_initialized(m: Self::MemoryKinds) -> EvalResult<'tcx>;
+
+    /// Heap allocations via the `box` keyword
+    ///
+    /// Returns a pointer to the allocated memory
+    fn box_alloc<'a>(
+        ecx: &mut EvalContext<'a, 'tcx, Self>,
+        ty: ty::Ty<'tcx>,
+    ) -> EvalResult<'tcx, PrimVal>;
 }
 
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index e8701d1e64c..31e47e706ad 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -116,7 +116,7 @@ impl fmt::Display for AllocId {
 }
 
 #[derive(Debug)]
-pub struct Allocation {
+pub struct Allocation<M> {
     /// The actual bytes of the allocation.
     /// Note that the bytes of a pointer represent the offset of the pointer
     pub bytes: Vec<u8>,
@@ -132,12 +132,12 @@ pub struct Allocation {
     /// Use the `mark_static_initalized` method of `Memory` to ensure that an error occurs, if the memory of this
     /// allocation is modified or deallocated in the future.
     /// Helps guarantee that stack allocations aren't deallocated via `rust_deallocate`
-    pub kind: Kind,
+    pub kind: Kind<M>,
     /// Memory regions that are locked by some function
     locks: BTreeMap<MemoryRange, LockInfo>,
 }
 
-impl Allocation {
+impl<M> Allocation<M> {
     fn iter_locks<'a>(&'a self, offset: u64, len: u64) -> impl Iterator<Item=(&'a MemoryRange, &'a LockInfo)> + 'a {
         self.locks.range(MemoryRange::range(offset, len))
             .filter(move |&(range, _)| range.overlaps(offset, len))
@@ -165,11 +165,7 @@ impl Allocation {
 }
 
 #[derive(Debug, PartialEq, Copy, Clone)]
-pub enum Kind {
-    /// Error if deallocated any other way than `rust_deallocate`
-    Rust,
-    /// Error if deallocated any other way than `free`
-    C,
+pub enum Kind<T> {
     /// Error if deallocated except during a stack pop
     Stack,
     /// Static in the process of being initialized.
@@ -179,8 +175,8 @@ pub enum Kind {
     UninitializedStatic,
     /// May never be deallocated
     Static,
-    /// Part of env var emulation
-    Env,
+    /// Additional memory kinds a machine wishes to distinguish from the builtin ones
+    Machine(T),
 }
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
@@ -226,7 +222,7 @@ pub struct Memory<'a, 'tcx, M: Machine<'tcx>> {
     pub data: M::MemoryData,
 
     /// Actual memory allocations (arbitrary bytes, may contain pointers into other allocations).
-    alloc_map: HashMap<AllocId, Allocation>,
+    alloc_map: HashMap<AllocId, Allocation<M::MemoryKinds>>,
 
     /// The AllocId to assign to the next new allocation. Always incremented, never gets smaller.
     next_id: AllocId,
@@ -285,7 +281,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
         }
     }
 
-    pub fn allocations(&self) -> ::std::collections::hash_map::Iter<AllocId, Allocation> {
+    pub fn allocations(&self) -> ::std::collections::hash_map::Iter<AllocId, Allocation<M::MemoryKinds>> {
         self.alloc_map.iter()
     }
 
@@ -313,7 +309,12 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
         Ok(ptr)
     }
 
-    pub fn allocate(&mut self, size: u64, align: u64, kind: Kind) -> EvalResult<'tcx, MemoryPointer> {
+    pub fn allocate(
+        &mut self,
+        size: u64,
+        align: u64,
+        kind: Kind<M::MemoryKinds>,
+    ) -> EvalResult<'tcx, MemoryPointer> {
         assert_ne!(align, 0);
         assert!(align.is_power_of_two());
 
@@ -341,7 +342,15 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
         Ok(MemoryPointer::new(id, 0))
     }
 
-    pub fn reallocate(&mut self, ptr: MemoryPointer, old_size: u64, old_align: u64, new_size: u64, new_align: u64, kind: Kind) -> EvalResult<'tcx, MemoryPointer> {
+    pub fn reallocate(
+        &mut self,
+        ptr: MemoryPointer,
+        old_size: u64,
+        old_align: u64,
+        new_size: u64,
+        new_align: u64,
+        kind: Kind<M::MemoryKinds>,
+    ) -> EvalResult<'tcx, MemoryPointer> {
         use std::cmp::min;
 
         if ptr.offset != 0 {
@@ -349,7 +358,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
         }
         if let Ok(alloc) = self.get(ptr.alloc_id) {
             if alloc.kind != kind {
-                return Err(EvalError::ReallocatedWrongMemoryKind(alloc.kind, kind));
+                return Err(EvalError::ReallocatedWrongMemoryKind(format!("{:?}", alloc.kind), format!("{:?}", kind)));
             }
         }
 
@@ -361,7 +370,12 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
         Ok(new_ptr)
     }
 
-    pub fn deallocate(&mut self, ptr: MemoryPointer, size_and_align: Option<(u64, u64)>, kind: Kind) -> EvalResult<'tcx> {
+    pub fn deallocate(
+        &mut self,
+        ptr: MemoryPointer,
+        size_and_align: Option<(u64, u64)>,
+        kind: Kind<M::MemoryKinds>,
+    ) -> EvalResult<'tcx> {
         if ptr.offset != 0 {
             return Err(EvalError::DeallocateNonBasePtr);
         }
@@ -380,7 +394,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
             .map_err(|lock| EvalError::DeallocatedLockedMemory { ptr, lock })?;
 
         if alloc.kind != kind {
-            return Err(EvalError::DeallocatedWrongMemoryKind(alloc.kind, kind));
+            return Err(EvalError::DeallocatedWrongMemoryKind(format!("{:?}", alloc.kind), format!("{:?}", kind)));
         }
         if let Some((size, align)) = size_and_align {
             if size != alloc.bytes.len() as u64 || align != alloc.align {
@@ -573,7 +587,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
 
 /// Allocation accessors
 impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
-    pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation> {
+    pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation<M::MemoryKinds>> {
         match self.alloc_map.get(&id) {
             Some(alloc) => Ok(alloc),
             None => match self.functions.get(&id) {
@@ -583,7 +597,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
         }
     }
     
-    fn get_mut_unchecked(&mut self, id: AllocId) -> EvalResult<'tcx, &mut Allocation> {
+    fn get_mut_unchecked(&mut self, id: AllocId) -> EvalResult<'tcx, &mut Allocation<M::MemoryKinds>> {
         match self.alloc_map.get_mut(&id) {
             Some(alloc) => Ok(alloc),
             None => match self.functions.get(&id) {
@@ -593,7 +607,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
         }
     }
 
-    pub fn get_mut(&mut self, id: AllocId) -> EvalResult<'tcx, &mut Allocation> {
+    pub fn get_mut(&mut self, id: AllocId) -> EvalResult<'tcx, &mut Allocation<M::MemoryKinds>> {
         let alloc = self.get_mut_unchecked(id)?;
         if alloc.mutable == Mutability::Mutable {
             Ok(alloc)
@@ -663,13 +677,11 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
             }
 
             let immutable = match (alloc.kind, alloc.mutable) {
-                (Kind::UninitializedStatic, _) => " (static in the process of initialization)",
-                (Kind::Static, Mutability::Mutable) => " (static mut)",
-                (Kind::Static, Mutability::Immutable) => " (immutable)",
-                (Kind::Env, _) => " (env var)",
-                (Kind::C, _) => " (malloc)",
-                (Kind::Rust, _) => " (heap)",
-                (Kind::Stack, _) => " (stack)",
+                (Kind::UninitializedStatic, _) => " (static in the process of initialization)".to_owned(),
+                (Kind::Static, Mutability::Mutable) => " (static mut)".to_owned(),
+                (Kind::Static, Mutability::Immutable) => " (immutable)".to_owned(),
+                (Kind::Machine(m), _) => format!(" ({:?})", m),
+                (Kind::Stack, _) => " (stack)".to_owned(),
             };
             trace!("{}({} bytes, alignment {}){}", msg, alloc.bytes.len(), alloc.align, immutable);
 
@@ -793,17 +805,12 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
                     // E.g. `const Foo: &u32 = &1;` refers to the temp local that stores the `1`
                     Kind::Stack |
                     // The entire point of this function
-                    Kind::UninitializedStatic |
-                    // In the future const eval will allow heap allocations so we'll need to protect them
-                    // from deallocation, too
-                    Kind::Rust |
-                    Kind::C => {},
+                    Kind::UninitializedStatic => {},
+                    Kind::Machine(m) => M::mark_static_initialized(m)?,
                     Kind::Static => {
                         trace!("mark_static_initalized: skipping already initialized static referred to by static currently being initialized");
                         return Ok(());
                     },
-                    // FIXME: This could be allowed, but not for env vars set during miri execution
-                    Kind::Env => return Err(EvalError::Unimplemented("statics can't refer to env vars".to_owned())),
                 }
                 *kind = Kind::Static;
                 *mutable = mutability;
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index 46a570349f0..960b73ee6b2 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -2,6 +2,7 @@
     i128_type,
     rustc_private,
     conservative_impl_trait,
+    never_type,
 )]
 
 // From rustc.
diff --git a/tests/compile-fail/stack_free.rs b/tests/compile-fail/stack_free.rs
index 08ff7457b76..96006c884e5 100644
--- a/tests/compile-fail/stack_free.rs
+++ b/tests/compile-fail/stack_free.rs
@@ -1,4 +1,4 @@
-// error-pattern: tried to deallocate Stack memory but gave Rust as the kind
+// error-pattern: tried to deallocate Stack memory but gave Machine(Rust) as the kind
 
 fn main() {
     let x = 42;