about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOliver Schneider <oli-obk@users.noreply.github.com>2017-08-09 16:06:14 +0200
committerGitHub <noreply@github.com>2017-08-09 16:06:14 +0200
commita6096fbfba1042d1f4ad3b7c7144692d1286f71a (patch)
treed61a90ad0e464e24ef68d3da20df486ffb3ea9d6
parent14e8f500af85da93e342dced154a0581ee9237ed (diff)
parent91db25bdef31781d9ef6878c5c5176975430c703 (diff)
downloadrust-a6096fbfba1042d1f4ad3b7c7144692d1286f71a.tar.gz
rust-a6096fbfba1042d1f4ad3b7c7144692d1286f71a.zip
Merge pull request #292 from oli-obk/static_alloc_ids
Prepare for splitting off static alloc ids from local alloc ids
-rw-r--r--miri/fn_call.rs39
-rw-r--r--miri/intrinsic.rs20
-rw-r--r--miri/lib.rs16
-rw-r--r--miri/memory.rs8
-rw-r--r--src/librustc_mir/interpret/const_eval.rs21
-rw-r--r--src/librustc_mir/interpret/error.rs2
-rw-r--r--src/librustc_mir/interpret/eval_context.rs299
-rw-r--r--src/librustc_mir/interpret/lvalue.rs138
-rw-r--r--src/librustc_mir/interpret/machine.rs4
-rw-r--r--src/librustc_mir/interpret/memory.rs194
-rw-r--r--src/librustc_mir/interpret/mod.rs4
-rw-r--r--src/librustc_mir/interpret/operator.rs4
-rw-r--r--src/librustc_mir/interpret/step.rs30
-rw-r--r--src/librustc_mir/interpret/terminator/drop.rs8
-rw-r--r--src/librustc_mir/interpret/terminator/mod.rs8
-rw-r--r--src/librustc_mir/interpret/traits.rs4
-rw-r--r--src/librustc_mir/interpret/validation.rs8
-rw-r--r--src/librustc_mir/interpret/value.rs11
-rw-r--r--tests/compile-fail/fn_ptr_offset.rs2
-rw-r--r--tests/run-pass/packed_static.rs10
20 files changed, 413 insertions, 417 deletions
diff --git a/miri/fn_call.rs b/miri/fn_call.rs
index 81db48fe129..26263a854dd 100644
--- a/miri/fn_call.rs
+++ b/miri/fn_call.rs
@@ -16,14 +16,14 @@ use super::{
 
 use tls::MemoryExt;
 
-use super::memory::Kind;
+use super::memory::MemoryKind;
 
 pub trait EvalContextExt<'tcx> {
     fn call_c_abi(
         &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> {
@@ -113,7 +113,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.into())?;
+                    let ptr = self.memory.allocate(size, align, MemoryKind::C.into())?;
                     self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
                 }
             }
@@ -121,7 +121,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.into())?;
+                    self.memory.deallocate(ptr.to_ptr()?, None, MemoryKind::C.into())?;
                 }
             }
 
@@ -251,7 +251,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.into())?;
+                        self.memory.deallocate(var, None, MemoryKind::Env.into())?;
                     }
                     self.write_null(dest, dest_ty)?;
                 } else {
@@ -274,12 +274,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.into())?;
+                    let value_copy = self.memory.allocate((value.len() + 1) as u64, 1, MemoryKind::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.into())?;
+                        self.memory.deallocate(var, None, MemoryKind::Env.into())?;
                     }
                     self.write_null(dest, dest_ty)?;
                 } else {
@@ -317,7 +317,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
             }
 
             "sysconf" => {
-                let name = self.value_to_primval(args[0], usize)?.to_u64()?;
+                let c_int = self.operand_ty(&arg_operands[0]);
+                let name = self.value_to_primval(args[0], c_int)?.to_u64()?;
                 trace!("sysconf() called with name {}", name);
                 // cache the sysconf integers via miri's global cache
                 let paths = &[
@@ -329,8 +330,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).cloned() {
+                            Some(ptr) => self.value_to_primval(Value::ByRef(ptr), c_int)?.to_u64()?,
                             None => eval_body_as_primval(self.tcx, instance)?.0.to_u64()?,
                         };
                         if val == name {
@@ -459,7 +460,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,
@@ -500,7 +501,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
                 if !align.is_power_of_two() {
                     return err!(HeapAllocNonPowerOfTwoAlignment(align));
                 }
-                let ptr = self.memory.allocate(size, align, Kind::Rust.into())?;
+                let ptr = self.memory.allocate(size, align, MemoryKind::Rust.into())?;
                 self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
             }
             "alloc::heap::::__rust_alloc_zeroed" => {
@@ -512,7 +513,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
                 if !align.is_power_of_two() {
                     return err!(HeapAllocNonPowerOfTwoAlignment(align));
                 }
-                let ptr = self.memory.allocate(size, align, Kind::Rust.into())?;
+                let ptr = self.memory.allocate(size, align, MemoryKind::Rust.into())?;
                 self.memory.write_repeat(ptr.into(), 0, size)?;
                 self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
             }
@@ -526,7 +527,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
                 if !align.is_power_of_two() {
                     return err!(HeapAllocNonPowerOfTwoAlignment(align));
                 }
-                self.memory.deallocate(ptr, Some((old_size, align)), Kind::Rust.into())?;
+                self.memory.deallocate(ptr, Some((old_size, align)), MemoryKind::Rust.into())?;
             }
             "alloc::heap::::__rust_realloc" => {
                 let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
@@ -543,7 +544,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
                 if !new_align.is_power_of_two() {
                     return err!(HeapAllocNonPowerOfTwoAlignment(new_align));
                 }
-                let new_ptr = self.memory.reallocate(ptr, old_size, old_align, new_size, new_align, Kind::Rust.into())?;
+                let new_ptr = self.memory.reallocate(ptr, old_size, old_align, new_size, new_align, MemoryKind::Rust.into())?;
                 self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?;
             }
 
diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs
index 4cdad350b43..5a609a569bb 100644
--- a/miri/intrinsic.rs
+++ b/miri/intrinsic.rs
@@ -8,7 +8,7 @@ use rustc_miri::interpret::{
     Lvalue, LvalueExtra,
     PrimVal, PrimValKind, Value, Pointer,
     HasMemory,
-    EvalContext,
+    EvalContext, PtrAndAlign,
 };
 
 use helpers::EvalContextExt as HelperEvalContextExt;
