about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorOliver Schneider <oli-obk@users.noreply.github.com>2017-07-31 12:41:29 +0200
committerGitHub <noreply@github.com>2017-07-31 12:41:29 +0200
commit7c6befe69f202f70e008e1ef398b4c09c2b3d485 (patch)
tree1712af9533fc408bbd7b6fa66c1046c3b177d000 /src
parentf906c5458c43d0666dd9af37f44cd46a190f0506 (diff)
parent4458001644d084f9741ccc0227ed1afb96ca0dbf (diff)
downloadrust-7c6befe69f202f70e008e1ef398b4c09c2b3d485.tar.gz
rust-7c6befe69f202f70e008e1ef398b4c09c2b3d485.zip
Merge pull request #274 from RalfJung/packed2
make force_allocation handle packed ByValPair
Diffstat (limited to 'src')
-rw-r--r--src/librustc_mir/interpret/eval_context.rs120
-rw-r--r--src/librustc_mir/interpret/lvalue.rs14
-rw-r--r--src/librustc_mir/interpret/memory.rs52
-rw-r--r--src/librustc_mir/interpret/step.rs12
-rw-r--r--src/librustc_mir/interpret/terminator/intrinsic.rs44
-rw-r--r--src/librustc_mir/interpret/terminator/mod.rs59
-rw-r--r--src/librustc_mir/interpret/validation.rs4
-rw-r--r--src/librustc_mir/interpret/value.rs18
8 files changed, 185 insertions, 138 deletions
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 331ae7e248b..bbaaba08a14 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -142,6 +142,12 @@ impl Default for ResourceLimits {
     }
 }
 
+#[derive(Copy, Clone, Debug)]
+pub struct TyAndPacked<'tcx> {
+    pub ty: Ty<'tcx>,
+    pub packed: bool,
+}
+
 impl<'a, 'tcx> EvalContext<'a, 'tcx> {
     pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, limits: ResourceLimits) -> Self {
         EvalContext {
@@ -381,7 +387,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                     .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) =>
+                    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 {
@@ -439,7 +445,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
     }
 
     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, aligned: _ }) = local {
             trace!("deallocating local");
             let ptr = ptr.to_ptr()?;
             self.memory.dump_alloc(ptr.alloc_id);
@@ -609,7 +615,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                                     let operand_ty = self.operand_ty(operand);
                                     assert_eq!(self.type_size(operand_ty)?, Some(0));
                                 }
-                                let (offset, ty) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?;
+                                let (offset, TyAndPacked { ty, packed: _}) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?;
+                                // TODO: The packed flag is ignored
 
                                 // FIXME(solson)
                                 let dest = self.force_allocation(dest)?.to_ptr()?;
@@ -702,7 +709,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                     LvalueExtra::DowncastVariant(..) =>
                         bug!("attempted to take a reference to an enum downcast lvalue"),
                 };
-
                 self.write_value(val, dest, dest_ty)?;
             }
 
@@ -745,7 +751,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                         let src_ty = self.operand_ty(operand);
                         if self.type_is_fat_ptr(src_ty) {
                             match (src, self.type_is_fat_ptr(dest_ty)) {
-                                (Value::ByRef(..), _) |
+                                (Value::ByRef{..}, _) |
                                 (Value::ByValPair(..), true) => {
                                     self.write_value(src, dest, dest_ty)?;
                                 },
@@ -826,7 +832,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
         ty: Ty<'tcx>,
         nndiscr: u64,
         discrfield: &[u32],
-    ) -> EvalResult<'tcx, (Size, Ty<'tcx>)> {
+    ) -> EvalResult<'tcx, (Size, TyAndPacked<'tcx>)> {
         // Skip the constant 0 at the start meant for LLVM GEP and the outer non-null variant
         let path = discrfield.iter().skip(2).map(|&i| i as usize);
 
@@ -849,16 +855,19 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
         mut offset: Size,
         mut ty: Ty<'tcx>,
         path: I,
-    ) -> EvalResult<'tcx, (Size, Ty<'tcx>)> {
+    ) -> EvalResult<'tcx, (Size, TyAndPacked<'tcx>)> {
         // Skip the initial 0 intended for LLVM GEP.
+        let mut packed = false;
         for field_index in path {
             let field_offset = self.get_field_offset(ty, field_index)?;
             trace!("field_path_offset_and_ty: {}, {}, {:?}, {:?}", field_index, ty, field_offset, offset);
-            ty = self.get_field_ty(ty, field_index)?;
+            let field_ty = self.get_field_ty(ty, field_index)?;
+            ty = field_ty.ty;
+            packed = packed || field_ty.packed;
             offset = offset.checked_add(field_offset, &self.tcx.data_layout).unwrap();
         }
 
-        Ok((offset, ty))
+        Ok((offset, TyAndPacked { ty, packed }))
     }
     fn get_fat_field(&self, pointee_ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Ty<'tcx>> {
         match (field_index, &self.tcx.struct_tail(pointee_ty).sty) {
@@ -870,33 +879,46 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
         }
     }
 
