about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--miri/fn_call.rs16
-rw-r--r--miri/intrinsic.rs6
-rw-r--r--miri/lib.rs4
-rw-r--r--src/librustc_mir/interpret/const_eval.rs16
-rw-r--r--src/librustc_mir/interpret/eval_context.rs118
-rw-r--r--src/librustc_mir/interpret/lvalue.rs74
-rw-r--r--src/librustc_mir/interpret/machine.rs4
-rw-r--r--src/librustc_mir/interpret/memory.rs16
-rw-r--r--src/librustc_mir/interpret/mod.rs1
-rw-r--r--src/librustc_mir/interpret/operator.rs4
-rw-r--r--src/librustc_mir/interpret/step.rs26
-rw-r--r--src/librustc_mir/interpret/terminator/drop.rs2
-rw-r--r--src/librustc_mir/interpret/terminator/mod.rs2
-rw-r--r--src/librustc_mir/interpret/validation.rs6
-rw-r--r--src/librustc_mir/interpret/value.rs6
15 files changed, 91 insertions, 210 deletions
diff --git a/miri/fn_call.rs b/miri/fn_call.rs
index 81db48fe129..5cbad8c4f12 100644
--- a/miri/fn_call.rs
+++ b/miri/fn_call.rs
@@ -23,7 +23,7 @@ pub trait EvalContextExt<'tcx> {
         &mut self,
         def_id: DefId,
         arg_operands: &[mir::Operand<'tcx>],
-        dest: Lvalue<'tcx>,
+        dest: Lvalue,
         dest_ty: Ty<'tcx>,
         dest_block: mir::BasicBlock,
     ) -> EvalResult<'tcx>;