@@ -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,
@@ -266,10 +266,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
                 let size = self.type_size(dest_ty)?.expect("cannot zero unsized value");
                 let init = |this: &mut Self, val: Value| {
                     let zero_val = match val {
-                        Value::ByRef { ptr, aligned } => {
+                        Value::ByRef(PtrAndAlign { ptr, .. }) => {
                             // These writes have no alignment restriction anyway.
                             this.memory.write_repeat(ptr, 0, size)?;
-                            Value::ByRef { ptr, aligned }
+                            val
                         },
                         // TODO(solson): Revisit this, it's fishy to check for Undef here.
                         Value::ByVal(PrimVal::Undef) => match this.ty_to_primval_kind(dest_ty) {
@@ -289,9 +289,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
                 };
                 match dest {
                     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 { ptr: PtrAndAlign { ptr, aligned: true }, extra: LvalueExtra::None } => 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)?,
                 }
             }
 
@@ -457,19 +456,18 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator>
                 let size = dest_layout.size(&self.tcx.data_layout).bytes();
                 let uninit = |this: &mut Self, val: Value| {
                     match val {
-                        Value::ByRef { ptr, aligned } => {
+                        Value::ByRef(PtrAndAlign { ptr, .. }) => {
                             this.memory.mark_definedness(ptr, size, false)?;
-                            Ok(Value::ByRef { ptr, aligned })
+                            Ok(val)
                         },
                         _ => Ok(Value::ByVal(PrimVal::Undef)),
                     }
                 };
                 match dest {
                     Lvalue::Local { frame, local } => self.modify_local(frame, local, uninit)?,
-                    Lvalue::Ptr { ptr, extra: LvalueExtra::None, aligned: true } =>
+                    Lvalue::Ptr { ptr: PtrAndAlign { ptr, aligned: true }, extra: LvalueExtra::None } =>
                         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..c93b938e9bd 100644
--- a/miri/lib.rs
+++ b/miri/lib.rs
@@ -71,7 +71,7 @@ pub fn eval_main<'a, 'tcx: 'a>(
             // Return value
             let size = ecx.tcx.data_layout.pointer_size.bytes();
             let align = ecx.tcx.data_layout.pointer_align.abi();
-            let ret_ptr = ecx.memory_mut().allocate(size, align, Kind::Stack)?;
+            let ret_ptr = ecx.memory_mut().allocate(size, align, MemoryKind::Stack)?;
             cleanup_ptr = Some(ret_ptr);
 
             // Push our stack frame
@@ -114,7 +114,7 @@ pub fn eval_main<'a, 'tcx: 'a>(
         while ecx.step()? {}
         ecx.run_tls_dtors()?;
         if let Some(cleanup_ptr) = cleanup_ptr {
-            ecx.memory_mut().deallocate(cleanup_ptr, None, Kind::Stack)?;
+            ecx.memory_mut().deallocate(cleanup_ptr, None, MemoryKind::Stack)?;
         }
         Ok(())
     }
@@ -161,13 +161,13 @@ struct MemoryData<'tcx> {
 impl<'tcx> Machine<'tcx> for Evaluator {
     type Data = EvaluatorData;
     type MemoryData = MemoryData<'tcx>;
-    type MemoryKinds = memory::Kind;
+    type MemoryKinds = memory::MemoryKind;
 
     /// Returns Ok() when the function was handled, fail otherwise
     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,
@@ -198,8 +198,8 @@ impl<'tcx> Machine<'tcx> for Evaluator {
         ecx.ptr_op(bin_op, left, left_ty, right, right_ty)
     }
 
-    fn mark_static_initialized(m: memory::Kind) -> EvalResult<'tcx> {
-        use memory::Kind::*;
+    fn mark_static_initialized(m: memory::MemoryKind) -> EvalResult<'tcx> {
+        use memory::MemoryKind::*;
         match m {
             // FIXME: This could be allowed, but not for env vars set during miri execution
             Env => err!(Unimplemented("statics can't refer to env vars".to_owned())),
@@ -218,7 +218,7 @@ impl<'tcx> Machine<'tcx> for Evaluator {
             Ok(PrimVal::Bytes(align.into()))
         } else {
             ecx.memory
-                .allocate(size, align, Kind::Machine(memory::Kind::Rust))
+                .allocate(size, align, MemoryKind::Machine(memory::MemoryKind::Rust))
                 .map(PrimVal::Ptr)
         }
     }
diff --git a/miri/memory.rs b/miri/memory.rs
index 55e6026280c..110540c0cf1 100644
--- a/miri/memory.rs
+++ b/miri/memory.rs
@@ -1,6 +1,6 @@
 
 #[derive(Debug, PartialEq, Copy, Clone)]
-pub enum Kind {
+pub enum MemoryKind {
     /// Error if deallocated any other way than `rust_deallocate`
     Rust,
     /// Error if deallocated any other way than `free`
@@ -9,8 +9,8 @@ pub enum Kind {
     Env,
 }
 
-impl Into<::rustc_miri::interpret::Kind<Kind>> for Kind {
-    fn into(self) -> ::rustc_miri::interpret::Kind<Kind> {
-        ::rustc_miri::interpret::Kind::Machine(self)
+impl Into<::rustc_miri::interpret::MemoryKind<MemoryKind>> for MemoryKind {
+    fn into(self) -> ::rustc_miri::interpret::MemoryKind<MemoryKind> {
+        ::rustc_miri::interpret::MemoryKind::Machine(self)
     }
 }
diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs
index 51f18bccf43..f11734a588a 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,
+    EvalContext, StackPopCleanup, PtrAndAlign,
+    MemoryKind,
 };
 
 use rustc_const_math::ConstInt;
@@ -30,7 +31,11 @@ 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, MemoryKind::UninitializedStatic)?;
+        let aligned = !ecx.is_packed(mir.return_ty)?;
+        ecx.globals.insert(cid, PtrAndAlign { ptr: ptr.into(), aligned });
         let mutable = !mir.return_ty.is_freeze(
                 ecx.tcx,
                 ty::ParamEnv::empty(Reveal::All),
@@ -42,18 +47,18 @@ pub fn eval_body_as_primval<'a, 'tcx>(
         };
         let cleanup = StackPopCleanup::MarkStatic(mutability);
         let name = ty::tls::with(|tcx| tcx.item_path_str(instance.def_id()));
-        trace!("pushing stack frame for global: {}", name);
+        trace!("const_eval: pushing stack frame for global: {}", name);
         ecx.push_stack_frame(
             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::ByRef(*ecx.globals.get(&cid).expect("global not cached"));
     Ok((ecx.value_to_primval(value, mir.return_ty)?, mir.return_ty))
 }
 
@@ -132,7 +137,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 +173,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/error.rs b/src/librustc_mir/interpret/error.rs
index 7cfff2d9810..96911c10cca 100644
--- a/src/librustc_mir/interpret/error.rs
+++ b/src/librustc_mir/interpret/error.rs
@@ -139,7 +139,7 @@ impl<'tcx> Error for EvalError<'tcx> {
             DoubleFree =>
                 "tried to deallocate dangling pointer",
             InvalidFunctionPointer =>
-                "tried to use an integer pointer or a dangling pointer as a function pointer",
+                "tried to use a function pointer after offsetting it",
             InvalidBool =>
                 "invalid boolean value read",
             InvalidDiscriminant =>
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index c5ca9712955..fd609d5fec1 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -7,7 +7,7 @@ use rustc::middle::const_val::ConstVal;
 use rustc::middle::region::CodeExtent;
 use rustc::mir;
 use rustc::traits::Reveal;
-use rustc::ty::layout::{self, Layout, Size, Align};
+use rustc::ty::layout::{self, Layout, Size, Align, HasDataLayout};
 use rustc::ty::subst::{Subst, Substs, Kind};
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Binder};
 use rustc::traits;
@@ -18,9 +18,9 @@ use syntax::abi::Abi;
 
 use super::{
     EvalError, EvalResult, EvalErrorKind,
-    Global, GlobalId, Lvalue, LvalueExtra,
+    GlobalId, Lvalue, LvalueExtra,
     Memory, MemoryPointer, HasMemory,
-    Kind as MemoryKind,
+    MemoryKind,
     operator,
     PrimVal, PrimValKind, Value, Pointer,
     ValidationQuery,
@@ -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>, PtrAndAlign>,
 
     /// 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.
@@ -143,6 +143,25 @@ pub struct TyAndPacked<'tcx> {
     pub packed: bool,
 }
 
+#[derive(Copy, Clone, Debug)]
+pub struct PtrAndAlign {
+    pub ptr: Pointer,
+    /// Remember whether this lvalue is *supposed* to be aligned.
+    pub aligned: bool,
+}
+
+impl PtrAndAlign {
+    pub fn to_ptr<'tcx>(self) -> EvalResult<'tcx, MemoryPointer> {
+        self.ptr.to_ptr()
+    }
+    pub fn offset<'tcx, C: HasDataLayout>(self, i: u64, cx: C) -> EvalResult<'tcx, Self> {
+        Ok(PtrAndAlign {
+            ptr: self.ptr.offset(i, cx)?,
+            aligned: self.aligned,
+        })
+    }
+}
+
 impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
     pub fn new(
         tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -195,20 +214,6 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         self.stack.len() - 1
     }
 
-    /// Returns true if the current frame or any parent frame is part of a ctfe.
-    ///
-    /// Used to disable features in const eval, which do not have a rfc enabling
-    /// them or which can't be written in a way that they produce the same output
-    /// that evaluating the code at runtime would produce.
-    pub fn const_env(&self) -> bool {
-        for frame in self.stack.iter().rev() {
-            if let StackPopCleanup::MarkStatic(_) = frame.return_to_block {
-                return true;
-            }
-        }
-        false
-    }
-
     pub fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> {
         let ptr = self.memory.allocate_cached(s.as_bytes())?;
         Ok(Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::from_u128(s.len() as u128)))
@@ -386,7 +391,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 +404,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 +424,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 +490,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);
             },
@@ -525,7 +508,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
     }
 
     pub fn deallocate_local(&mut self, local: Option<Value>) -> EvalResult<'tcx> {
-        if let Some(Value::ByRef { ptr, aligned: _ }) = local {
+        if let Some(Value::ByRef(ptr)) = local {
             trace!("deallocating local");
             let ptr = ptr.to_ptr()?;
             self.memory.dump_alloc(ptr.alloc_id);
@@ -543,7 +526,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>],
@@ -558,9 +541,11 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         self.memory.write_uint(discr_dest, discr_val, discr_size)?;
 
         let dest = Lvalue::Ptr {
-            ptr: dest_ptr.into(),
+            ptr: PtrAndAlign {
+                ptr: dest_ptr.into(),
+                aligned: true,
+            },
             extra: LvalueExtra::DowncastVariant(variant_idx),
-            aligned: true,
         };
 
         self.assign_fields(dest, dest_ty, operands)
@@ -568,7 +553,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> {
@@ -639,7 +624,13 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                 self.inc_step_counter_and_check_limit(operands.len() as u64)?;
                 use rustc::ty::layout::Layout::*;
                 match *dest_layout {
-                    Univariant { .. } | Array { .. } => {
+                    Univariant { ref variant, .. } => {
+                        self.write_maybe_aligned_mut(!variant.packed, |ecx| {
+                            ecx.assign_fields(dest, dest_ty, operands)
+                        })?;
+                    }
+
+                    Array { .. } => {
                         self.assign_fields(dest, dest_ty, operands)?;
                     }
 
@@ -686,10 +677,12 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                         }
                     }
 
-                    StructWrappedNullablePointer { nndiscr, ref discrfield_source, .. } => {
+                    StructWrappedNullablePointer { nndiscr, ref discrfield_source, ref nonnull, .. } => {
                         if let mir::AggregateKind::Adt(_, variant, _, _) = **kind {
                             if nndiscr == variant as u64 {
-                                self.assign_fields(dest, dest_ty, operands)?;
+                                self.write_maybe_aligned_mut(!nonnull.packed, |ecx| {
+                                    ecx.assign_fields(dest, dest_ty, operands)
+                                })?;
                             } else {
                                 for operand in operands {
                                     let operand_ty = self.operand_ty(operand);
@@ -704,7 +697,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                                 let dest = dest.offset(offset.bytes(), &self)?;
                                 let dest_size = self.type_size(ty)?
                                     .expect("bad StructWrappedNullablePointer discrfield");
-                                self.memory.write_int(dest, 0, dest_size)?;
+                                self.memory.write_maybe_aligned_mut(!nonnull.packed, |mem| {
+                                    mem.write_int(dest, 0, dest_size)
+                                })?;
                             }
                         } else {
                             bug!("tried to assign {:?} to Layout::RawNullablePointer", kind);
@@ -729,12 +724,14 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                         self.assign_fields(dest, dest_ty, operands)?;
                     }
 
-                    UntaggedUnion { .. } => {
+                    UntaggedUnion { ref variants } => {
                         assert_eq!(operands.len(), 1);
                         let operand = &operands[0];
                         let value = self.eval_operand(operand)?;
                         let value_ty = self.operand_ty(operand);
-                        self.write_value(value, dest, value_ty)?;
+                        self.write_maybe_aligned_mut(!variants.packed, |ecx| {
+                            ecx.write_value(value, dest, value_ty)
+                        })?;
                     }
 
                     _ => {
@@ -778,12 +775,12 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                 let src = self.eval_lvalue(lvalue)?;
                 // We ignore the alignment of the lvalue here -- special handling for packed structs ends
                 // at the `&` operator.
-                let (ptr, extra, _aligned) = self.force_allocation(src)?.to_ptr_extra_aligned();
+                let (ptr, extra) = self.force_allocation(src)?.to_ptr_extra_aligned();
 
                 let val = match extra {
-                    LvalueExtra::None => ptr.to_value(),
-                    LvalueExtra::Length(len) => ptr.to_value_with_len(len),
-                    LvalueExtra::Vtable(vtable) => ptr.to_value_with_vtable(vtable),
+                    LvalueExtra::None => ptr.ptr.to_value(),
+                    LvalueExtra::Length(len) => ptr.ptr.to_value_with_len(len),
+                    LvalueExtra::Vtable(vtable) => ptr.ptr.to_value_with_vtable(vtable),
                     LvalueExtra::DowncastVariant(..) =>
                         bug!("attempted to take a reference to an enum downcast lvalue"),
                 };
@@ -1046,7 +1043,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::ByRef(*self.globals.get(&cid).expect("static/const not cached"))
                     }
 
                     Literal::Promoted { index } => {
@@ -1054,7 +1051,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::ByRef(*self.globals.get(&cid).expect("promoted not cached"))
                     }
                 };
 
@@ -1063,6 +1060,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         }
     }
 
+    pub fn read_global_as_value(&self, gid: GlobalId) -> Value {
+        Value::ByRef(*self.globals.get(&gid).expect("global not cached"))
+    }
+
     pub fn operand_ty(&self, operand: &mir::Operand<'tcx>) -> Ty<'tcx> {
         self.monomorphize(operand.ty(self.mir(), self.tcx), self.substs())
     }
@@ -1074,17 +1075,32 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         Ok(())
     }
 
+    pub fn is_packed(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, bool> {
+        let layout = self.type_layout(ty)?;
+        use rustc::ty::layout::Layout::*;
+        Ok(match *layout {
+            Univariant { ref variant, .. } => variant.packed,
+
+            StructWrappedNullablePointer { ref nonnull, .. } => nonnull.packed,
+
+            UntaggedUnion { ref variants } => variants.packed,
+
+            // can only apply #[repr(packed)] to struct and union
+            _ => false,
+        })
+    }
+
     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
                 match self.stack[frame].locals[local.index() - 1] {
                     None => return err!(DeadLocal),
-                    Some(Value::ByRef { ptr, aligned }) => {
-                        Lvalue::Ptr { ptr, aligned, extra: LvalueExtra::None }
+                    Some(Value::ByRef(ptr)) => {
+                        Lvalue::Ptr { ptr, extra: LvalueExtra::None }
                     },
                     Some(val) => {
                         let ty = self.stack[frame].mir.local_decls[local].ty;
@@ -1098,28 +1114,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)
     }
@@ -1127,7 +1121,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
     /// ensures this Value is not a ByRef
     pub(super) fn follow_by_ref_value(&mut self, value: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
         match value {
-            Value::ByRef { ptr, aligned } => {
+            Value::ByRef(PtrAndAlign { ptr, aligned }) => {
                 self.read_maybe_aligned(aligned, |ectx| ectx.read_value(ptr, ty))
             }
             other => Ok(other),
@@ -1149,7 +1143,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 +1151,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 +1160,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 +1170,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,22 +1179,7 @@ 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 } => {
+            Lvalue::Ptr { ptr: PtrAndAlign { ptr, aligned }, extra } => {
                 assert_eq!(extra, LvalueExtra::None);
                 self.write_maybe_aligned_mut(aligned,
                     |ectx| ectx.write_value_to_ptr(src_val, ptr, dest_ty))
@@ -1226,7 +1205,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         old_dest_val: Value,
         dest_ty: Ty<'tcx>,
     ) -> EvalResult<'tcx> {
-        if let Value::ByRef { ptr: dest_ptr, aligned } = old_dest_val {
+        if let Value::ByRef(PtrAndAlign { ptr: dest_ptr, aligned }) = old_dest_val {
             // If the value is already `ByRef` (that is, backed by an `Allocation`),
             // then we must write the new value into this allocation, because there may be
             // other pointers into the allocation. These other pointers are logically
@@ -1237,7 +1216,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             self.write_maybe_aligned_mut(aligned,
                 |ectx| ectx.write_value_to_ptr(src_val, dest_ptr, dest_ty))?;
 
-        } else if let Value::ByRef { ptr: src_ptr, aligned } = src_val {
+        } else if let Value::ByRef(PtrAndAlign { ptr: src_ptr, aligned }) = src_val {
             // If the value is not `ByRef`, then we know there are no pointers to it
             // and we can simply overwrite the `Value` in the locals array directly.
             //
@@ -1275,7 +1254,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         dest_ty: Ty<'tcx>,
     ) -> EvalResult<'tcx> {
         match value {
-            Value::ByRef { ptr, aligned } => {
+            Value::ByRef(PtrAndAlign { ptr, aligned }) => {
                 self.read_maybe_aligned_mut(aligned, |ectx| ectx.copy(ptr, dest, dest_ty))
             },
             Value::ByVal(primval) => {
@@ -1542,7 +1521,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 +1557,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) {
@@ -1610,7 +1589,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                 //let src = adt::MaybeSizedValue::sized(src);
                 //let dst = adt::MaybeSizedValue::sized(dst);
                 let src_ptr = match src {
-                    Value::ByRef { ptr, aligned: true } => ptr,
+                    Value::ByRef(PtrAndAlign { ptr, aligned: true }) => ptr,
                     // TODO: Is it possible for unaligned pointers to occur here?
                     _ => bug!("expected aligned pointer, got {:?}", src),
                 };
@@ -1640,60 +1619,58 @@ 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();
-            let mut msg = format!("{:?}", local);
-            if frame != self.cur_frame() {
-                write!(msg, " ({} frames up)", self.cur_frame() - frame).unwrap();
-            }
-            write!(msg, ":").unwrap();
-
-            match self.stack[frame].get_local(local) {
-                Err(EvalError{ kind: EvalErrorKind::DeadLocal, ..} ) => {
-                    write!(msg, " is dead").unwrap();
+        match lvalue {
+            Lvalue::Local { frame, local } => {
+                let mut allocs = Vec::new();
+                let mut msg = format!("{:?}", local);
+                if frame != self.cur_frame() {
+                    write!(msg, " ({} frames up)", self.cur_frame() - frame).unwrap();
                 }
-                Err(err) => {
-                    panic!("Failed to access local: {:?}", err);
+                write!(msg, ":").unwrap();
+
+                match self.stack[frame].get_local(local) {
+                    Err(EvalError{ kind: EvalErrorKind::DeadLocal, ..} ) => {
+                        write!(msg, " is dead").unwrap();
+                    }
+                    Err(err) => {
+                        panic!("Failed to access local: {:?}", err);
+                    }
+                    Ok(Value::ByRef(PtrAndAlign{ ptr, aligned })) => match ptr.into_inner_primval() {
+                        PrimVal::Ptr(ptr) => {
+                            write!(msg, " by {}ref:", if aligned { "" } else { "unaligned " }).unwrap();
+                            allocs.push(ptr.alloc_id);
+                        },
+                        ptr => write!(msg, " integral by ref: {:?}", ptr).unwrap(),
+                    },
+                    Ok(Value::ByVal(val)) => {
+                        write!(msg, " {:?}", val).unwrap();
+                        if let PrimVal::Ptr(ptr) = val { allocs.push(ptr.alloc_id); }
+                    }
+                    Ok(Value::ByValPair(val1, val2)) => {
+                        write!(msg, " ({:?}, {:?})", val1, val2).unwrap();
+                        if let PrimVal::Ptr(ptr) = val1 { allocs.push(ptr.alloc_id); }
+                        if let PrimVal::Ptr(ptr) = val2 { allocs.push(ptr.alloc_id); }
+                    }
                 }
-                Ok(Value::ByRef { ptr, aligned }) => match ptr.into_inner_primval() {
+
+                trace!("{}", msg);
+                self.memory.dump_allocs(allocs);
+            }
+            Lvalue::Ptr { ptr: PtrAndAlign { ptr, aligned }, .. } => {
+                match ptr.into_inner_primval() {
                     PrimVal::Ptr(ptr) => {
-                        write!(msg, " by {}ref:", if aligned { "" } else { "unaligned " }).unwrap();
-                        allocs.push(ptr.alloc_id);
+                        trace!("by {}ref:", if aligned { "" } else { "unaligned " });
+                        self.memory.dump_alloc(ptr.alloc_id);
                     },
-                    ptr => write!(msg, " integral by ref: {:?}", ptr).unwrap(),
-                },
-                Ok(Value::ByVal(val)) => {
-                    write!(msg, " {:?}", val).unwrap();
-                    if let PrimVal::Ptr(ptr) = val { allocs.push(ptr.alloc_id); }
-                }
-                Ok(Value::ByValPair(val1, val2)) => {
-                    write!(msg, " ({:?}, {:?})", val1, val2).unwrap();
-                    if let PrimVal::Ptr(ptr) = val1 { allocs.push(ptr.alloc_id); }
-                    if let PrimVal::Ptr(ptr) = val2 { allocs.push(ptr.alloc_id); }
+                    ptr => trace!(" integral by ref: {:?}", ptr),
                 }
             }
-
-            trace!("{}", msg);
-            self.memory.dump_allocs(allocs);
         }
     }
 
-    /// 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..02af68d384f 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,
@@ -10,19 +9,18 @@ use super::{
     MemoryPointer,
     PrimVal, Value, Pointer,
     Machine,
+    PtrAndAlign,
 };
 
 #[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,
         /// since it might be turned back into a reference
         /// before ever being dereferenced.
-        ptr: Pointer,
+        ptr: PtrAndAlign,
         extra: LvalueExtra,
-        /// Remember whether this lvalue is *supposed* to be aligned.
-        aligned: bool,
     },
 
     /// An lvalue referring to a value on the stack. Represented by a stack frame index paired with
@@ -31,9 +29,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,42 +50,30 @@ 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())
     }
 
     pub fn from_primval_ptr(ptr: Pointer) -> Self {
-        Lvalue::Ptr { ptr, extra: LvalueExtra::None, aligned: true }
+        Lvalue::Ptr { ptr: PtrAndAlign { ptr, aligned: true }, extra: LvalueExtra::None }
     }
 
     pub fn from_ptr(ptr: MemoryPointer) -> Self {
         Self::from_primval_ptr(ptr.into())
     }
 
-    pub(super) fn to_ptr_extra_aligned(self) -> (Pointer, LvalueExtra, bool) {
+    pub(super) fn to_ptr_extra_aligned(self) -> (PtrAndAlign, LvalueExtra) {
         match self {
-            Lvalue::Ptr { ptr, extra, aligned } => (ptr, extra, aligned),
+            Lvalue::Ptr { ptr, extra } => (ptr, extra),
             _ => bug!("to_ptr_and_extra: expected Lvalue::Ptr, got {:?}", self),
 
         }
     }
 
     pub fn to_ptr(self) -> EvalResult<'tcx, MemoryPointer> {
-        let (ptr, extra, _aligned) = self.to_ptr_extra_aligned();
+        let (ptr, extra) = self.to_ptr_extra_aligned();
         // At this point, we forget about the alignment information -- the lvalue has been turned into a reference,
         // and no matter where it came from, it now must be aligned.
         assert_eq!(extra, LvalueExtra::None);
@@ -113,26 +96,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 +110,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::ByRef(*self.globals.get(&cid).expect("global not cached"))))
             },
             Projection(ref proj) => self.try_read_lvalue_projection(proj),
         }
@@ -195,22 +158,19 @@ 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 } => {
+            Lvalue::Ptr { ptr, extra } => {
                 assert_eq!(extra, LvalueExtra::None);
-                Ok(Value::ByRef { ptr, aligned })
+                Ok(Value::ByRef(ptr))
             }
             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 +178,11 @@ 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::Ptr {
+                    ptr: *self.globals.get(&gid).expect("uncached global"),
+                    extra: LvalueExtra::None,
+                }
             }
 
             Projection(ref proj) => {
@@ -237,11 +201,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 {
@@ -250,10 +214,11 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             },
 
             General { ref variants, .. } => {
-                let (_, base_extra, _) = base.to_ptr_extra_aligned();
+                let (_, base_extra) = base.to_ptr_extra_aligned();
                 if let LvalueExtra::DowncastVariant(variant_idx) = base_extra {
                     // +1 for the discriminant, which is field 0
-                    (variants[variant_idx].offsets[field_index + 1], variants[variant_idx].packed)
+                    assert!(!variants[variant_idx].packed);
+                    (variants[variant_idx].offsets[field_index + 1], false)
                 } else {
                     bug!("field access on enum had no variant index");
                 }
@@ -300,8 +265,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         };
 
         // Do not allocate in trivial cases
-        let (base_ptr, base_extra, aligned) = match base {
-            Lvalue::Ptr { ptr, extra, aligned } => (ptr, extra, aligned),
+        let (base_ptr, base_extra) = match base {
+            Lvalue::Ptr { ptr, extra } => (ptr, extra),
             Lvalue::Local { frame, local } => match self.stack[frame].get_local(local)? {
                 // 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) => {
@@ -312,27 +277,20 @@ 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 {
             LvalueExtra::Vtable(tab) => {
-                let (_, align) = self.size_and_align_of_dst(base_ty, base_ptr.to_value_with_vtable(tab))?;
+                let (_, align) = self.size_and_align_of_dst(base_ty, base_ptr.ptr.to_value_with_vtable(tab))?;
                 offset.abi_align(Align::from_bytes(align, align).unwrap()).bytes()
             }
             _ => offset.bytes(),
         };
 
-        let ptr = base_ptr.offset(offset, &self)?;
+        let mut ptr = base_ptr.offset(offset, &self)?;
+        // if we were unaligned, stay unaligned
+        // no matter what we were, if we are packed, we must not be aligned anymore
+        ptr.aligned &= !packed;
 
         let field_ty = self.monomorphize(field_ty, self.substs());
 
@@ -349,43 +307,43 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             base_extra
         };
 
-        Ok(Lvalue::Ptr { ptr, extra, aligned: aligned && !packed })
+        Ok(Lvalue::Ptr { ptr, extra } )
     }
 
-    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)?;
-                Lvalue::Ptr { ptr, extra: LvalueExtra::Vtable(vtable), aligned: true }
+                Lvalue::Ptr { ptr: PtrAndAlign { ptr, aligned: true }, extra: LvalueExtra::Vtable(vtable) }
             },
             ty::TyStr | ty::TySlice(_) => {
                 let (ptr, len) = val.into_slice(&self.memory)?;
-                Lvalue::Ptr { ptr, extra: LvalueExtra::Length(len), aligned: true }
+                Lvalue::Ptr { ptr: PtrAndAlign { ptr, aligned: true }, extra: LvalueExtra::Length(len) }
             },
-            _ => Lvalue::Ptr { ptr: val.into_ptr(&self.memory)?, extra: LvalueExtra::None, aligned: true },
+            _ => Lvalue::from_primval_ptr(val.into_ptr(&self.memory)?),
         })
     }
 
-    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();
+        let (base_ptr, _) = base.to_ptr_extra_aligned();
 
         let (elem_ty, len) = base.elem_ty_and_len(outer_ty);
         let elem_size = self.type_size(elem_ty)?.expect("slice element must be sized");
         assert!(n < len, "Tried to access element {} of array/slice with length {}", n, len);
         let ptr = base_ptr.offset(n * elem_size, self.memory.layout)?;
-        Ok(Lvalue::Ptr { ptr, extra: LvalueExtra::None, aligned })
+        Ok(Lvalue::Ptr { ptr, extra: LvalueExtra::None })
     }
 
     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 {
+        let (ptr, extra) = match *proj_elem {
             Field(field, field_ty) => {
                 return self.lvalue_field(base, field.index(), base_ty, field_ty);
             }
@@ -394,7 +352,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                 let base_layout = self.type_layout(base_ty)?;
                 // FIXME(solson)
                 let base = self.force_allocation(base)?;
-                let (base_ptr, base_extra, aligned) = base.to_ptr_extra_aligned();
+                let (base_ptr, base_extra) = base.to_ptr_extra_aligned();
 
                 use rustc::ty::layout::Layout::*;
                 let extra = match *base_layout {
@@ -402,7 +360,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                     RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => base_extra,
                     _ => bug!("variant downcast on non-aggregate: {:?}", base_layout),
                 };
-                (base_ptr, extra, aligned)
+                (base_ptr, extra)
             }
 
             Deref => {
@@ -431,7 +389,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
             ConstantIndex { offset, min_length, from_end } => {
                 // FIXME(solson)
                 let base = self.force_allocation(base)?;
-                let (base_ptr, _, aligned) = base.to_ptr_extra_aligned();
+                let (base_ptr, _) = base.to_ptr_extra_aligned();
 
                 let (elem_ty, n) = base.elem_ty_and_len(base_ty);
                 let elem_size = self.type_size(elem_ty)?.expect("sequence element must be sized");
@@ -444,24 +402,24 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                 };
 
                 let ptr = base_ptr.offset(index * elem_size, &self)?;
-                (ptr, LvalueExtra::None, aligned)
+                (ptr, LvalueExtra::None)
             }
 
             Subslice { from, to } => {
                 // FIXME(solson)
                 let base = self.force_allocation(base)?;
-                let (base_ptr, _, aligned) = base.to_ptr_extra_aligned();
+                let (base_ptr, _) = base.to_ptr_extra_aligned();
 
                 let (elem_ty, n) = base.elem_ty_and_len(base_ty);
                 let elem_size = self.type_size(elem_ty)?.expect("slice element must be sized");
                 assert!(u64::from(from) <= n - u64::from(to));
                 let ptr = base_ptr.offset(u64::from(from) * elem_size, &self)?;
                 let extra = LvalueExtra::Length(n - u64::from(to) - u64::from(from));
-                (ptr, extra, aligned)
+                (ptr, extra)
             }
         };
 
-        Ok(Lvalue::Ptr { ptr, extra, aligned })
+        Ok(Lvalue::Ptr { ptr, extra })
     }
 
     pub(super) fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> {
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 88fd254a2f2..f068bc839d1 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -82,12 +82,55 @@ impl LockInfo {
 // Allocations and pointers
 ////////////////////////////////////////////////////////////////////////////////
 
-#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
-pub struct AllocId(pub u64);
+#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct AllocId(u64);
+
+#[derive(Debug)]
+enum AllocIdKind {
+    /// We can't ever have more than `usize::max_value` functions at the same time
+    /// since we never "deallocate" functions
+    Function(usize),
+    /// Locals and heap allocations (also statics for now, but those will get their
+    /// own variant soonish).
+    Runtime(u64),
+}
+
+impl AllocIdKind {
+    fn into_alloc_id(self) -> AllocId {
+        match self {
+            AllocIdKind::Function(n) => AllocId(n as u64),
+            AllocIdKind::Runtime(n) => AllocId((1 << 63) | n),
+        }
+    }
+}
+
+impl AllocId {
+    /// Currently yields the top bit to discriminate the `AllocIdKind`s
+    fn discriminant(self) -> u64 {
+        self.0 >> 63
+    }
+    /// Yields everything but the discriminant bits
+    fn index(self) -> u64 {
+        self.0 & ((1 << 63) - 1)
+    }
+    fn into_alloc_id_kind(self) -> AllocIdKind {
+        match self.discriminant() {
+            0 => AllocIdKind::Function(self.index() as usize),
+            1 => AllocIdKind::Runtime(self.index()),
+            n => bug!("got discriminant {} for AllocId", n),
+        }
+    }
+}
 
 impl fmt::Display for AllocId {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "{}", self.0)
+        write!(f, "{:?}", self.into_alloc_id_kind())
+    }
+}
+
+impl fmt::Debug for AllocId {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "{:?}", self.into_alloc_id_kind())
     }
 }
 
@@ -108,7 +151,7 @@ pub struct Allocation<M> {
     /// 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<M>,
+    pub kind: MemoryKind<M>,
     /// Memory regions that are locked by some function
     locks: RangeMap<LockInfo>,
 }
@@ -129,7 +172,7 @@ impl<M> Allocation<M> {
 }
 
 #[derive(Debug, PartialEq, Copy, Clone)]
-pub enum Kind<T> {
+pub enum MemoryKind<T> {
     /// Error if deallocated except during a stack pop
     Stack,
     /// Static in the process of being initialized.
@@ -186,16 +229,10 @@ 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<M::MemoryKinds>>,
+    alloc_map: HashMap<u64, Allocation<M::MemoryKinds>>,
 
-    /// The AllocId to assign to the next new allocation. Always incremented, never gets smaller.
-    next_id: AllocId,
-
-    /// 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>,
+    /// The AllocId to assign to the next new regular allocation. Always incremented, never gets smaller.
+    next_alloc_id: u64,
 
     /// Number of virtual bytes allocated.
     memory_usage: u64,
@@ -205,7 +242,7 @@ pub struct Memory<'a, 'tcx, M: Machine<'tcx>> {
 
     /// Function "allocations". They exist solely so pointers have something to point to, and
     /// we can figure out what they point to.
-    functions: HashMap<AllocId, ty::Instance<'tcx>>,
+    functions: Vec<ty::Instance<'tcx>>,
 
     /// Inverse map of `functions` so we don't allocate a new pointer every time we need one
     function_alloc_cache: HashMap<ty::Instance<'tcx>, AllocId>,
@@ -231,13 +268,12 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
         Memory {
             data,
             alloc_map: HashMap::new(),
-            functions: HashMap::new(),
+            functions: Vec::new(),
             function_alloc_cache: HashMap::new(),
-            next_id: AllocId(0),
+            next_alloc_id: 0,
             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),
@@ -245,20 +281,20 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
         }
     }
 
-    pub fn allocations(&self) -> ::std::collections::hash_map::Iter<AllocId, Allocation<M::MemoryKinds>> {
-        self.alloc_map.iter()
+    pub fn allocations<'x>(&'x self) -> impl Iterator<Item = (AllocId, &'x Allocation<M::MemoryKinds>)> {
+        self.alloc_map.iter().map(|(&id, alloc)| (AllocIdKind::Runtime(id).into_alloc_id(), alloc))
     }
 
     pub fn create_fn_alloc(&mut self, instance: ty::Instance<'tcx>) -> MemoryPointer {
         if let Some(&alloc_id) = self.function_alloc_cache.get(&instance) {
             return MemoryPointer::new(alloc_id, 0);
         }
-        let id = self.next_id;
+        let id = self.functions.len();
         debug!("creating fn ptr: {}", id);
-        self.next_id.0 += 1;
-        self.functions.insert(id, instance);
-        self.function_alloc_cache.insert(instance, id);
-        MemoryPointer::new(id, 0)
+        self.functions.push(instance);
+        let alloc_id = AllocIdKind::Function(id).into_alloc_id();
+        self.function_alloc_cache.insert(instance, alloc_id);
+        MemoryPointer::new(alloc_id, 0)
     }
 
     pub fn allocate_cached(&mut self, bytes: &[u8]) -> EvalResult<'tcx, MemoryPointer> {
@@ -266,7 +302,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
             return Ok(MemoryPointer::new(alloc_id, 0));
         }
 
-        let ptr = self.allocate(bytes.len() as u64, 1, Kind::UninitializedStatic)?;
+        let ptr = self.allocate(bytes.len() as u64, 1, MemoryKind::UninitializedStatic)?;
         self.write_bytes(ptr.into(), bytes)?;
         self.mark_static_initalized(ptr.alloc_id, Mutability::Immutable)?;
         self.literal_alloc_cache.insert(bytes.to_vec(), ptr.alloc_id);
@@ -277,7 +313,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
         &mut self,
         size: u64,
         align: u64,
-        kind: Kind<M::MemoryKinds>,
+        kind: MemoryKind<M::MemoryKinds>,
     ) -> EvalResult<'tcx, MemoryPointer> {
         assert_ne!(align, 0);
         assert!(align.is_power_of_two());
@@ -300,10 +336,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
             mutable: Mutability::Mutable,
             locks: RangeMap::new(),
         };
-        let id = self.next_id;
-        self.next_id.0 += 1;
+        let id = self.next_alloc_id;
+        self.next_alloc_id += 1;
         self.alloc_map.insert(id, alloc);
-        Ok(MemoryPointer::new(id, 0))
+        Ok(MemoryPointer::new(AllocIdKind::Runtime(id).into_alloc_id(), 0))
     }
 
     pub fn reallocate(
@@ -313,7 +349,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
         old_align: u64,
         new_size: u64,
         new_align: u64,
-        kind: Kind<M::MemoryKinds>,
+        kind: MemoryKind<M::MemoryKinds>,
     ) -> EvalResult<'tcx, MemoryPointer> {
         use std::cmp::min;
 