-    pub fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Ty<'tcx>> {
+    /// Returns the field type and whether the field is packed
+    pub fn get_field_ty(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, TyAndPacked<'tcx>> {
         match ty.sty {
-            ty::TyAdt(adt_def, _) if adt_def.is_box() => self.get_fat_field(ty.boxed_ty(), field_index),
+            ty::TyAdt(adt_def, _) if adt_def.is_box() =>
+                Ok(TyAndPacked { ty: self.get_fat_field(ty.boxed_ty(), field_index)?, packed: false }),
             ty::TyAdt(adt_def, substs) if adt_def.is_enum() => {
                 use rustc::ty::layout::Layout::*;
                 match *self.type_layout(ty)? {
-                    RawNullablePointer { nndiscr, .. } |
-                    StructWrappedNullablePointer { nndiscr, .. } => Ok(adt_def.variants[nndiscr as usize].fields[field_index].ty(self.tcx, substs)),
+                    RawNullablePointer { nndiscr, .. } =>
+                        Ok(TyAndPacked { ty: adt_def.variants[nndiscr as usize].fields[field_index].ty(self.tcx, substs), packed: false }),
+                    StructWrappedNullablePointer { nndiscr, ref nonnull, .. } => {
+                        let ty = adt_def.variants[nndiscr as usize].fields[field_index].ty(self.tcx, substs);
+                        Ok(TyAndPacked { ty, packed: nonnull.packed })
+                    },
                     _ => Err(EvalError::Unimplemented(format!("get_field_ty can't handle enum type: {:?}, {:?}", ty, ty.sty))),
                 }
             }
             ty::TyAdt(adt_def, substs) => {
-                Ok(adt_def.struct_variant().fields[field_index].ty(self.tcx, substs))
+                let variant_def = adt_def.struct_variant();
+                use rustc::ty::layout::Layout::*;
+                match *self.type_layout(ty)? {
+                    Univariant { ref variant, .. } =>
+                        Ok(TyAndPacked { ty: variant_def.fields[field_index].ty(self.tcx, substs), packed: variant.packed }),
+                    _ => Err(EvalError::Unimplemented(format!("get_field_ty can't handle struct type: {:?}, {:?}", ty, ty.sty))),
+                }
             }
 
-            ty::TyTuple(fields, _) => Ok(fields[field_index]),
+            ty::TyTuple(fields, _) => Ok(TyAndPacked { ty: fields[field_index], packed: false }),
 
             ty::TyRef(_, ref tam) |
-            ty::TyRawPtr(ref tam) => self.get_fat_field(tam.ty, field_index),
+            ty::TyRawPtr(ref tam) => Ok(TyAndPacked { ty: self.get_fat_field(tam.ty, field_index)?, packed: false }),
 
-            ty::TyArray(ref inner, _) => Ok(inner),
+            ty::TyArray(ref inner, _) => Ok(TyAndPacked { ty: inner, packed: false }),
 
             _ => Err(EvalError::Unimplemented(format!("can't handle type: {:?}, {:?}", ty, ty.sty))),
         }
     }
 
     fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Size> {
+        // Also see lvalue_field in lvalue.rs, which handles more cases but needs an actual value at the given type
         let layout = self.type_layout(ty)?;
 
         use rustc::ty::layout::Layout::*;
@@ -1026,7 +1048,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                 // -1 since we don't store the return value
                 match self.stack[frame].locals[local.index() - 1] {
                     None => return Err(EvalError::DeadLocal),
-                    Some(Value::ByRef(ptr, aligned)) => {
+                    Some(Value::ByRef { ptr, aligned }) => {
                         Lvalue::Ptr { ptr, aligned, extra: LvalueExtra::None }
                     },
                     Some(val) => {
@@ -1044,7 +1066,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             Lvalue::Global(cid) => {
                 let global_val = self.globals.get(&cid).expect("global not cached").clone();
                 match global_val.value {
-                    Value::ByRef(ptr, aligned) =>
+                    Value::ByRef { ptr, aligned } =>
                         Lvalue::Ptr { ptr, aligned, extra: LvalueExtra::None },
                     _ => {
                         let ptr = self.alloc_ptr_with_substs(global_val.ty, cid.instance.substs)?;
@@ -1070,7 +1092,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
     /// 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 { ptr, aligned } => {
                 self.read_maybe_aligned(aligned, |ectx| ectx.read_value(ptr, ty))
             }
             other => Ok(other),
@@ -1079,7 +1101,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
     pub(super) fn value_to_primval(&mut self, value: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> {
         match self.follow_by_ref_value(value, ty)? {
-            Value::ByRef(..) => bug!("follow_by_ref_value can't result in `ByRef`"),
+            Value::ByRef{..} => bug!("follow_by_ref_value can't result in `ByRef`"),
 
             Value::ByVal(primval) => {
                 self.ensure_valid_value(primval, ty)?;
@@ -1145,7 +1167,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
             Lvalue::Ptr { ptr, extra, aligned } => {
                 assert_eq!(extra, LvalueExtra::None);
-                self.write_maybe_aligned(aligned,
+                self.write_maybe_aligned_mut(aligned,
                     |ectx| ectx.write_value_to_ptr(src_val, ptr, dest_ty))
             }
 
@@ -1169,7 +1191,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
         old_dest_val: Value,
         dest_ty: Ty<'tcx>,
     ) -> EvalResult<'tcx> {
-        if let Value::ByRef(dest_ptr, aligned) = old_dest_val {
+        if let Value::ByRef { 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
@@ -1177,10 +1199,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             //
             // Thus, it would be an error to replace the `ByRef` with a `ByVal`, unless we
             // knew for certain that there were no outstanding pointers to this allocation.
-            self.write_maybe_aligned(aligned,
+            self.write_maybe_aligned_mut(aligned,
                 |ectx| ectx.write_value_to_ptr(src_val, dest_ptr, dest_ty))?;
 
-        } else if let Value::ByRef(src_ptr, aligned) = src_val {
+        } else if let Value::ByRef { 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.
             //
@@ -1192,7 +1214,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             // It is a valid optimization to attempt reading a primitive value out of the
             // source and write that into the destination without making an allocation, so
             // we do so here.
-            self.read_maybe_aligned(aligned, |ectx| {
+            self.read_maybe_aligned_mut(aligned, |ectx| {
                 if let Ok(Some(src_val)) = ectx.try_read_value(src_ptr, dest_ty) {
                     write_dest(ectx, src_val)?;
                 } else {
@@ -1218,8 +1240,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
         dest_ty: Ty<'tcx>,
     ) -> EvalResult<'tcx> {
         match value {
-            Value::ByRef(ptr, aligned) => {
-                self.read_maybe_aligned(aligned, |ectx| ectx.copy(ptr, dest, dest_ty))
+            Value::ByRef { ptr, aligned } => {
+                self.read_maybe_aligned_mut(aligned, |ectx| ectx.copy(ptr, dest, dest_ty))
             },
             Value::ByVal(primval) => {
                 let size = self.type_size(dest_ty)?.expect("dest type must be sized");
@@ -1236,20 +1258,27 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
         ptr: MemoryPointer,
         mut ty: Ty<'tcx>
     ) -> EvalResult<'tcx> {
+        let mut packed = false;
         while self.get_field_count(ty)? == 1 {
-            ty = self.get_field_ty(ty, 0)?;
+            let field = self.get_field_ty(ty, 0)?;
+            ty = field.ty;
+            packed = packed || field.packed;
         }
         assert_eq!(self.get_field_count(ty)?, 2);
-        let field_0 = self.get_field_offset(ty, 0)?.bytes();
-        let field_1 = self.get_field_offset(ty, 1)?.bytes();
+        let field_0 = self.get_field_offset(ty, 0)?;
+        let field_1 = self.get_field_offset(ty, 1)?;
         let field_0_ty = self.get_field_ty(ty, 0)?;
         let field_1_ty = self.get_field_ty(ty, 1)?;
-        let field_0_size = self.type_size(field_0_ty)?.expect("pair element type must be sized");
-        let field_1_size = self.type_size(field_1_ty)?.expect("pair element type must be sized");
-        let field_0_ptr = ptr.offset(field_0, &self)?.into();
-        let field_1_ptr = ptr.offset(field_1, &self)?.into();
-        self.memory.write_primval(field_0_ptr, a, field_0_size)?;
-        self.memory.write_primval(field_1_ptr, b, field_1_size)?;
+        assert_eq!(field_0_ty.packed, field_1_ty.packed, "the two fields must agree on being packed");
+        packed = packed || field_0_ty.packed;
+        let field_0_size = self.type_size(field_0_ty.ty)?.expect("pair element type must be sized");
+        let field_1_size = self.type_size(field_1_ty.ty)?.expect("pair element type must be sized");
+        let field_0_ptr = ptr.offset(field_0.bytes(), &self)?.into();
+        let field_1_ptr = ptr.offset(field_1.bytes(), &self)?.into();
+        self.write_maybe_aligned_mut(!packed,
+            |ectx| ectx.memory.write_primval(field_0_ptr, a, field_0_size))?;
+        self.write_maybe_aligned_mut(!packed,
+            |ectx| ectx.memory.write_primval(field_1_ptr, b, field_1_size))?;
         Ok(())
     }
 
@@ -1352,7 +1381,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
         }
     }
 
-    pub(super) fn read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
+    pub(super) fn read_value(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> {
         if let Some(val) = self.try_read_value(ptr, ty)? {
             Ok(val)
         } else {
@@ -1376,7 +1405,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
         }
     }
 
-    fn try_read_value(&mut self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
+    fn try_read_value(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Option<Value>> {
         use syntax::ast::FloatTy;
 
         let val = match ty.sty {
@@ -1488,7 +1517,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
         match (&src_pointee_ty.sty, &dest_pointee_ty.sty) {
             (&ty::TyArray(_, length), &ty::TySlice(_)) => {
-                let ptr = src.into_ptr(&mut self.memory)?;
+                let ptr = src.into_ptr(&self.memory)?;
                 // u64 cast is from usize to u64, which is always good
                 self.write_value(ptr.to_value_with_len(length as u64), dest, dest_ty)
             }
@@ -1502,7 +1531,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                 let trait_ref = data.principal().unwrap().with_self_ty(self.tcx, src_pointee_ty);
                 let trait_ref = self.tcx.erase_regions(&trait_ref);
                 let vtable = self.get_vtable(src_pointee_ty, trait_ref)?;
-                let ptr = src.into_ptr(&mut self.memory)?;
+                let ptr = src.into_ptr(&self.memory)?;
                 self.write_value(ptr.to_value_with_vtable(vtable), dest, dest_ty)
             },
 
@@ -1529,8 +1558,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                     return self.unsize_into_ptr(src, src_ty, dest, dest_ty, src_ty.boxed_ty(), dest_ty.boxed_ty());
                 }
                 if self.ty_to_primval_kind(src_ty).is_ok() {
-                    let sty = self.get_field_ty(src_ty, 0)?;
-                    let dty = self.get_field_ty(dest_ty, 0)?;
+                    // TODO: We ignore the packed flag here
+                    let sty = self.get_field_ty(src_ty, 0)?.ty;
+                    let dty = self.get_field_ty(dest_ty, 0)?.ty;
                     return self.unsize_into(src, sty, dest, dty);
                 }
                 // unsizing of generic struct with pointer fields
@@ -1545,7 +1575,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                 //let src = adt::MaybeSizedValue::sized(src);
                 //let dst = adt::MaybeSizedValue::sized(dst);
                 let src_ptr = match src {
-                    Value::ByRef(ptr, true) => ptr,
+                    Value::ByRef { ptr, aligned: true } => ptr,
                     // TODO: Is it possible for unaligned pointers to occur here?
                     _ => bug!("expected aligned pointer, got {:?}", src),
                 };
@@ -1592,7 +1622,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                 Err(err) => {
                     panic!("Failed to access local: {:?}", err);
                 }
-                Ok(Value::ByRef(ptr, aligned)) => match ptr.into_inner_primval() {
+                Ok(Value::ByRef { ptr, aligned }) => match ptr.into_inner_primval() {
                     PrimVal::Ptr(ptr) => {
                         write!(msg, " by {}ref:", if aligned { "" } else { "unaligned " }).unwrap();
                         allocs.push(ptr.alloc_id);
diff --git a/src/librustc_mir/interpret/lvalue.rs b/src/librustc_mir/interpret/lvalue.rs
index e4ab3d90a5c..a3927e2637a 100644
--- a/src/librustc_mir/interpret/lvalue.rs
+++ b/src/librustc_mir/interpret/lvalue.rs
@@ -196,7 +196,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
         match lvalue {
             Lvalue::Ptr { ptr, extra, aligned } => {
                 assert_eq!(extra, LvalueExtra::None);
-                Ok(Value::ByRef(ptr, aligned))
+                Ok(Value::ByRef { ptr, aligned })
             }
             Lvalue::Local { frame, local } => {
                 self.stack[frame].get_local(local)
@@ -305,7 +305,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                     assert_eq!(offset.bytes(), 0, "ByVal can only have 1 non zst field with offset 0");
                     return Ok(base);
                 },
-                Value::ByRef(..) |
+                Value::ByRef{..} |
                 Value::ByValPair(..) |
                 Value::ByVal(_) => self.force_allocation(base)?.to_ptr_extra_aligned(),
             },
@@ -315,7 +315,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                     assert_eq!(offset.bytes(), 0, "ByVal can only have 1 non zst field with offset 0");
                     return Ok(base);
                 },
-                Value::ByRef(..) |
+                Value::ByRef{..} |
                 Value::ByValPair(..) |
                 Value::ByVal(_) => self.force_allocation(base)?.to_ptr_extra_aligned(),
             },
@@ -349,17 +349,17 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
         Ok(Lvalue::Ptr { ptr, extra, aligned: aligned && !packed })
     }
 
-    pub(super) fn val_to_lvalue(&mut 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<'tcx>> {
         Ok(match self.tcx.struct_tail(ty).sty {
             ty::TyDynamic(..) => {
-                let (ptr, vtable) = val.into_ptr_vtable_pair(&mut self.memory)?;
+                let (ptr, vtable) = val.into_ptr_vtable_pair(&self.memory)?;
                 Lvalue::Ptr { ptr, extra: LvalueExtra::Vtable(vtable), aligned: true }
             },
             ty::TyStr | ty::TySlice(_) => {
-                let (ptr, len) = val.into_slice(&mut self.memory)?;
+                let (ptr, len) = val.into_slice(&self.memory)?;
                 Lvalue::Ptr { ptr, extra: LvalueExtra::Length(len), aligned: true }
             },
-            _ => Lvalue::Ptr { ptr: val.into_ptr(&mut self.memory)?, extra: LvalueExtra::None, aligned: true },
+            _ => Lvalue::Ptr { ptr: val.into_ptr(&self.memory)?, extra: LvalueExtra::None, aligned: true },
         })
     }
 
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index 461fced3c60..2226744c6ab 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -1,6 +1,7 @@
 use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian};
 use std::collections::{btree_map, BTreeMap, HashMap, HashSet, VecDeque};
 use std::{fmt, iter, ptr, mem, io, ops};
+use std::cell::Cell;
 
 use rustc::ty;
 use rustc::ty::layout::{self, TargetDataLayout, HasDataLayout};
@@ -266,8 +267,8 @@ pub struct Memory<'a, 'tcx> {
 
     /// To avoid having to pass flags to every single memory access, we have some global state saying whether
     /// alignment checking is currently enforced for read and/or write accesses.
-    reads_are_aligned: bool,
-    writes_are_aligned: bool,
+    reads_are_aligned: Cell<bool>,
+    writes_are_aligned: Cell<bool>,
 
     /// The current stack frame.  Used to check accesses against locks.
     cur_frame: usize,
@@ -287,8 +288,8 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
             literal_alloc_cache: HashMap::new(),
             thread_local: BTreeMap::new(),
             next_thread_local: 0,
-            reads_are_aligned: true,
-            writes_are_aligned: true,
+            reads_are_aligned: Cell::new(true),
+            writes_are_aligned: Cell::new(true),
             cur_frame: usize::max_value(),
         }
     }
@@ -796,7 +797,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
 impl<'a, 'tcx> Memory<'a, 'tcx> {
     fn get_bytes_unchecked(&self, ptr: MemoryPointer, size: u64, align: u64) -> EvalResult<'tcx, &[u8]> {
         // Zero-sized accesses can use dangling pointers, but they still have to be aligned and non-NULL
-        if self.reads_are_aligned {
+        if self.reads_are_aligned.get() {
             self.check_align(ptr.into(), align)?;
         }
         if size == 0 {
@@ -813,7 +814,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
 
     fn get_bytes_unchecked_mut(&mut self, ptr: MemoryPointer, size: u64, align: u64) -> EvalResult<'tcx, &mut [u8]> {
         // Zero-sized accesses can use dangling pointers, but they still have to be aligned and non-NULL
-        if self.writes_are_aligned {
+        if self.writes_are_aligned.get() {
             self.check_align(ptr.into(), align)?;
         }
         if size == 0 {
@@ -909,10 +910,10 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
     pub fn copy(&mut self, src: Pointer, dest: Pointer, size: u64, align: u64, nonoverlapping: bool) -> EvalResult<'tcx> {
         if size == 0 {
             // Empty accesses don't need to be valid pointers, but they should still be aligned
-            if self.reads_are_aligned {
+            if self.reads_are_aligned.get() {
                 self.check_align(src, align)?;
             }
-            if self.writes_are_aligned {
+            if self.writes_are_aligned.get() {
                 self.check_align(dest, align)?;
             }
             return Ok(());
@@ -968,7 +969,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
     pub fn read_bytes(&self, ptr: Pointer, size: u64) -> EvalResult<'tcx, &[u8]> {
         if size == 0 {
             // Empty accesses don't need to be valid pointers, but they should still be non-NULL
-            if self.reads_are_aligned {
+            if self.reads_are_aligned.get() {
                 self.check_align(ptr, 1)?;
             }
             return Ok(&[]);
@@ -979,7 +980,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
     pub fn write_bytes(&mut self, ptr: Pointer, src: &[u8]) -> EvalResult<'tcx> {
         if src.is_empty() {
             // Empty accesses don't need to be valid pointers, but they should still be non-NULL
-            if self.writes_are_aligned {
+            if self.writes_are_aligned.get() {
                 self.check_align(ptr, 1)?;
             }
             return Ok(());
@@ -992,7 +993,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
     pub fn write_repeat(&mut self, ptr: Pointer, val: u8, count: u64) -> EvalResult<'tcx> {
         if count == 0 {
             // Empty accesses don't need to be valid pointers, but they should still be non-NULL
-            if self.writes_are_aligned {
+            if self.writes_are_aligned.get() {
                 self.check_align(ptr, 1)?;
             }
             return Ok(());
@@ -1399,23 +1400,36 @@ pub(crate) trait HasMemory<'a, 'tcx> {
     fn memory(&self) -> &Memory<'a, 'tcx>;
 
     // These are not supposed to be overriden.
-    fn read_maybe_aligned<F, T>(&mut self, aligned: bool, f: F) -> EvalResult<'tcx, T>
+    fn read_maybe_aligned<F, T>(&self, aligned: bool, f: F) -> EvalResult<'tcx, T>
+        where F: FnOnce(&Self) -> EvalResult<'tcx, T>
+    {
+        let old = self.memory().reads_are_aligned.get();
+        // Do alignment checking if *all* nested calls say it has to be aligned.
+        self.memory().reads_are_aligned.set(old && aligned);
+        let t = f(self);
+        self.memory().reads_are_aligned.set(old);
+        t
+    }
+
+    fn read_maybe_aligned_mut<F, T>(&mut self, aligned: bool, f: F) -> EvalResult<'tcx, T>
         where F: FnOnce(&mut Self) -> EvalResult<'tcx, T>
     {
-        assert!(self.memory_mut().reads_are_aligned, "Unaligned reads must not be nested");
-        self.memory_mut().reads_are_aligned = aligned;
+        let old = self.memory().reads_are_aligned.get();
+        // Do alignment checking if *all* nested calls say it has to be aligned.
+        self.memory().reads_are_aligned.set(old && aligned);
         let t = f(self);
-        self.memory_mut().reads_are_aligned = true;
+        self.memory().reads_are_aligned.set(old);
         t
     }
 
-    fn write_maybe_aligned<F, T>(&mut self, aligned: bool, f: F) -> EvalResult<'tcx, T>
+    fn write_maybe_aligned_mut<F, T>(&mut self, aligned: bool, f: F) -> EvalResult<'tcx, T>
         where F: FnOnce(&mut Self) -> EvalResult<'tcx, T>
     {
-        assert!(self.memory_mut().writes_are_aligned, "Unaligned writes must not be nested");
-        self.memory_mut().writes_are_aligned = aligned;
+        let old = self.memory().writes_are_aligned.get();
+        // Do alignment checking if *all* nested calls say it has to be aligned.
+        self.memory().writes_are_aligned.set(old && aligned);
         let t = f(self);
-        self.memory_mut().writes_are_aligned = true;
+        self.memory().writes_are_aligned.set(old);
         t
     }
 }
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index 86e12323306..1679688625d 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -11,12 +11,14 @@ use rustc::ty;
 use rustc::ty::layout::Layout;
 use rustc::ty::subst::Substs;
 
+use syntax::codemap::Span;
+use syntax::ast::Mutability;
+
 use error::{EvalResult, EvalError};
-use eval_context::{EvalContext, StackPopCleanup};
+use eval_context::{EvalContext, StackPopCleanup, TyAndPacked};
 use lvalue::{Global, GlobalId, Lvalue};
 use value::{Value, PrimVal};
-use syntax::codemap::Span;
-use syntax::ast::Mutability;
+use memory::HasMemory;
 
 impl<'a, 'tcx> EvalContext<'a, 'tcx> {
     pub fn inc_step_counter_and_check_limit(&mut self, n: u64) -> EvalResult<'tcx> {
@@ -101,12 +103,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
                     Layout::StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
                         if variant_index as u64 != nndiscr {
-                            let (offset, ty) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?;
+                            let (offset, TyAndPacked { ty, packed }) = self.nonnull_offset_and_ty(dest_ty, nndiscr, discrfield)?;
                             let nonnull = self.force_allocation(dest)?.to_ptr()?.offset(offset.bytes(), &self)?;
                             trace!("struct wrapped nullable pointer type: {}", ty);
                             // only the pointer part of a fat pointer is used for this space optimization
                             let discr_size = self.type_size(ty)?.expect("bad StructWrappedNullablePointer discrfield");
-                            self.memory.write_uint(nonnull, 0, discr_size)?;
+                            self.write_maybe_aligned_mut(!packed, |ectx| ectx.memory.write_uint(nonnull, 0, discr_size))?;
                         }
                     },
 
diff --git a/src/librustc_mir/interpret/terminator/intrinsic.rs b/src/librustc_mir/interpret/terminator/intrinsic.rs
index 2be5b7666f0..5c608bc1630 100644
--- a/src/librustc_mir/interpret/terminator/intrinsic.rs
+++ b/src/librustc_mir/interpret/terminator/intrinsic.rs
@@ -45,7 +45,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
             "arith_offset" => {
                 let offset = self.value_to_primval(arg_vals[1], isize)?.to_i128()? as i64;
-                let ptr = arg_vals[0].into_ptr(&mut self.memory)?;
+                let ptr = arg_vals[0].into_ptr(&self.memory)?;
                 let result_ptr = self.wrapping_pointer_offset(ptr, substs.type_at(0), offset)?;
                 self.write_ptr(dest, result_ptr, dest_ty)?;
             }
@@ -61,7 +61,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             "atomic_load_acq" |
             "volatile_load" => {
                 let ty = substs.type_at(0);
-                let ptr = arg_vals[0].into_ptr(&mut self.memory)?;
+                let ptr = arg_vals[0].into_ptr(&self.memory)?;
                 self.write_value(Value::by_ref(ptr), dest, ty)?;
             }
 
@@ -70,7 +70,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             "atomic_store_rel" |
             "volatile_store" => {
                 let ty = substs.type_at(0);
-                let dest = arg_vals[0].into_ptr(&mut self.memory)?;
+                let dest = arg_vals[0].into_ptr(&self.memory)?;
                 self.write_value_to_ptr(arg_vals[1], dest, ty)?;
             }
 
@@ -80,12 +80,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
             _ if intrinsic_name.starts_with("atomic_xchg") => {
                 let ty = substs.type_at(0);
-                let ptr = arg_vals[0].into_ptr(&mut self.memory)?;
+                let ptr = arg_vals[0].into_ptr(&self.memory)?;
                 let change = self.value_to_primval(arg_vals[1], ty)?;
                 let old = self.read_value(ptr, ty)?;
                 let old = match old {
                     Value::ByVal(val) => val,
-                    Value::ByRef(..) => bug!("just read the value, can't be byref"),
+                    Value::ByRef { .. } => bug!("just read the value, can't be byref"),
                     Value::ByValPair(..) => bug!("atomic_xchg doesn't work with nonprimitives"),
                 };
                 self.write_primval(dest, old, ty)?;
@@ -94,13 +94,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
             _ if intrinsic_name.starts_with("atomic_cxchg") => {
                 let ty = substs.type_at(0);
-                let ptr = arg_vals[0].into_ptr(&mut self.memory)?;
+                let ptr = arg_vals[0].into_ptr(&self.memory)?;
                 let expect_old = self.value_to_primval(arg_vals[1], ty)?;
                 let change = self.value_to_primval(arg_vals[2], ty)?;
                 let old = self.read_value(ptr, ty)?;
                 let old = match old {
                     Value::ByVal(val) => val,
-                    Value::ByRef(..) => bug!("just read the value, can't be byref"),
+                    Value::ByRef { .. } => bug!("just read the value, can't be byref"),
                     Value::ByValPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"),
                 };
                 let (val, _) = self.binary_op(mir::BinOp::Eq, old, ty, expect_old, ty)?;
@@ -115,12 +115,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             "atomic_xadd" | "atomic_xadd_acq" | "atomic_xadd_rel" | "atomic_xadd_acqrel" | "atomic_xadd_relaxed" |
             "atomic_xsub" | "atomic_xsub_acq" | "atomic_xsub_rel" | "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => {
                 let ty = substs.type_at(0);
-                let ptr = arg_vals[0].into_ptr(&mut self.memory)?;
+                let ptr = arg_vals[0].into_ptr(&self.memory)?;
                 let change = self.value_to_primval(arg_vals[1], ty)?;
                 let old = self.read_value(ptr, ty)?;
                 let old = match old {
                     Value::ByVal(val) => val,
-                    Value::ByRef(..) => bug!("just read the value, can't be byref"),
+                    Value::ByRef { .. } => bug!("just read the value, can't be byref"),
                     Value::ByValPair(..) => bug!("atomic_xadd_relaxed doesn't work with nonprimitives"),
                 };
                 self.write_primval(dest, old, ty)?;
@@ -148,8 +148,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                     // TODO: We do not even validate alignment for the 0-bytes case.  libstd relies on this in vec::IntoIter::next.
                     // Also see the write_bytes intrinsic.
                     let elem_align = self.type_align(elem_ty)?;
-                    let src = arg_vals[0].into_ptr(&mut self.memory)?;
-                    let dest = arg_vals[1].into_ptr(&mut self.memory)?;
+                    let src = arg_vals[0].into_ptr(&self.memory)?;
+                    let dest = arg_vals[1].into_ptr(&self.memory)?;
                     self.memory.copy(src, dest, count * elem_size, elem_align, intrinsic_name.ends_with("_nonoverlapping"))?;
                 }
             }
@@ -176,7 +176,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
             "discriminant_value" => {
                 let ty = substs.type_at(0);
-                let adt_ptr = arg_vals[0].into_ptr(&mut self.memory)?.to_ptr()?;
+                let adt_ptr = arg_vals[0].into_ptr(&self.memory)?.to_ptr()?;
                 let discr_val = self.read_discriminant_value(adt_ptr, ty)?;
                 self.write_primval(dest, PrimVal::Bytes(discr_val), dest_ty)?;
             }
@@ -251,10 +251,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                 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 { ptr, aligned } => {
                             // These writes have no alignment restriction anyway.
                             this.memory.write_repeat(ptr, 0, size)?;
-                            Value::ByRef(ptr, aligned)
+                            Value::ByRef { ptr, aligned }
                         },
                         // TODO(solson): Revisit this, it's fishy to check for Undef here.
                         Value::ByVal(PrimVal::Undef) => match this.ty_to_primval_kind(dest_ty) {
@@ -297,7 +297,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
             "move_val_init" => {
                 let ty = substs.type_at(0);
-                let ptr = arg_vals[0].into_ptr(&mut self.memory)?;
+                let ptr = arg_vals[0].into_ptr(&self.memory)?;
                 self.write_value_to_ptr(arg_vals[1], ptr, ty)?;
             }
 
@@ -310,7 +310,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
             "offset" => {
                 let offset = self.value_to_primval(arg_vals[1], isize)?.to_i128()? as i64;
-                let ptr = arg_vals[0].into_ptr(&mut self.memory)?;
+                let ptr = arg_vals[0].into_ptr(&self.memory)?;
                 let result_ptr = self.pointer_offset(ptr, substs.type_at(0), offset)?;
                 self.write_ptr(dest, result_ptr, dest_ty)?;
             }
@@ -399,7 +399,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             "transmute" => {
                 let src_ty = substs.type_at(0);
                 let ptr = self.force_allocation(dest)?.to_ptr()?;
-                self.write_maybe_aligned(/*aligned*/false, |ectx| {
+                self.write_maybe_aligned_mut(/*aligned*/false, |ectx| {
                     ectx.write_value_to_ptr(arg_vals[0], ptr.into(), src_ty)
                 })?;
             }
@@ -442,9 +442,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                 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 { ptr, aligned } => {
                             this.memory.mark_definedness(ptr, size, false)?;
-                            Ok(Value::ByRef(ptr, aligned))
+                            Ok(Value::ByRef { ptr, aligned })
                         },
                         _ => Ok(Value::ByVal(PrimVal::Undef)),
                     }
@@ -464,7 +464,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                 let ty_align = self.type_align(ty)?;
                 let val_byte = self.value_to_primval(arg_vals[1], u8)?.to_u128()? as u8;
                 let size = self.type_size(ty)?.expect("write_bytes() type must be sized");
-                let ptr = arg_vals[0].into_ptr(&mut self.memory)?;
+                let ptr = arg_vals[0].into_ptr(&self.memory)?;
                 let count = self.value_to_primval(arg_vals[2], usize)?.to_u64()?;
                 if count > 0 {
                     // HashMap relies on write_bytes on a NULL ptr with count == 0 to work
@@ -550,7 +550,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                     Ok((size, align.abi()))
                 }
                 ty::TyDynamic(..) => {
-                    let (_, vtable) = value.into_ptr_vtable_pair(&mut self.memory)?;
+                    let (_, vtable) = value.into_ptr_vtable_pair(&self.memory)?;
                     // the second entry in the vtable is the dynamic size of the object.
                     self.read_size_and_align_from_vtable(vtable)
                 }
@@ -558,7 +558,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                 ty::TySlice(_) | ty::TyStr => {
                     let elem_ty = ty.sequence_element_type(self.tcx);
                     let elem_size = self.type_size(elem_ty)?.expect("slice element must be sized") as u64;
-                    let (_, len) = value.into_slice(&mut self.memory)?;
+                    let (_, len) = value.into_slice(&self.memory)?;
                     let align = self.type_align(elem_ty)?;
                     Ok((len * elem_size, align as u64))
                 }
diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs
index 3ee6bab77e0..288409783db 100644
--- a/src/librustc_mir/interpret/terminator/mod.rs
+++ b/src/librustc_mir/interpret/terminator/mod.rs
@@ -7,9 +7,9 @@ use syntax::attr;
 use syntax::abi::Abi;
 
 use error::{EvalError, EvalResult};
-use eval_context::{EvalContext, IntegerExt, StackPopCleanup, is_inhabited, self};
+use eval_context::{EvalContext, IntegerExt, StackPopCleanup, TyAndPacked, is_inhabited, self};
 use lvalue::Lvalue;
-use memory::{MemoryPointer, TlsKey, Kind};
+use memory::{MemoryPointer, TlsKey, Kind, HasMemory};
 use value::{PrimVal, Value};
 use rustc_data_structures::indexed_vec::Idx;
 use const_eval;
@@ -313,10 +313,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                             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 { 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.offset(offset, &self)?, true);
+                                            let arg = Value::ByRef { ptr: ptr.offset(offset, &self)?, aligned: true};
                                             let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?;
                                             trace!("writing arg {:?} to {:?} (type: {})", arg, dest, ty);
                                             self.write_value(arg, dest, ty)?;
@@ -397,12 +397,12 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             },
             ty::InstanceDef::Virtual(_, idx) => {
                 let ptr_size = self.memory.pointer_size();
-                let (_, vtable) = self.eval_operand(&arg_operands[0])?.into_ptr_vtable_pair(&mut self.memory)?;
+                let (_, vtable) = self.eval_operand(&arg_operands[0])?.into_ptr_vtable_pair(&self.memory)?;
                 let fn_ptr = self.memory.read_ptr(vtable.offset(ptr_size * (idx as u64 + 3), &self)?)?;
                 let instance = self.memory.get_fn(fn_ptr.to_ptr()?)?;
                 let mut arg_operands = arg_operands.to_vec();
                 let ty = self.operand_ty(&arg_operands[0]);
-                let ty = self.get_field_ty(ty, 0)?;
+                let ty = self.get_field_ty(ty, 0)?.ty; // TODO: packed flag is ignored
                 match arg_operands[0] {
                     mir::Operand::Consume(ref mut lval) => *lval = lval.clone().field(mir::Field::new(0), ty),
                     _ => bug!("virtual call first arg cannot be a constant"),
@@ -487,12 +487,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             }
 
             StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => {
-                let (offset, ty) = self.nonnull_offset_and_ty(adt_ty, nndiscr, discrfield)?;
-                let nonnull = adt_ptr.offset(offset.bytes(), self)?;
+                let (offset, TyAndPacked { ty, packed }) = self.nonnull_offset_and_ty(adt_ty, nndiscr, discrfield)?;
+                let nonnull = adt_ptr.offset(offset.bytes(), &*self)?;
                 trace!("struct wrapped nullable pointer type: {}", ty);
                 // only the pointer part of a fat pointer is used for this space optimization
                 let discr_size = self.type_size(ty)?.expect("bad StructWrappedNullablePointer discrfield");
-                self.read_nonnull_discriminant_value(nonnull, nndiscr as u128, discr_size)?
+                self.read_maybe_aligned(!packed,
+                    |ectx| ectx.read_nonnull_discriminant_value(nonnull, nndiscr as u128, discr_size))?
             }
 
             // The discriminant_value intrinsic returns 0 for non-sum types.
@@ -576,7 +577,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                 self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?;
             }
             "alloc::heap::::__rust_dealloc" => {
-                let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
+                let ptr = args[0].into_ptr(&self.memory)?.to_ptr()?;
                 let old_size = self.value_to_primval(args[1], usize)?.to_u64()?;
                 let align = self.value_to_primval(args[2], usize)?.to_u64()?;
                 if old_size == 0 {
@@ -588,7 +589,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                 self.memory.deallocate(ptr, Some((old_size, align)), Kind::Rust)?;
             }
             "alloc::heap::::__rust_realloc" => {
-                let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
+                let ptr = args[0].into_ptr(&self.memory)?.to_ptr()?;
                 let old_size = self.value_to_primval(args[1], usize)?.to_u64()?;
                 let old_align = self.value_to_primval(args[2], usize)?.to_u64()?;
                 let new_size = self.value_to_primval(args[3], usize)?.to_u64()?;
@@ -664,7 +665,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             }
 
             "free" => {
-                let ptr = args[0].into_ptr(&mut self.memory)?;
+                let ptr = args[0].into_ptr(&self.memory)?;
                 if !ptr.is_null()? {
                     self.memory.deallocate(ptr.to_ptr()?, None, Kind::C)?;
                 }
@@ -678,8 +679,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             }
 
             "dlsym" => {
-                let _handle = args[0].into_ptr(&mut self.memory)?;
-                let symbol = args[1].into_ptr(&mut self.memory)?.to_ptr()?;
+                let _handle = args[0].into_ptr(&self.memory)?;
+                let symbol = args[1].into_ptr(&self.memory)?.to_ptr()?;
                 let symbol_name = self.memory.read_c_str(symbol)?;
                 let err = format!("bad c unicode symbol: {:?}", symbol_name);
                 let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err);
@@ -690,8 +691,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
                 // fn __rust_maybe_catch_panic(f: fn(*mut u8), data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32
                 // We abort on panic, so not much is going on here, but we still have to call the closure
                 let u8_ptr_ty = self.tcx.mk_mut_ptr(self.tcx.types.u8);
-                let f = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
-                let data = args[1].into_ptr(&mut self.memory)?;
+                let f = args[0].into_ptr(&self.memory)?.to_ptr()?;
+                let data = args[1].into_ptr(&self.memory)?;
                 let f_instance = self.memory.get_fn(f)?;
                 self.write_null(dest, dest_ty)?;
 
@@ -722,8 +723,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             }
 
             "memcmp" => {
-                let left = args[0].into_ptr(&mut self.memory)?;
-                let right = args[1].into_ptr(&mut self.memory)?;
+                let left = args[0].into_ptr(&self.memory)?;
+                let right = args[1].into_ptr(&self.memory)?;
                 let n = self.value_to_primval(args[2], usize)?.to_u64()?;
 
                 let result = {
@@ -742,7 +743,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             }
 
             "memrchr" => {
-                let ptr = args[0].into_ptr(&mut self.memory)?;
+                let ptr = args[0].into_ptr(&self.memory)?;
                 let val = self.value_to_primval(args[1], usize)?.to_u64()? as u8;
                 let num = self.value_to_primval(args[2], usize)?.to_u64()?;
                 if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().rev().position(|&c| c == val) {
@@ -754,7 +755,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             }
 
             "memchr" => {
-                let ptr = args[0].into_ptr(&mut self.memory)?;
+                let ptr = args[0].into_ptr(&self.memory)?;
                 let val = self.value_to_primval(args[1], usize)?.to_u64()? as u8;
                 let num = self.value_to_primval(args[2], usize)?.to_u64()?;
                 if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().position(|&c| c == val) {
@@ -767,7 +768,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
             "getenv" => {
                 let result = {
-                    let name_ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
+                    let name_ptr = args[0].into_ptr(&self.memory)?.to_ptr()?;
                     let name = self.memory.read_c_str(name_ptr)?;
                     match self.env_vars.get(name) {
                         Some(&var) => PrimVal::Ptr(var),
@@ -780,7 +781,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             "unsetenv" => {
                 let mut success = None;
                 {
-                    let name_ptr = args[0].into_ptr(&mut self.memory)?;
+                    let name_ptr = args[0].into_ptr(&self.memory)?;
                     if !name_ptr.is_null()? {
                         let name = self.memory.read_c_str(name_ptr.to_ptr()?)?;
                         if !name.is_empty() && !name.contains(&b'=') {
@@ -801,8 +802,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             "setenv" => {
                 let mut new = None;
                 {
-                    let name_ptr = args[0].into_ptr(&mut self.memory)?;
-                    let value_ptr = args[1].into_ptr(&mut self.memory)?.to_ptr()?;
+                    let name_ptr = args[0].into_ptr(&self.memory)?;
+                    let value_ptr = args[1].into_ptr(&self.memory)?.to_ptr()?;
                     let value = self.memory.read_c_str(value_ptr)?;
                     if !name_ptr.is_null()? {
                         let name = self.memory.read_c_str(name_ptr.to_ptr()?)?;
@@ -828,7 +829,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
             "write" => {
                 let fd = self.value_to_primval(args[0], usize)?.to_u64()?;
-                let buf = args[1].into_ptr(&mut self.memory)?;
+                let buf = args[1].into_ptr(&self.memory)?;
                 let n = self.value_to_primval(args[2], usize)?.to_u64()?;
                 trace!("Called write({:?}, {:?}, {:?})", fd, buf, n);
                 let result = if fd == 1 || fd == 2 { // stdout/stderr
@@ -845,7 +846,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             }
 
             "strlen" => {
-                let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?;
+                let ptr = args[0].into_ptr(&self.memory)?.to_ptr()?;
                 let n = self.memory.read_c_str(ptr)?.len();
                 self.write_primval(dest, PrimVal::Bytes(n as u128), dest_ty)?;
             }
@@ -888,10 +889,10 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
 
             // Hook pthread calls that go to the thread-local storage memory subsystem
             "pthread_key_create" => {
-                let key_ptr = args[0].into_ptr(&mut self.memory)?;
+                let key_ptr = args[0].into_ptr(&self.memory)?;
 
                 // Extract the function type out of the signature (that seems easier than constructing it ourselves...)
-                let dtor = match args[1].into_ptr(&mut self.memory)?.into_inner_primval() {
+                let dtor = match args[1].into_ptr(&self.memory)?.into_inner_primval() {
                     PrimVal::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?),
                     PrimVal::Bytes(0) => None,
                     PrimVal::Bytes(_) => return Err(EvalError::ReadBytesAsPointer),
@@ -933,7 +934,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
             "pthread_setspecific" => {
                 // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t
                 let key = self.value_to_primval(args[0], usize)?.to_u64()? as TlsKey;
-                let new_ptr = args[1].into_ptr(&mut self.memory)?;
+                let new_ptr = args[1].into_ptr(&self.memory)?;
                 self.memory.store_tls(key, new_ptr)?;
                 
                 // Return success (0)
diff --git a/src/librustc_mir/interpret/validation.rs b/src/librustc_mir/interpret/validation.rs
index 4c9e239299d..8c3cc185250 100644
--- a/src/librustc_mir/interpret/validation.rs
+++ b/src/librustc_mir/interpret/validation.rs
@@ -151,7 +151,7 @@ std::sync::atomic::AtomicBool::get_mut$|\
     fn validate_ptr(&mut self, val: Value, pointee_ty: Ty<'tcx>, re: Option<CodeExtent>, mutbl: Mutability, mode: ValidationMode) -> EvalResult<'tcx> {
         // Check alignment and non-NULLness
         let (_, align) = self.size_and_align_of_dst(pointee_ty, val)?;
-        let ptr = val.into_ptr(&mut self.memory)?;
+        let ptr = val.into_ptr(&self.memory)?;
         self.memory.check_align(ptr, align)?;
 
         // Recurse
@@ -309,7 +309,7 @@ std::sync::atomic::AtomicBool::get_mut$|\
                 self.validate_ptr(val, query.ty.boxed_ty(), query.re, query.mutbl, mode)
             }
             TyFnPtr(_sig) => {
-                let ptr = self.read_lvalue(query.lval)?.into_ptr(&mut self.memory)?.to_ptr()?;
+                let ptr = self.read_lvalue(query.lval)?.into_ptr(&self.memory)?.to_ptr()?;
                 self.memory.get_fn(ptr)?;
                 // TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?).
                 Ok(())
diff --git a/src/librustc_mir/interpret/value.rs b/src/librustc_mir/interpret/value.rs
index a4115ddb5cc..87b3d9f383c 100644
--- a/src/librustc_mir/interpret/value.rs
+++ b/src/librustc_mir/interpret/value.rs
@@ -32,7 +32,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(Pointer, bool),
+    ByRef { ptr: Pointer, aligned: bool},
     ByVal(PrimVal),
     ByValPair(PrimVal, PrimVal),
 }
@@ -162,15 +162,15 @@ pub enum PrimValKind {
 impl<'a, 'tcx: 'a> Value {
     #[inline]
     pub(super) fn by_ref(ptr: Pointer) -> Self {
-        Value::ByRef(ptr, true)
+        Value::ByRef { ptr, aligned: true }
     }
 
     /// Convert the value into a pointer (or a pointer-sized integer).  If the value is a ByRef,
     /// this may have to perform a load.
-    pub(super) fn into_ptr(&self, mem: &mut Memory<'a, 'tcx>) -> EvalResult<'tcx, Pointer> {
+    pub(super) fn into_ptr(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, Pointer> {
         use self::Value::*;
         match *self {
-            ByRef(ptr, aligned) => {
+            ByRef { ptr, aligned } => {
                 mem.read_maybe_aligned(aligned, |mem| mem.read_ptr(ptr.to_ptr()?) )
             },
             ByVal(ptr) | ByValPair(ptr, _) => Ok(ptr.into()),
@@ -179,11 +179,11 @@ impl<'a, 'tcx: 'a> Value {
 
     pub(super) fn into_ptr_vtable_pair(
         &self,
-        mem: &mut Memory<'a, 'tcx>
+        mem: &Memory<'a, 'tcx>
     ) -> EvalResult<'tcx, (Pointer, MemoryPointer)> {
         use self::Value::*;
         match *self {
-            ByRef(ref_ptr, aligned) => {
+            ByRef { 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()?)?;
@@ -197,11 +197,11 @@ impl<'a, 'tcx: 'a> Value {
         }
     }
 
-    pub(super) fn into_slice(&self, mem: &mut Memory<'a, 'tcx>) -> EvalResult<'tcx, (Pointer, u64)> {
+    pub(super) fn into_slice(&self, mem: &Memory<'a, 'tcx>) -> EvalResult<'tcx, (Pointer, u64)> {
         use self::Value::*;
         match *self {
-            ByRef(ref_ptr, aligned) => {
-                mem.write_maybe_aligned(aligned, |mem| {
+            ByRef { 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()?)?;
                     Ok((ptr, len))