@@ -33,7 +33,7 @@ pub trait EvalContextExt<'tcx> {
     fn call_missing_fn(
         &mut self,
         instance: ty::Instance<'tcx>,
-        destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
+        destination: Option<(Lvalue, mir::BasicBlock)>,
         arg_operands: &[mir::Operand<'tcx>],
         sig: ty::FnSig<'tcx>,
         path: String,
@@ -42,7 +42,7 @@ pub trait EvalContextExt<'tcx> {
     fn eval_fn_call(
         &mut self,
         instance: ty::Instance<'tcx>,
-        destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
+        destination: Option<(Lvalue, mir::BasicBlock)>,
         arg_operands: &[mir::Operand<'tcx>],
         span: Span,
         sig: ty::FnSig<'tcx>,
@@ -53,7 +53,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
     fn eval_fn_call(
         &mut self,
         instance: ty::Instance<'tcx>,
-        destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
+        destination: Option<(Lvalue, mir::BasicBlock)>,
         arg_operands: &[mir::Operand<'tcx>],
         span: Span,
         sig: ty::FnSig<'tcx>,
@@ -89,7 +89,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
         &mut self,
         def_id: DefId,
         arg_operands: &[mir::Operand<'tcx>],
-        dest: Lvalue<'tcx>,
+        dest: Lvalue,
         dest_ty: Ty<'tcx>,
         dest_block: mir::BasicBlock,
     ) -> EvalResult<'tcx> {
@@ -329,8 +329,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
                     if let Ok(instance) = self.resolve_path(path) {
                         let cid = GlobalId { instance, promoted: None };
                         // compute global if not cached
-                        let val = match self.globals.get(&cid).map(|glob| glob.value) {
-                            Some(value) => self.value_to_primval(value, usize)?.to_u64()?,
+                        let val = match self.globals.get(&cid).map(|&ptr| ptr) {
+                            Some(ptr) => self.value_to_primval(Value::by_ref(ptr.into()), usize)?.to_u64()?,
                             None => eval_body_as_primval(self.tcx, instance)?.0.to_u64()?,
                         };
                         if val == name {
@@ -459,7 +459,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
     fn call_missing_fn(
         &mut self,
         instance: ty::Instance<'tcx>,
-        destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
+        destination: Option<(Lvalue, mir::BasicBlock)>,
         arg_operands: &[mir::Operand<'tcx>],
         sig: ty::FnSig<'tcx>,
         path: String,
diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs
index 4cdad350b43..053b2da86f7 100644
--- a/miri/intrinsic.rs
+++ b/miri/intrinsic.rs
@@ -18,7 +18,7 @@ pub trait EvalContextExt<'tcx> {
         &mut self,
         instance: ty::Instance<'tcx>,
         args: &[mir::Operand<'tcx>],
-        dest: Lvalue<'tcx>,
+        dest: Lvalue,
         dest_ty: Ty<'tcx>,
         dest_layout: &'tcx Layout,
         target: mir::BasicBlock,
@@ -30,7 +30,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
         &mut self,
         instance: ty::Instance<'tcx>,
         args: &[mir::Operand<'tcx>],
-        dest: Lvalue<'tcx>,
+        dest: Lvalue,
         dest_ty: Ty<'tcx>,
         dest_layout: &'tcx Layout,
         target: mir::BasicBlock,
@@ -291,7 +291,6 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
                     Lvalue::Local { frame, local } => self.modify_local(frame, local, init)?,
                     Lvalue::Ptr { ptr, extra: LvalueExtra::None, aligned: true } => self.memory.write_repeat(ptr, 0, size)?,
                     Lvalue::Ptr { .. } => bug!("init intrinsic tried to write to fat or unaligned ptr target"),
-                    Lvalue::Global(cid) => self.modify_global(cid, init)?,
                 }
             }
 
@@ -469,7 +468,6 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
                     Lvalue::Ptr { ptr, extra: LvalueExtra::None, aligned: true } =>
                         self.memory.mark_definedness(ptr, size, false)?,
                     Lvalue::Ptr { .. } => bug!("uninit intrinsic tried to write to fat or unaligned ptr target"),
-                    Lvalue::Global(cid) => self.modify_global(cid, uninit)?,
                 }
             }
 
diff --git a/miri/lib.rs b/miri/lib.rs
index c887890fabf..1dc1682b17f 100644
--- a/miri/lib.rs
+++ b/miri/lib.rs
@@ -167,7 +167,7 @@ impl<'tcx> Machine<'tcx> for Evaluator {
     fn eval_fn_call<'a>(
         ecx: &mut EvalContext<'a, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
-        destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
+        destination: Option<(Lvalue, mir::BasicBlock)>,
         arg_operands: &[mir::Operand<'tcx>],
         span: Span,
         sig: ty::FnSig<'tcx>,
@@ -179,7 +179,7 @@ impl<'tcx> Machine<'tcx> for Evaluator {
         ecx: &mut rustc_miri::interpret::EvalContext<'a, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         args: &[mir::Operand<'tcx>],
-        dest: Lvalue<'tcx>,
+        dest: Lvalue,
         dest_ty: ty::Ty<'tcx>,
         dest_layout: &'tcx Layout,
         target: mir::BasicBlock,
diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs
index 51f18bccf43..f55c94e67c4 100644
--- a/src/librustc_mir/interpret/const_eval.rs
+++ b/src/librustc_mir/interpret/const_eval.rs
@@ -7,9 +7,10 @@ use syntax::codemap::Span;
 
 use super::{
     EvalResult, EvalError, EvalErrorKind,
-    Global, GlobalId, Lvalue,
+    GlobalId, Lvalue, Value,
     PrimVal,
     EvalContext, StackPopCleanup,
+    Kind,
 };
 
 use rustc_const_math::ConstInt;
@@ -30,7 +31,10 @@ pub fn eval_body_as_primval<'a, 'tcx>(
     
     let mir = ecx.load_mir(instance.def)?;
     if !ecx.globals.contains_key(&cid) {
-        ecx.globals.insert(cid, Global::uninitialized(mir.return_ty));
+        let size = ecx.type_size_with_substs(mir.return_ty, instance.substs)?.expect("unsized global");
+        let align = ecx.type_align_with_substs(mir.return_ty, instance.substs)?;
+        let ptr = ecx.memory.allocate(size, align, Kind::UninitializedStatic)?;
+        ecx.globals.insert(cid, ptr);
         let mutable = !mir.return_ty.is_freeze(
                 ecx.tcx,
                 ty::ParamEnv::empty(Reveal::All),
@@ -47,13 +51,13 @@ pub fn eval_body_as_primval<'a, 'tcx>(
             instance,
             mir.span,
             mir,
-            Lvalue::Global(cid),
+            Lvalue::from_ptr(ptr),
             cleanup,
         )?;
 
         while ecx.step()? {}
     }
-    let value = ecx.globals.get(&cid).expect("global not cached").value;
+    let value = Value::by_ref(ecx.globals.get(&cid).expect("global not cached").into());
     Ok((ecx.value_to_primval(value, mir.return_ty)?, mir.return_ty))
 }
 
@@ -132,7 +136,7 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeFunctionEvaluator {
     fn eval_fn_call<'a>(
         ecx: &mut EvalContext<'a, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
-        destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
+        destination: Option<(Lvalue, mir::BasicBlock)>,
         _arg_operands: &[mir::Operand<'tcx>],
         span: Span,
         _sig: ty::FnSig<'tcx>,
@@ -168,7 +172,7 @@ impl<'tcx> super::Machine<'tcx> for CompileTimeFunctionEvaluator {
         _ecx: &mut EvalContext<'a, 'tcx, Self>,
         _instance: ty::Instance<'tcx>,
         _args: &[mir::Operand<'tcx>],
-        _dest: Lvalue<'tcx>,
+        _dest: Lvalue,
         _dest_ty: Ty<'tcx>,
         _dest_layout: &'tcx layout::Layout,
         _target: mir::BasicBlock,
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index c5ca9712955..beeb07b4ce1 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -18,7 +18,7 @@ use syntax::abi::Abi;
 
 use super::{
     EvalError, EvalResult, EvalErrorKind,
-    Global, GlobalId, Lvalue, LvalueExtra,
+    GlobalId, Lvalue, LvalueExtra,
     Memory, MemoryPointer, HasMemory,
     Kind as MemoryKind,
     operator,
@@ -41,7 +41,7 @@ pub struct EvalContext<'a, 'tcx: 'a, M: Machine<'tcx>> {
     pub(crate) suspended: HashMap<DynamicLifetime, Vec<ValidationQuery<'tcx>>>,
 
     /// Precomputed statics, constants and promoteds.
-    pub globals: HashMap<GlobalId<'tcx>, Global<'tcx>>,
+    pub globals: HashMap<GlobalId<'tcx>, MemoryPointer>,
 
     /// The virtual call stack.
     pub(crate) stack: Vec<Frame<'tcx>>,
@@ -78,7 +78,7 @@ pub struct Frame<'tcx> {
     pub return_to_block: StackPopCleanup,
 
     /// The location where the result of the current stack frame should be written to.
-    pub return_lvalue: Lvalue<'tcx>,
+    pub return_lvalue: Lvalue,
 
     /// The list of locals for this stack frame, stored in order as
     /// `[arguments..., variables..., temporaries...]`. The locals are stored as `Option<Value>`s.
@@ -386,7 +386,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         self.type_align_with_substs(ty, self.substs())
     }
 
-    fn type_size_with_substs(
+    pub fn type_size_with_substs(
         &self,
         ty: Ty<'tcx>,
         substs: &'tcx Substs<'tcx>,
@@ -399,7 +399,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         }
     }
 
-    fn type_align_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, u64> {
+    pub fn type_align_with_substs(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> EvalResult<'tcx, u64> {
         self.type_layout_with_substs(ty, substs).map(|layout| layout.align(&self.tcx.data_layout).abi())
     }
 
@@ -419,7 +419,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         instance: ty::Instance<'tcx>,
         span: codemap::Span,
         mir: &'tcx mir::Mir<'tcx>,
-        return_lvalue: Lvalue<'tcx>,
+        return_lvalue: Lvalue,
         return_to_block: StackPopCleanup,
     ) -> EvalResult<'tcx> {
         ::log_settings::settings().indentation += 1;
@@ -485,31 +485,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             self.memory.set_cur_frame(cur_frame);
         }
         match frame.return_to_block {
-            StackPopCleanup::MarkStatic(mutable) => if let Lvalue::Global(id) = frame.return_lvalue {
-                let global_value = self.globals.get_mut(&id)
-                    .expect("global should have been cached (static)");
-                match global_value.value {
-                    // FIXME: to_ptr()? might be too extreme here, static zsts might reach this under certain conditions
-                    Value::ByRef { ptr, aligned: _aligned } =>
-                        // Alignment does not matter for this call
-                        self.memory.mark_static_initalized(ptr.to_ptr()?.alloc_id, mutable)?,
-                    Value::ByVal(val) => if let PrimVal::Ptr(ptr) = val {
-                        self.memory.mark_inner_allocation(ptr.alloc_id, mutable)?;
-                    },
-                    Value::ByValPair(val1, val2) => {
-                        if let PrimVal::Ptr(ptr) = val1 {
-                            self.memory.mark_inner_allocation(ptr.alloc_id, mutable)?;
-                        }
-                        if let PrimVal::Ptr(ptr) = val2 {
-                            self.memory.mark_inner_allocation(ptr.alloc_id, mutable)?;
-                        }
-                    },
-                }
-                // see comment on `initialized` field
-                assert!(!global_value.initialized);
-                global_value.initialized = true;
-                assert_eq!(global_value.mutable, Mutability::Mutable);
-                global_value.mutable = mutable;
+            StackPopCleanup::MarkStatic(mutable) => if let Lvalue::Ptr{ ptr, .. } = frame.return_lvalue {
+                // FIXME: to_ptr()? might be too extreme here, static zsts might reach this under certain conditions
+                self.memory.mark_static_initalized(ptr.to_ptr()?.alloc_id, mutable)?
             } else {
                 bug!("StackPopCleanup::MarkStatic on: {:?}", frame.return_lvalue);
             },
@@ -543,7 +521,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
 
     pub fn assign_discr_and_fields(
         &mut self,
-        dest: Lvalue<'tcx>,
+        dest: Lvalue,
         dest_ty: Ty<'tcx>,
         discr_offset: u64,
         operands: &[mir::Operand<'tcx>],
@@ -568,7 +546,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
 
     pub fn assign_fields(
         &mut self,
-        dest: Lvalue<'tcx>,
+        dest: Lvalue,
         dest_ty: Ty<'tcx>,
         operands: &[mir::Operand<'tcx>],
     ) -> EvalResult<'tcx> {
@@ -1046,7 +1024,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                     Literal::Item { def_id, substs } => {
                         let instance = self.resolve_associated_const(def_id, substs);
                         let cid = GlobalId { instance, promoted: None };
-                        self.globals.get(&cid).expect("static/const not cached").value
+                        Value::by_ref(self.globals.get(&cid).expect("static/const not cached").into())
                     }
 
                     Literal::Promoted { index } => {
@@ -1054,7 +1032,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                             instance: self.frame().instance,
                             promoted: Some(index),
                         };
-                        self.globals.get(&cid).expect("promoted not cached").value
+                        Value::by_ref(self.globals.get(&cid).expect("promoted not cached").into())
                     }
                 };
 
@@ -1076,8 +1054,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
 
     pub fn force_allocation(
         &mut self,
-        lvalue: Lvalue<'tcx>,
-    ) -> EvalResult<'tcx, Lvalue<'tcx>> {
+        lvalue: Lvalue,
+    ) -> EvalResult<'tcx, Lvalue> {
         let new_lvalue = match lvalue {
             Lvalue::Local { frame, local } => {
                 // -1 since we don't store the return value
@@ -1098,28 +1076,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                 }
             }
             Lvalue::Ptr { .. } => lvalue,
-            Lvalue::Global(cid) => {
-                let global_val = self.globals.get(&cid).expect("global not cached").clone();
-                match global_val.value {
-                    Value::ByRef { ptr, aligned } =>
-                        Lvalue::Ptr { ptr, aligned, extra: LvalueExtra::None },
-                    _ => {
-                        let ptr = self.alloc_ptr_with_substs(global_val.ty, cid.instance.substs)?;
-                        self.memory.mark_static(ptr.alloc_id);
-                        self.write_value_to_ptr(global_val.value, ptr.into(), global_val.ty)?;
-                        // see comment on `initialized` field
-                        if global_val.initialized {
-                            self.memory.mark_static_initalized(ptr.alloc_id, global_val.mutable)?;
-                        }
-                        let lval = self.globals.get_mut(&cid).expect("already checked");
-                        *lval = Global {
-                            value: Value::by_ref(ptr.into()),
-                            .. global_val
-                        };
-                        Lvalue::from_ptr(ptr)
-                    },
-                }
-            }
         };
         Ok(new_lvalue)
     }
@@ -1149,7 +1105,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
 
     pub fn write_null(
         &mut self,
-        dest: Lvalue<'tcx>,
+        dest: Lvalue,
         dest_ty: Ty<'tcx>,
     ) -> EvalResult<'tcx> {
         self.write_primval(dest, PrimVal::Bytes(0), dest_ty)
@@ -1157,7 +1113,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
 
     pub fn write_ptr(
         &mut self,
-        dest: Lvalue<'tcx>,
+        dest: Lvalue,
         val: Pointer,
         dest_ty: Ty<'tcx>,
     ) -> EvalResult<'tcx> {
@@ -1166,7 +1122,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
 
     pub fn write_primval(
         &mut self,
-        dest: Lvalue<'tcx>,
+        dest: Lvalue,
         val: PrimVal,
         dest_ty: Ty<'tcx>,
     ) -> EvalResult<'tcx> {
@@ -1176,7 +1132,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
     pub fn write_value(
         &mut self,
         src_val: Value,
-        dest: Lvalue<'tcx>,
+        dest: Lvalue,
         dest_ty: Ty<'tcx>,
     ) -> EvalResult<'tcx> {
         //trace!("Writing {:?} to {:?} at type {:?}", src_val, dest, dest_ty);
@@ -1185,21 +1141,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         // correct if we never look at this data with the wrong type.
 
         match dest {
-            Lvalue::Global(cid) => {
-                let dest = self.globals.get_mut(&cid).expect("global should be cached").clone();
-                if dest.mutable == Mutability::Immutable {
-                    return err!(ModifiedConstantMemory);
-                }
-                let write_dest = |this: &mut Self, val| {
-                    *this.globals.get_mut(&cid).expect("already checked") = Global {
-                        value: val,
-                        ..dest
-                    };
-                    Ok(())
-                };
-                self.write_value_possibly_by_val(src_val, write_dest, dest.value, dest_ty)
-            },
-
             Lvalue::Ptr { ptr, extra, aligned } => {
                 assert_eq!(extra, LvalueExtra::None);
                 self.write_maybe_aligned_mut(aligned,
@@ -1542,7 +1483,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         &mut self,
         src: Value,
         src_ty: Ty<'tcx>,
-        dest: Lvalue<'tcx>,
+        dest: Lvalue,
         dest_ty: Ty<'tcx>,
         sty: Ty<'tcx>,
         dty: Ty<'tcx>,
@@ -1578,7 +1519,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         &mut self,
         src: Value,
         src_ty: Ty<'tcx>,
-        dest: Lvalue<'tcx>,
+        dest: Lvalue,
         dest_ty: Ty<'tcx>,
     ) -> EvalResult<'tcx> {
         match (&src_ty.sty, &dest_ty.sty) {
@@ -1640,7 +1581,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         }
     }
 
-    pub fn dump_local(&self, lvalue: Lvalue<'tcx>) {
+    pub fn dump_local(&self, lvalue: Lvalue) {
         // Debug output
         if let Lvalue::Local { frame, local } = lvalue {
             let mut allocs = Vec::new();
@@ -1680,20 +1621,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         }
     }
 
-    /// Convenience function to ensure correct usage of globals and code-sharing with locals.
-    pub fn modify_global<F>(&mut self, cid: GlobalId<'tcx>, f: F) -> EvalResult<'tcx>
-        where F: FnOnce(&mut Self, Value) -> EvalResult<'tcx, Value>,
-    {
-        let mut val = self.globals.get(&cid).expect("global not cached").clone();
-        if val.mutable == Mutability::Immutable {
-            return err!(ModifiedConstantMemory);
-        }
-        val.value = f(self, val.value)?;
-        *self.globals.get_mut(&cid).expect("already checked") = val;
-        Ok(())
-    }
-
-    /// Convenience function to ensure correct usage of locals and code-sharing with globals.
+    /// Convenience function to ensure correct usage of locals
     pub fn modify_local<F>(
         &mut self,
         frame: usize,
diff --git a/src/librustc_mir/interpret/lvalue.rs b/src/librustc_mir/interpret/lvalue.rs
index 8722c96dbec..4485e936b1e 100644
--- a/src/librustc_mir/interpret/lvalue.rs
+++ b/src/librustc_mir/interpret/lvalue.rs
@@ -2,7 +2,6 @@ use rustc::mir;
 use rustc::ty::layout::{Size, Align};
 use rustc::ty::{self, Ty};
 use rustc_data_structures::indexed_vec::Idx;
-use syntax::ast::Mutability;
 
 use super::{
     EvalResult,
@@ -13,7 +12,7 @@ use super::{
 };
 
 #[derive(Copy, Clone, Debug)]
-pub enum Lvalue<'tcx> {
+pub enum Lvalue {
     /// An lvalue referring to a value allocated in the `Memory` system.
     Ptr {
         /// An lvalue may have an invalid (integral or undef) pointer,
@@ -31,9 +30,6 @@ pub enum Lvalue<'tcx> {
         frame: usize,
         local: mir::Local,
     },
-
-    /// An lvalue referring to a global
-    Global(GlobalId<'tcx>),
 }
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
@@ -55,19 +51,7 @@ pub struct GlobalId<'tcx> {
     pub promoted: Option<mir::Promoted>,
 }
 
-#[derive(Clone, Debug)]
-pub struct Global<'tcx> {
-    pub value: Value,
-    /// Only used in `force_allocation` to ensure we don't mark the memory
-    /// before the static is initialized. It is possible to convert a
-    /// global which initially is `Value::ByVal(PrimVal::Undef)` and gets
-    /// lifted to an allocation before the static is fully initialized
-    pub(super) initialized: bool,
-    pub(super) mutable: Mutability,
-    pub(super) ty: Ty<'tcx>,
-}
-
-impl<'tcx> Lvalue<'tcx> {
+impl<'tcx> Lvalue {
     /// Produces an Lvalue that will error if attempted to be read from
     pub fn undef() -> Self {
         Self::from_primval_ptr(PrimVal::Undef.into())
@@ -113,26 +97,6 @@ impl<'tcx> Lvalue<'tcx> {
     }
 }
 
-impl<'tcx> Global<'tcx> {
-    pub(super) fn uninitialized(ty: Ty<'tcx>) -> Self {
-        Global {
-            value: Value::ByVal(PrimVal::Undef),
-            mutable: Mutability::Mutable,
-            ty,
-            initialized: false,
-        }
-    }
-
-    pub(super) fn initialized(ty: Ty<'tcx>, value: Value, mutable: Mutability) -> Self {
-        Global {
-            value,
-            mutable,
-            ty,
-            initialized: true,
-        }
-    }
-}
-
 impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
     /// Reads a value from the lvalue without going through the intermediate step of obtaining
     /// a `miri::Lvalue`
@@ -147,7 +111,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             Static(ref static_) => {
                 let instance = ty::Instance::mono(self.tcx, static_.def_id);
                 let cid = GlobalId { instance, promoted: None };
-                Ok(Some(self.globals.get(&cid).expect("global not cached").value))
+                Ok(Some(Value::by_ref(self.globals.get(&cid).expect("global not cached").into())))
             },
             Projection(ref proj) => self.try_read_lvalue_projection(proj),
         }
@@ -195,7 +159,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         self.read_lvalue(lvalue)
     }
 
-    pub fn read_lvalue(&self, lvalue: Lvalue<'tcx>) -> EvalResult<'tcx, Value> {
+    pub fn read_lvalue(&self, lvalue: Lvalue) -> EvalResult<'tcx, Value> {
         match lvalue {
             Lvalue::Ptr { ptr, extra, aligned } => {
                 assert_eq!(extra, LvalueExtra::None);
@@ -204,13 +168,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             Lvalue::Local { frame, local } => {
                 self.stack[frame].get_local(local)
             }
-            Lvalue::Global(cid) => {
-                Ok(self.globals.get(&cid).expect("global not cached").value)
-            }
         }
     }
 
-    pub fn eval_lvalue(&mut self, mir_lvalue: &mir::Lvalue<'tcx>) -> EvalResult<'tcx, Lvalue<'tcx>> {
+    pub fn eval_lvalue(&mut self, mir_lvalue: &mir::Lvalue<'tcx>) -> EvalResult<'tcx, Lvalue> {
         use rustc::mir::Lvalue::*;
         let lvalue = match *mir_lvalue {
             Local(mir::RETURN_POINTER) => self.frame().return_lvalue,
@@ -218,7 +179,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
 
             Static(ref static_) => {
                 let instance = ty::Instance::mono(self.tcx, static_.def_id);
-                Lvalue::Global(GlobalId { instance, promoted: None })
+                let gid = GlobalId { instance, promoted: None };
+                Lvalue::from_ptr(*self.globals.get(&gid).expect("uncached global"))
             }
 
             Projection(ref proj) => {
@@ -237,11 +199,11 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
 
     pub fn lvalue_field(
         &mut self,
-        base: Lvalue<'tcx>,
+        base: Lvalue,
         field_index: usize,
         base_ty: Ty<'tcx>,
         field_ty: Ty<'tcx>,
-    ) -> EvalResult<'tcx, Lvalue<'tcx>> {
+    ) -> EvalResult<'tcx, Lvalue> {
         let base_layout = self.type_layout(base_ty)?;
         use rustc::ty::layout::Layout::*;
         let (offset, packed) = match *base_layout {
@@ -312,16 +274,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                 Value::ByValPair(..) |
                 Value::ByVal(_) => self.force_allocation(base)?.to_ptr_extra_aligned(),
             },
-            Lvalue::Global(cid) => match self.globals.get(&cid).expect("uncached global").value {
-                // in case the type has a single field, just return the value
-                Value::ByVal(_) if self.get_field_count(base_ty).map(|c| c == 1).unwrap_or(false) => {
-                    assert_eq!(offset.bytes(), 0, "ByVal can only have 1 non zst field with offset 0");
-                    return Ok(base);
-                },
-                Value::ByRef{..} |
-                Value::ByValPair(..) |
-                Value::ByVal(_) => self.force_allocation(base)?.to_ptr_extra_aligned(),
-            },
         };
 
         let offset = match base_extra {
@@ -352,7 +304,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         Ok(Lvalue::Ptr { ptr, extra, aligned: aligned && !packed })
     }
 
-    pub(super) fn val_to_lvalue(&self, val: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, Lvalue<'tcx>> {
+    pub(super) fn val_to_lvalue(&self, val: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, Lvalue> {
         Ok(match self.tcx.struct_tail(ty).sty {
             ty::TyDynamic(..) => {
                 let (ptr, vtable) = val.into_ptr_vtable_pair(&self.memory)?;
@@ -366,7 +318,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         })
     }
 
-    pub(super) fn lvalue_index(&mut self, base: Lvalue<'tcx>, outer_ty: Ty<'tcx>, n: u64) -> EvalResult<'tcx, Lvalue<'tcx>> {
+    pub(super) fn lvalue_index(&mut self, base: Lvalue, outer_ty: Ty<'tcx>, n: u64) -> EvalResult<'tcx, Lvalue> {
         // Taking the outer type here may seem odd; it's needed because for array types, the outer type gives away the length.
         let base = self.force_allocation(base)?;
         let (base_ptr, _, aligned) = base.to_ptr_extra_aligned();
@@ -380,10 +332,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
 
     pub(super) fn eval_lvalue_projection(
         &mut self,
-        base: Lvalue<'tcx>,
+        base: Lvalue,
         base_ty: Ty<'tcx>,
         proj_elem: &mir::ProjectionElem<'tcx, mir::Operand<'tcx>, Ty<'tcx>>,
-    ) -> EvalResult<'tcx, Lvalue<'tcx>> {
+    ) -> EvalResult<'tcx, Lvalue> {
         use rustc::mir::ProjectionElem::*;
         let (ptr, extra, aligned) = match *proj_elem {
             Field(field, field_ty) => {
diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs
index 0150a6c836d..c65c3f2e103 100644
--- a/src/librustc_mir/interpret/machine.rs
+++ b/src/librustc_mir/interpret/machine.rs
@@ -33,7 +33,7 @@ pub trait Machine<'tcx>: Sized {
     fn eval_fn_call<'a>(
         ecx: &mut EvalContext<'a, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
-        destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
+        destination: Option<(Lvalue, mir::BasicBlock)>,
         arg_operands: &[mir::Operand<'tcx>],
         span: Span,
         sig: ty::FnSig<'tcx>,
@@ -44,7 +44,7 @@ pub trait Machine<'tcx>: Sized {
         ecx: &mut EvalContext<'a, 'tcx, Self>,
         instance: ty::Instance<'tcx>,
         args: &[mir::Operand<'tcx>],
-        dest: Lvalue<'tcx>,
+        dest: Lvalue,
         dest_ty: ty::Ty<'tcx>,
         dest_layout: &'tcx ty::layout::Layout,
         target: mir::BasicBlock,
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index c476046d385..1ea814d5714 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -234,12 +234,6 @@ pub struct Memory<'a, 'tcx, M: Machine<'tcx>> {
     /// The AllocId to assign to the next new regular allocation. Always incremented, never gets smaller.
     next_alloc_id: u64,
 
-    /// Set of statics, constants, promoteds, vtables, ... to prevent `mark_static_initalized` from
-    /// stepping out of its own allocations. This set only contains statics backed by an
-    /// allocation. If they are ByVal or ByValPair they are not here, but will be inserted once
-    /// they become ByRef.
-    static_alloc: HashSet<AllocId>,
-
     /// Number of virtual bytes allocated.
     memory_usage: u64,
 
@@ -280,7 +274,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
             layout,
             memory_size: max_memory,
             memory_usage: 0,
-            static_alloc: HashSet::new(),
             literal_alloc_cache: HashMap::new(),
             reads_are_aligned: Cell::new(true),
             writes_are_aligned: Cell::new(true),
@@ -859,18 +852,11 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
 
 /// Reading and writing
 impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
-    /// mark an allocation as being the entry point to a static (see `static_alloc` field)
-    pub fn mark_static(&mut self, alloc_id: AllocId) {
-        trace!("mark_static: {:?}", alloc_id);
-        if !self.static_alloc.insert(alloc_id) {
-            bug!("tried to mark an allocation ({:?}) as static twice", alloc_id);
-        }
-    }
 
     /// mark an allocation pointed to by a static as static and initialized
     pub fn mark_inner_allocation(&mut self, alloc: AllocId, mutability: Mutability) -> EvalResult<'tcx> {
         // relocations into other statics are not "inner allocations"
-        if !self.static_alloc.contains(&alloc) {
+        if self.get(alloc).ok().map_or(false, |alloc| alloc.kind != Kind::UninitializedStatic) {
             self.mark_static_initalized(alloc, mutability)?;
         }
         Ok(())
diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs
index 39a0c7d25f9..b2e5f134d34 100644
--- a/src/librustc_mir/interpret/mod.rs
+++ b/src/librustc_mir/interpret/mod.rs
@@ -38,7 +38,6 @@ pub use self::eval_context::{
 pub use self::lvalue::{
     Lvalue,
     LvalueExtra,
-    Global,
     GlobalId,
 };
 
diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs
index a9675d148d6..8880be6e848 100644
--- a/src/librustc_mir/interpret/operator.rs
+++ b/src/librustc_mir/interpret/operator.rs
@@ -39,7 +39,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         op: mir::BinOp,
         left: &mir::Operand<'tcx>,
         right: &mir::Operand<'tcx>,
-        dest: Lvalue<'tcx>,
+        dest: Lvalue,
         dest_ty: Ty<'tcx>,
     ) -> EvalResult<'tcx> {
         let (val, overflowed) = self.binop_with_overflow(op, left, right)?;
@@ -54,7 +54,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         op: mir::BinOp,
         left: &mir::Operand<'tcx>,
         right: &mir::Operand<'tcx>,
-        dest: Lvalue<'tcx>,
+        dest: Lvalue,
         dest_ty: Ty<'tcx>,
     ) -> EvalResult<'tcx, bool> {
         let (val, overflowed) = self.binop_with_overflow(op, left, right)?;
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index 56195998b9e..ca3c8490e7a 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -14,9 +14,8 @@ use rustc::ty::subst::Substs;
 use super::{
     EvalResult,
     EvalContext, StackPopCleanup, TyAndPacked,
-    Global, GlobalId, Lvalue,
-    Value, PrimVal,
-    HasMemory,
+    GlobalId, Lvalue,
+    HasMemory, Kind,
     Machine,
 };
 
@@ -179,11 +178,18 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         if self.tcx.has_attr(def_id, "linkage") {
             // FIXME: check that it's `#[linkage = "extern_weak"]`
             trace!("Initializing an extern global with NULL");
-            self.globals.insert(cid, Global::initialized(self.tcx.type_of(def_id), Value::ByVal(PrimVal::Bytes(0)), mutability));
+            let ptr_size = self.memory.pointer_size();
+            let ptr = self.memory.allocate(ptr_size, ptr_size, Kind::UninitializedStatic)?;
+            self.memory.write_usize(ptr, 0)?;
+            self.memory.mark_static_initalized(ptr.alloc_id, mutability)?;
+            self.globals.insert(cid, ptr);
             return Ok(false);
         }
         let mir = self.load_mir(instance.def)?;
-        self.globals.insert(cid, Global::uninitialized(mir.return_ty));
+        let size = self.type_size_with_substs(mir.return_ty, substs)?.expect("unsized global");
+        let align = self.type_align_with_substs(mir.return_ty, substs)?;
+        let ptr = self.memory.allocate(size, align, Kind::UninitializedStatic)?;
+        self.globals.insert(cid, ptr);
         let internally_mutable = !mir.return_ty.is_freeze(
                 self.tcx,
                 ty::ParamEnv::empty(Reveal::All),
@@ -200,7 +206,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             instance,
             span,
             mir,
-            Lvalue::Global(cid),
+            Lvalue::from_ptr(ptr),
             cleanup,
         )?;
         Ok(true)
@@ -256,13 +262,15 @@ impl<'a, 'b, 'tcx, M: Machine<'tcx>> Visitor<'tcx> for ConstantExtractor<'a, 'b,
                 }
                 let mir = &self.mir.promoted[index];
                 self.try(|this| {
-                    let ty = this.ecx.monomorphize(mir.return_ty, this.instance.substs);
-                    this.ecx.globals.insert(cid, Global::uninitialized(ty));
+                    let size = this.ecx.type_size_with_substs(mir.return_ty, this.instance.substs)?.expect("unsized global");
+                    let align = this.ecx.type_align_with_substs(mir.return_ty, this.instance.substs)?;
+                    let ptr = this.ecx.memory.allocate(size, align, Kind::UninitializedStatic)?;
+                    this.ecx.globals.insert(cid, ptr);
                     trace!("pushing stack frame for {:?}", index);
                     this.ecx.push_stack_frame(this.instance,
                                               constant.span,
                                               mir,
-                                              Lvalue::Global(cid),
+                                              Lvalue::from_ptr(ptr),
                                               StackPopCleanup::MarkStatic(Mutability::Immutable),
                     )?;
                     Ok(true)
diff --git a/src/librustc_mir/interpret/terminator/drop.rs b/src/librustc_mir/interpret/terminator/drop.rs
index 5f4bc0b1bd9..527d5917b66 100644
--- a/src/librustc_mir/interpret/terminator/drop.rs
+++ b/src/librustc_mir/interpret/terminator/drop.rs
@@ -11,7 +11,7 @@ use interpret::{
 };
 
 impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
-    pub(crate) fn drop_lvalue(&mut self, lval: Lvalue<'tcx>, instance: ty::Instance<'tcx>, ty: Ty<'tcx>, span: Span) -> EvalResult<'tcx> {
+    pub(crate) fn drop_lvalue(&mut self, lval: Lvalue, instance: ty::Instance<'tcx>, ty: Ty<'tcx>, span: Span) -> EvalResult<'tcx> {
         trace!("drop_lvalue: {:#?}", lval);
         // We take the address of the object.  This may well be unaligned, which is fine for us here.
         // However, unaligned accesses will probably make the actual drop implementation fail -- a problem shared
diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs
index b9447a30ab1..a6412dedd3b 100644
--- a/src/librustc_mir/interpret/terminator/mod.rs
+++ b/src/librustc_mir/interpret/terminator/mod.rs
@@ -204,7 +204,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
     fn eval_fn_call(
         &mut self,
         instance: ty::Instance<'tcx>,
-        destination: Option<(Lvalue<'tcx>, mir::BasicBlock)>,
+        destination: Option<(Lvalue, mir::BasicBlock)>,
         arg_operands: &[mir::Operand<'tcx>],
         span: Span,
         sig: ty::FnSig<'tcx>,
diff --git a/src/librustc_mir/interpret/validation.rs b/src/librustc_mir/interpret/validation.rs
index 83931535e59..459309abda7 100644
--- a/src/librustc_mir/interpret/validation.rs
+++ b/src/librustc_mir/interpret/validation.rs
@@ -16,7 +16,7 @@ use super::{
     Machine,
 };
 
-pub type ValidationQuery<'tcx> = ValidationOperand<'tcx, Lvalue<'tcx>>;
+pub type ValidationQuery<'tcx> = ValidationOperand<'tcx, Lvalue>;
 
 #[derive(Copy, Clone, Debug)]
 enum ValidationMode {
@@ -242,8 +242,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                         }
                     }
                 }
-                Lvalue::Local { .. } | Lvalue::Global(..) => {
-                    // These are not backed by memory, so we have nothing to do.
+                Lvalue::Local { .. }  => {
+                    // Not backed by memory, so we have nothing to do.
                 }
             }
         }
diff --git a/src/librustc_mir/interpret/value.rs b/src/librustc_mir/interpret/value.rs
index 88ffc57a8f0..cd1bde987fe 100644
--- a/src/librustc_mir/interpret/value.rs
+++ b/src/librustc_mir/interpret/value.rs
@@ -133,6 +133,12 @@ impl ::std::convert::From<MemoryPointer> for Pointer {
     }
 }
 
+impl<'a> ::std::convert::From<&'a MemoryPointer> for Pointer {
+    fn from(ptr: &'a MemoryPointer) -> Self {
+        PrimVal::Ptr(*ptr).into()
+    }
+}
+
 /// A `PrimVal` represents an immediate, primitive value existing outside of a
 /// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
 /// size. Like a range of bytes in an `Allocation`, a `PrimVal` can either represent the raw bytes