@@ -338,13 +374,19 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
         &mut self,
         ptr: MemoryPointer,
         size_and_align: Option<(u64, u64)>,
-        kind: Kind<M::MemoryKinds>,
+        kind: MemoryKind<M::MemoryKinds>,
     ) -> EvalResult<'tcx> {
         if ptr.offset != 0 {
             return err!(DeallocateNonBasePtr);
         }
 
-        let alloc = match self.alloc_map.remove(&ptr.alloc_id) {
+        let alloc_id = match ptr.alloc_id.into_alloc_id_kind() {
+            AllocIdKind::Function(_) =>
+                return err!(DeallocatedWrongMemoryKind("function".to_string(), format!("{:?}", kind))),
+            AllocIdKind::Runtime(id) => id,
+        };
+
+        let alloc = match self.alloc_map.remove(&alloc_id) {
             Some(alloc) => alloc,
             None => return err!(DoubleFree),
         };
@@ -624,22 +666,22 @@ 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<M::MemoryKinds>> {
-        match self.alloc_map.get(&id) {
-            Some(alloc) => Ok(alloc),
-            None => match self.functions.get(&id) {
-                Some(_) => err!(DerefFunctionPointer),
+        match id.into_alloc_id_kind() {
+            AllocIdKind::Function(_) => err!(DerefFunctionPointer),
+            AllocIdKind::Runtime(id) => match self.alloc_map.get(&id) {
+                Some(alloc) => Ok(alloc),
                 None => err!(DanglingPointerDeref),
-            }
+            },
         }
     }
     
     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) {
-                Some(_) => err!(DerefFunctionPointer),
+        match id.into_alloc_id_kind() {
+            AllocIdKind::Function(_) => err!(DerefFunctionPointer),
+            AllocIdKind::Runtime(id) => match self.alloc_map.get_mut(&id) {
+                Some(alloc) => Ok(alloc),
                 None => err!(DanglingPointerDeref),
-            }
+            },
         }
     }
 
@@ -657,12 +699,9 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
             return err!(InvalidFunctionPointer);
         }
         debug!("reading fn ptr: {}", ptr.alloc_id);
-        match self.functions.get(&ptr.alloc_id) {
-            Some(&fndef) => Ok(fndef),
-            None => match self.alloc_map.get(&ptr.alloc_id) {
-                Some(_) => err!(ExecuteMemory),
-                None => err!(InvalidFunctionPointer),
-            }
+        match ptr.alloc_id.into_alloc_id_kind() {
+            AllocIdKind::Function(id) => Ok(self.functions[id]),
+            AllocIdKind::Runtime(_) => err!(ExecuteMemory),
         }
     }
 
@@ -684,17 +723,18 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
             let prefix_len = msg.len();
             let mut relocations = vec![];
 
-            let alloc = match (self.alloc_map.get(&id), self.functions.get(&id)) {
-                (Some(a), None) => a,
-                (None, Some(instance)) => {
-                    trace!("{} {}", msg, instance);
+            let alloc = match id.into_alloc_id_kind() {
+                AllocIdKind::Function(id) => {
+                    trace!("{} {}", msg, self.functions[id]);
                     continue;
                 },
-                (None, None) => {
-                    trace!("{} (deallocated)", msg);
-                    continue;
+                AllocIdKind::Runtime(id) => match self.alloc_map.get(&id) {
+                    Some(a) => a,
+                    None => {
+                        trace!("{} (deallocated)", msg);
+                        continue;
+                    }
                 },
-                (Some(_), Some(_)) => bug!("miri invariant broken: an allocation id exists that points to both a function and a memory location"),
             };
 
             for i in 0..(alloc.bytes.len() as u64) {
@@ -713,11 +753,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)".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(),
+                (MemoryKind::UninitializedStatic, _) => " (static in the process of initialization)".to_owned(),
+                (MemoryKind::Static, Mutability::Mutable) => " (static mut)".to_owned(),
+                (MemoryKind::Static, Mutability::Immutable) => " (immutable)".to_owned(),
+                (MemoryKind::Machine(m), _) => format!(" ({:?})", m),
+                (MemoryKind::Stack, _) => " (stack)".to_owned(),
             };
             trace!("{}({} bytes, alignment {}){}", msg, alloc.bytes.len(), alloc.align, immutable);
 
@@ -744,8 +784,8 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
         let leaks: Vec<_> = self.alloc_map
             .iter()
             .filter_map(|(&key, val)| {
-                if val.kind != Kind::Static {
-                    Some(key)
+                if val.kind != MemoryKind::Static {
+                    Some(AllocIdKind::Runtime(key).into_alloc_id())
                 } else {
                     None
                 }
@@ -812,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 != MemoryKind::UninitializedStatic) {
             self.mark_static_initalized(alloc, mutability)?;
         }
         Ok(())
@@ -834,28 +867,31 @@ impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> {
         trace!("mark_static_initalized {:?}, mutability: {:?}", alloc_id, mutability);
         // do not use `self.get_mut(alloc_id)` here, because we might have already marked a
         // sub-element or have circular pointers (e.g. `Rc`-cycles)
+        let alloc_id = match alloc_id.into_alloc_id_kind() {
+            AllocIdKind::Function(_) => return Ok(()),
+            AllocIdKind::Runtime(id) => id,
+        };
         let relocations = match self.alloc_map.get_mut(&alloc_id) {
             Some(&mut Allocation { ref mut relocations, ref mut kind, ref mut mutable, .. }) => {
                 match *kind {
                     // const eval results can refer to "locals".
                     // E.g. `const Foo: &u32 = &1;` refers to the temp local that stores the `1`
-                    Kind::Stack |
+                    MemoryKind::Stack |
                     // The entire point of this function
-                    Kind::UninitializedStatic => {},
-                    Kind::Machine(m) => M::mark_static_initialized(m)?,
-                    Kind::Static => {
+                    MemoryKind::UninitializedStatic => {},
+                    MemoryKind::Machine(m) => M::mark_static_initialized(m)?,
+                    MemoryKind::Static => {
                         trace!("mark_static_initalized: skipping already initialized static referred to by static currently being initialized");
                         return Ok(());
                     },
                 }
-                *kind = Kind::Static;
+                *kind = MemoryKind::Static;
                 *mutable = mutability;
                 // take out the relocations vector to free the borrow on self, so we can call
                 // mark recursively
                 mem::replace(relocations, Default::default())
             },
-            None if !self.functions.contains_key(&alloc_id) => return err!(DanglingPointerDeref),
-            _ => return Ok(()),
+            None => return err!(DanglingPointerDeref),
         };
         // recurse into inner allocations
         for &alloc in relocations.values() {
diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs
index 39a0c7d25f9..392724757eb 100644
--- a/src/librustc_mir/interpret/mod.rs
+++ b/src/librustc_mir/interpret/mod.rs
@@ -33,12 +33,12 @@ pub use self::eval_context::{
     StackPopCleanup,
     DynamicLifetime,
     TyAndPacked,
+    PtrAndAlign,
 };
 
 pub use self::lvalue::{
     Lvalue,
     LvalueExtra,
-    Global,
     GlobalId,
 };
 
@@ -46,7 +46,7 @@ pub use self::memory::{
     AllocId,
     Memory,
     MemoryPointer,
-    Kind,
+    MemoryKind,
     HasMemory,
 };
 
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..a85d8d05c32 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -13,10 +13,9 @@ use rustc::ty::subst::Substs;
 
 use super::{
     EvalResult,
-    EvalContext, StackPopCleanup, TyAndPacked,
-    Global, GlobalId, Lvalue,
-    Value, PrimVal,
-    HasMemory,
+    EvalContext, StackPopCleanup, TyAndPacked, PtrAndAlign,
+    GlobalId, Lvalue,
+    HasMemory, MemoryKind,
     Machine,
 };
 
@@ -179,11 +178,19 @@ 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, MemoryKind::UninitializedStatic)?;
+            self.memory.write_usize(ptr, 0)?;
+            self.memory.mark_static_initalized(ptr.alloc_id, mutability)?;
+            self.globals.insert(cid, PtrAndAlign { ptr: ptr.into(), aligned: true });
             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, MemoryKind::UninitializedStatic)?;
+        let aligned = !self.is_packed(mir.return_ty)?;
+        self.globals.insert(cid, PtrAndAlign { ptr: ptr.into(), aligned });
         let internally_mutable = !mir.return_ty.is_freeze(
                 self.tcx,
                 ty::ParamEnv::empty(Reveal::All),
@@ -200,7 +207,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 +263,16 @@ 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, MemoryKind::UninitializedStatic)?;
+                    let aligned = !this.ecx.is_packed(mir.return_ty)?;
+                    this.ecx.globals.insert(cid, PtrAndAlign { ptr: ptr.into(), aligned });
                     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..36d56511afc 100644
--- a/src/librustc_mir/interpret/terminator/drop.rs
+++ b/src/librustc_mir/interpret/terminator/drop.rs
@@ -11,15 +11,15 @@ 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
         // by rustc.
         let val = match self.force_allocation(lval)? {
-            Lvalue::Ptr { ptr, extra: LvalueExtra::Vtable(vtable), aligned: _ } => ptr.to_value_with_vtable(vtable),
-            Lvalue::Ptr { ptr, extra: LvalueExtra::Length(len), aligned: _ } => ptr.to_value_with_len(len),
-            Lvalue::Ptr { ptr, extra: LvalueExtra::None, aligned: _ } => ptr.to_value(),
+            Lvalue::Ptr { ptr, extra: LvalueExtra::Vtable(vtable) } => ptr.ptr.to_value_with_vtable(vtable),
+            Lvalue::Ptr { ptr, extra: LvalueExtra::Length(len) } => ptr.ptr.to_value_with_len(len),
+            Lvalue::Ptr { ptr, extra: LvalueExtra::None } => ptr.ptr.to_value(),
             _ => bug!("force_allocation broken"),
         };
         self.drop(val, instance, ty, span)
diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs
index b9447a30ab1..531e1792d9e 100644
--- a/src/librustc_mir/interpret/terminator/mod.rs
+++ b/src/librustc_mir/interpret/terminator/mod.rs
@@ -6,7 +6,7 @@ use syntax::abi::Abi;
 
 use super::{
     EvalError, EvalResult, EvalErrorKind,
-    EvalContext, eval_context, TyAndPacked,
+    EvalContext, eval_context, TyAndPacked, PtrAndAlign,
     Lvalue,
     MemoryPointer,
     PrimVal, Value,
@@ -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>,
@@ -311,10 +311,10 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
                             if self.frame().mir.args_iter().count() == fields.len() + 1 {
                                 let offsets = variant.offsets.iter().map(|s| s.bytes());
                                 match arg_val {
-                                    Value::ByRef { ptr, aligned } => {
+                                    Value::ByRef(PtrAndAlign { ptr, aligned }) => {
                                         assert!(aligned, "Unaligned ByRef-values cannot occur as function arguments");
                                         for ((offset, ty), arg_local) in offsets.zip(fields).zip(arg_locals) {
-                                            let arg = Value::ByRef { ptr: ptr.offset(offset, &self)?, aligned: true};
+                                            let arg = Value::by_ref(ptr.offset(offset, &self)?);
                                             let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?;
                                             trace!("writing arg {:?} to {:?} (type: {})", arg, dest, ty);
                                             self.write_value(arg, dest, ty)?;
diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs
index a1821e58a99..3b642591917 100644
--- a/src/librustc_mir/interpret/traits.rs
+++ b/src/librustc_mir/interpret/traits.rs
@@ -8,7 +8,7 @@ use syntax::ast::{self, Mutability};
 use super::{
     EvalResult,
     EvalContext, eval_context,
-    MemoryPointer, Kind,
+    MemoryPointer, MemoryKind,
     Value, PrimVal,
     Machine,
 };
@@ -51,7 +51,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
 
         let ptr_size = self.memory.pointer_size();
         let methods = ::rustc::traits::get_vtable_methods(self.tcx, trait_ref);
-        let vtable = self.memory.allocate(ptr_size * (3 + methods.count() as u64), ptr_size, Kind::UninitializedStatic)?;
+        let vtable = self.memory.allocate(ptr_size * (3 + methods.count() as u64), ptr_size, MemoryKind::UninitializedStatic)?;
 
         let drop = eval_context::resolve_drop_in_place(self.tcx, ty);
         let drop = self.memory.create_fn_alloc(drop);
diff --git a/src/librustc_mir/interpret/validation.rs b/src/librustc_mir/interpret/validation.rs
index 83931535e59..b291c639b9c 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 {
@@ -213,7 +213,7 @@ impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> {
         };
         if is_owning {
             match query.lval {
-                Lvalue::Ptr { ptr, extra, aligned: _ } => {
+                Lvalue::Ptr { ptr, extra } => {
                     // Determine the size
                     // FIXME: Can we reuse size_and_align_of_dst for Lvalues?
                     let len = match self.type_size(query.ty)? {
@@ -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..be6d304d3f5 100644
--- a/src/librustc_mir/interpret/value.rs
+++ b/src/librustc_mir/interpret/value.rs
@@ -7,6 +7,7 @@ use super::{
     EvalResult,
     Memory, MemoryPointer, HasMemory, PointerArithmetic,
     Machine,
+    PtrAndAlign,
 };
 
 pub(super) fn bytes_to_f32(bytes: u128) -> f32 {
@@ -36,7 +37,7 @@ pub(super) fn f64_to_bytes(f: f64) -> u128 {
 /// operations and fat pointers. This idea was taken from rustc's trans.
 #[derive(Clone, Copy, Debug)]
 pub enum Value {
-    ByRef { ptr: Pointer, aligned: bool},
+    ByRef(PtrAndAlign),
     ByVal(PrimVal),
     ByValPair(PrimVal, PrimVal),
 }
@@ -166,7 +167,7 @@ pub enum PrimValKind {
 impl<'a, 'tcx: 'a> Value {
     #[inline]
     pub fn by_ref(ptr: Pointer) -> Self {
-        Value::ByRef { ptr, aligned: true }
+        Value::ByRef(PtrAndAlign { ptr, aligned: true })
     }
 
     /// Convert the value into a pointer (or a pointer-sized integer).  If the value is a ByRef,
@@ -174,7 +175,7 @@ impl<'a, 'tcx: 'a> Value {
     pub fn into_ptr<M: Machine<'tcx>>(&self, mem: &Memory<'a, 'tcx, M>) -> EvalResult<'tcx, Pointer> {
         use self::Value::*;
         match *self {
-            ByRef { ptr, aligned } => {
+            ByRef(PtrAndAlign { ptr, aligned }) => {
                 mem.read_maybe_aligned(aligned, |mem| mem.read_ptr(ptr.to_ptr()?) )
             },
             ByVal(ptr) | ByValPair(ptr, _) => Ok(ptr.into()),
@@ -187,7 +188,7 @@ impl<'a, 'tcx: 'a> Value {
     ) -> EvalResult<'tcx, (Pointer, MemoryPointer)> {
         use self::Value::*;
         match *self {
-            ByRef { ptr: ref_ptr, aligned } => {
+            ByRef(PtrAndAlign { ptr: ref_ptr, aligned }) => {
                 mem.read_maybe_aligned(aligned, |mem| {
                     let ptr = mem.read_ptr(ref_ptr.to_ptr()?)?;
                     let vtable = mem.read_ptr(ref_ptr.offset(mem.pointer_size(), mem.layout)?.to_ptr()?)?;
@@ -205,7 +206,7 @@ impl<'a, 'tcx: 'a> Value {
     pub(super) fn into_slice<M: Machine<'tcx>>(&self, mem: &Memory<'a, 'tcx, M>) -> EvalResult<'tcx, (Pointer, u64)> {
         use self::Value::*;
         match *self {
-            ByRef { ptr: ref_ptr, aligned } => {
+            ByRef(PtrAndAlign { ptr: ref_ptr, aligned } ) => {
                 mem.read_maybe_aligned(aligned, |mem| {
                     let ptr = mem.read_ptr(ref_ptr.to_ptr()?)?;
                     let len = mem.read_usize(ref_ptr.offset(mem.pointer_size(), mem.layout)?.to_ptr()?)?;
diff --git a/tests/compile-fail/fn_ptr_offset.rs b/tests/compile-fail/fn_ptr_offset.rs
index 3e4c5d6ad39..45e32142a8c 100644
--- a/tests/compile-fail/fn_ptr_offset.rs
+++ b/tests/compile-fail/fn_ptr_offset.rs
@@ -10,5 +10,5 @@ fn main() {
     let y : *mut u8 = unsafe { mem::transmute(x) };
     let y = y.wrapping_offset(1);
     let x : fn() = unsafe { mem::transmute(y) };
-    x(); //~ ERROR: tried to use an integer pointer or a dangling pointer as a function pointer
+    x(); //~ ERROR: tried to use a function pointer after offsetting it
 }
diff --git a/tests/run-pass/packed_static.rs b/tests/run-pass/packed_static.rs
new file mode 100644
index 00000000000..1fa3a369670
--- /dev/null
+++ b/tests/run-pass/packed_static.rs
@@ -0,0 +1,10 @@
+#[repr(packed)]
+struct Foo {
+    i: i32
+}
+
+fn main() {
+    assert_eq!({FOO.i}, 42);
+}
+
+static FOO: Foo = Foo { i: 42 };