about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/mir/interpret/mod.rs7
-rw-r--r--src/librustc/mir/interpret/value.rs97
-rw-r--r--src/librustc_mir/interpret/cast.rs102
-rw-r--r--src/librustc_mir/interpret/eval_context.rs3
-rw-r--r--src/librustc_mir/interpret/intrinsics.rs17
-rw-r--r--src/librustc_mir/interpret/memory.rs34
-rw-r--r--src/librustc_mir/interpret/operand.rs5
-rw-r--r--src/librustc_mir/interpret/operator.rs42
-rw-r--r--src/librustc_mir/interpret/place.rs30
-rw-r--r--src/librustc_mir/interpret/step.rs23
-rw-r--r--src/librustc_mir/interpret/terminator.rs9
-rw-r--r--src/librustc_mir/interpret/traits.rs17
-rw-r--r--src/librustc_mir/interpret/validity.rs5
13 files changed, 210 insertions, 181 deletions
diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs
index 147f9ccad7c..da5216bd1be 100644
--- a/src/librustc/mir/interpret/mod.rs
+++ b/src/librustc/mir/interpret/mod.rs
@@ -85,9 +85,14 @@ pub struct GlobalId<'tcx> {
 pub trait PointerArithmetic: layout::HasDataLayout {
     // These are not supposed to be overridden.
 
+    #[inline(always)]
+    fn pointer_size(self) -> Size {
+        self.data_layout().pointer_size
+    }
+
     //// Trunace the given value to the pointer size; also return whether there was an overflow
     fn truncate_to_ptr(self, val: u128) -> (u64, bool) {
-        let max_ptr_plus_1 = 1u128 << self.data_layout().pointer_size.bits();
+        let max_ptr_plus_1 = 1u128 << self.pointer_size().bits();
         ((val % max_ptr_plus_1) as u64, val >= max_ptr_plus_1)
     }
 
diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs
index d793bb1cc63..11a4f8b884e 100644
--- a/src/librustc/mir/interpret/value.rs
+++ b/src/librustc/mir/interpret/value.rs
@@ -14,7 +14,7 @@ use ty::layout::{HasDataLayout, Size};
 use ty::subst::Substs;
 use hir::def_id::DefId;
 
-use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend};
+use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend, truncate};
 
 /// Represents a constant value in Rust. Scalar and ScalarPair are optimizations which
 /// matches the LocalValue optimizations for easy conversions between Value and ConstValue.
@@ -58,6 +58,7 @@ impl<'tcx> ConstValue<'tcx> {
         self.try_to_scalar()?.to_ptr().ok()
     }
 
+    #[inline]
     pub fn new_slice(
         val: Scalar,
         len: u64,
@@ -69,12 +70,14 @@ impl<'tcx> ConstValue<'tcx> {
         }.into())
     }
 
+    #[inline]
     pub fn new_dyn_trait(val: Scalar, vtable: Pointer) -> Self {
         ConstValue::ScalarPair(val, Scalar::Ptr(vtable).into())
     }
 }
 
 impl<'tcx> Scalar {
+    #[inline]
     pub fn ptr_null(cx: impl HasDataLayout) -> Self {
         Scalar::Bits {
             bits: 0,
@@ -82,10 +85,12 @@ impl<'tcx> Scalar {
         }
     }
 
+    #[inline]
     pub fn zst() -> Self {
         Scalar::Bits { bits: 0, size: 0 }
     }
 
+    #[inline]
     pub fn ptr_signed_offset(self, i: i64, cx: impl HasDataLayout) -> EvalResult<'tcx, Self> {
         let layout = cx.data_layout();
         match self {
@@ -100,6 +105,7 @@ impl<'tcx> Scalar {
         }
     }
 
+    #[inline]
     pub fn ptr_offset(self, i: Size, cx: impl HasDataLayout) -> EvalResult<'tcx, Self> {
         let layout = cx.data_layout();
         match self {
@@ -114,6 +120,7 @@ impl<'tcx> Scalar {
         }
     }
 
+    #[inline]
     pub fn ptr_wrapping_signed_offset(self, i: i64, cx: impl HasDataLayout) -> Self {
         let layout = cx.data_layout();
         match self {
@@ -128,6 +135,7 @@ impl<'tcx> Scalar {
         }
     }
 
+    #[inline]
     pub fn is_null_ptr(self, cx: impl HasDataLayout) -> bool {
         match self {
             Scalar::Bits { bits, size } =>  {
@@ -138,14 +146,53 @@ impl<'tcx> Scalar {
         }
     }
 
+    #[inline]
+    pub fn is_null(self) -> bool {
+        match self {
+            Scalar::Bits { bits, .. } => bits == 0,
+            Scalar::Ptr(_) => false
+        }
+    }
+
+    #[inline]
     pub fn from_bool(b: bool) -> Self {
         Scalar::Bits { bits: b as u128, size: 1 }
     }
 
+    #[inline]
     pub fn from_char(c: char) -> Self {
         Scalar::Bits { bits: c as u128, size: 4 }
     }
 
+    #[inline]
+    pub fn from_uint(i: impl Into<u128>, size: Size) -> Self {
+        let i = i.into();
+        debug_assert_eq!(truncate(i, size), i,
+                    "Unsigned value {} does not fit in {} bits", i, size.bits());
+        Scalar::Bits { bits: i, size: size.bytes() as u8 }
+    }
+
+    #[inline]
+    pub fn from_int(i: impl Into<i128>, size: Size) -> Self {
+        let i = i.into();
+        // `into` performed sign extension, we have to truncate
+        let truncated = truncate(i as u128, size);
+        debug_assert_eq!(sign_extend(truncated, size) as i128, i,
+                    "Signed value {} does not fit in {} bits", i, size.bits());
+        Scalar::Bits { bits: truncated, size: size.bytes() as u8 }
+    }
+
+    #[inline]
+    pub fn from_f32(f: f32) -> Self {
+        Scalar::Bits { bits: f.to_bits() as u128, size: 4 }
+    }
+
+    #[inline]
+    pub fn from_f64(f: f64) -> Self {
+        Scalar::Bits { bits: f.to_bits() as u128, size: 8 }
+    }
+
+    #[inline]
     pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> {
         match self {
             Scalar::Bits { bits, size } => {
@@ -157,6 +204,7 @@ impl<'tcx> Scalar {
         }
     }
 
+    #[inline]
     pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
         match self {
             Scalar::Bits { bits: 0, .. } => err!(InvalidNullPointerUsage),
@@ -165,6 +213,7 @@ impl<'tcx> Scalar {
         }
     }
 
+    #[inline]
     pub fn is_bits(self) -> bool {
         match self {
             Scalar::Bits { .. } => true,
@@ -172,6 +221,7 @@ impl<'tcx> Scalar {
         }
     }
 
+    #[inline]
     pub fn is_ptr(self) -> bool {
         match self {
             Scalar::Ptr(_) => true,
@@ -209,6 +259,13 @@ impl<'tcx> Scalar {
         Ok(b as u32)
     }
 
+    pub fn to_u64(self) -> EvalResult<'static, u64> {
+        let sz = Size::from_bits(64);
+        let b = self.to_bits(sz)?;
+        assert_eq!(b as u64 as u128, b);
+        Ok(b as u64)
+    }
+
     pub fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64> {
         let b = self.to_bits(cx.data_layout().pointer_size)?;
         assert_eq!(b as u64 as u128, b);
@@ -231,12 +288,30 @@ impl<'tcx> Scalar {
         Ok(b as i32)
     }
 
+    pub fn to_i64(self) -> EvalResult<'static, i64> {
+        let sz = Size::from_bits(64);
+        let b = self.to_bits(sz)?;
+        let b = sign_extend(b, sz) as i128;
+        assert_eq!(b as i64 as i128, b);
+        Ok(b as i64)
+    }
+
     pub fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64> {
         let b = self.to_bits(cx.data_layout().pointer_size)?;
         let b = sign_extend(b, cx.data_layout().pointer_size) as i128;
         assert_eq!(b as i64 as i128, b);
         Ok(b as i64)
     }
+
+    #[inline]
+    pub fn to_f32(self) -> EvalResult<'static, f32> {
+        Ok(f32::from_bits(self.to_u32()?))
+    }
+
+    #[inline]
+    pub fn to_f64(self) -> EvalResult<'static, f64> {
+        Ok(f64::from_bits(self.to_u64()?))
+    }
 }
 
 impl From<Pointer> for Scalar {
@@ -309,6 +384,16 @@ impl<'tcx> ScalarMaybeUndef {
     }
 
     #[inline(always)]
+    pub fn to_f32(self) -> EvalResult<'tcx, f32> {
+        self.not_undef()?.to_f32()
+    }
+
+    #[inline(always)]
+    pub fn to_f64(self) -> EvalResult<'tcx, f64> {
+        self.not_undef()?.to_f64()
+    }
+
+    #[inline(always)]
     pub fn to_u8(self) -> EvalResult<'tcx, u8> {
         self.not_undef()?.to_u8()
     }
@@ -319,6 +404,11 @@ impl<'tcx> ScalarMaybeUndef {
     }
 
     #[inline(always)]
+    pub fn to_u64(self) -> EvalResult<'tcx, u64> {
+        self.not_undef()?.to_u64()
+    }
+
+    #[inline(always)]
     pub fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'tcx, u64> {
         self.not_undef()?.to_usize(cx)
     }
@@ -334,6 +424,11 @@ impl<'tcx> ScalarMaybeUndef {
     }
 
     #[inline(always)]
+    pub fn to_i64(self) -> EvalResult<'tcx, i64> {
+        self.not_undef()?.to_i64()
+    }
+
+    #[inline(always)]
     pub fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'tcx, i64> {
         self.not_undef()?.to_isize(cx)
     }
diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs
index d0d1c5d6610..9bbaa0e7ef6 100644
--- a/src/librustc_mir/interpret/cast.rs
+++ b/src/librustc_mir/interpret/cast.rs
@@ -14,8 +14,7 @@ use syntax::ast::{FloatTy, IntTy, UintTy};
 
 use rustc_apfloat::ieee::{Single, Double};
 use rustc::mir::interpret::{
-    Scalar, EvalResult, Pointer, PointerArithmetic, EvalErrorKind,
-    truncate, sign_extend
+    Scalar, EvalResult, Pointer, PointerArithmetic, EvalErrorKind, truncate
 };
 use rustc::mir::CastKind;
 use rustc_apfloat::Float;
@@ -70,10 +69,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                                     .discriminant_for_variant(*self.tcx, index)
                                     .val;
                                 return self.write_scalar(
-                                    Scalar::Bits {
-                                        bits: discr_val,
-                                        size: dst_layout.size.bytes() as u8,
-                                    },
+                                    Scalar::from_uint(discr_val, dst_layout.size),
                                     dest);
                             }
                         }
@@ -198,41 +194,39 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         match dest_layout.ty.sty {
             Int(_) | Uint(_) => {
                 let v = self.truncate(v, dest_layout);
-                Ok(Scalar::Bits {
-                    bits: v,
-                    size: dest_layout.size.bytes() as u8,
-                })
+                Ok(Scalar::from_uint(v, dest_layout.size))
             }
 
-            Float(FloatTy::F32) if signed => Ok(Scalar::Bits {
-                bits: Single::from_i128(v as i128).value.to_bits(),
-                size: 4,
-            }),
-            Float(FloatTy::F64) if signed => Ok(Scalar::Bits {
-                bits: Double::from_i128(v as i128).value.to_bits(),
-                size: 8,
-            }),
-            Float(FloatTy::F32) => Ok(Scalar::Bits {
-                bits: Single::from_u128(v).value.to_bits(),
-                size: 4,
-            }),
-            Float(FloatTy::F64) => Ok(Scalar::Bits {
-                bits: Double::from_u128(v).value.to_bits(),
-                size: 8,
-            }),
+            Float(FloatTy::F32) if signed => Ok(Scalar::from_uint(
+                Single::from_i128(v as i128).value.to_bits(),
+                Size::from_bits(32)
+            )),
+            Float(FloatTy::F64) if signed => Ok(Scalar::from_uint(
+                Double::from_i128(v as i128).value.to_bits(),
+                Size::from_bits(64)
+            )),
+            Float(FloatTy::F32) => Ok(Scalar::from_uint(
+                Single::from_u128(v).value.to_bits(),
+                Size::from_bits(32)
+            )),
+            Float(FloatTy::F64) => Ok(Scalar::from_uint(
+                Double::from_u128(v).value.to_bits(),
+                Size::from_bits(64)
+            )),
 
             Char => {
-                assert_eq!(v as u8 as u128, v);
-                Ok(Scalar::Bits { bits: v, size: 4 })
+                // `u8` to `char` cast
+                debug_assert_eq!(v as u8 as u128, v);
+                Ok(Scalar::from_uint(v, Size::from_bytes(4)))
             },
 
             // No alignment check needed for raw pointers.
             // But we have to truncate to target ptr size.
             RawPtr(_) => {
-                Ok(Scalar::Bits {
-                    bits: self.memory.truncate_to_ptr(v).0 as u128,
-                    size: self.memory.pointer_size().bytes() as u8,
-                })
+                Ok(Scalar::from_uint(
+                    self.truncate_to_ptr(v).0,
+                    self.pointer_size(),
+                ))
             },
 
             // Casts to bool are not permitted by rustc, no need to handle them here.
@@ -251,56 +245,40 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         match dest_ty.sty {
             // float -> uint
             Uint(t) => {
-                let width = t.bit_width().unwrap_or(self.memory.pointer_size().bits() as usize);
+                let width = t.bit_width().unwrap_or(self.pointer_size().bits() as usize);
                 let v = match fty {
                     FloatTy::F32 => Single::from_bits(bits).to_u128(width).value,
                     FloatTy::F64 => Double::from_bits(bits).to_u128(width).value,
                 };
                 // This should already fit the bit width
-                Ok(Scalar::Bits {
-                    bits: v,
-                    size: (width / 8) as u8,
-                })
+                Ok(Scalar::from_uint(v, Size::from_bits(width as u64)))
             },
             // float -> int
             Int(t) => {
-                let width = t.bit_width().unwrap_or(self.memory.pointer_size().bits() as usize);
+                let width = t.bit_width().unwrap_or(self.pointer_size().bits() as usize);
                 let v = match fty {
                     FloatTy::F32 => Single::from_bits(bits).to_i128(width).value,
                     FloatTy::F64 => Double::from_bits(bits).to_i128(width).value,
                 };
-                // We got an i128, but we may need something smaller. We have to truncate ourselves.
-                let truncated = truncate(v as u128, Size::from_bits(width as u64));
-                assert_eq!(sign_extend(truncated, Size::from_bits(width as u64)) as i128, v,
-                    "truncating and extending changed the value?!?");
-                Ok(Scalar::Bits {
-                    bits: truncated,
-                    size: (width / 8) as u8,
-                })
+                Ok(Scalar::from_int(v, Size::from_bits(width as u64)))
             },
             // f64 -> f32
             Float(FloatTy::F32) if fty == FloatTy::F64 => {
-                Ok(Scalar::Bits {
-                    bits: Single::to_bits(Double::from_bits(bits).convert(&mut false).value),
-                    size: 4,
-                })
+                Ok(Scalar::from_uint(
+                    Single::to_bits(Double::from_bits(bits).convert(&mut false).value),
+                    Size::from_bits(32),
+                ))
             },
             // f32 -> f64
             Float(FloatTy::F64) if fty == FloatTy::F32 => {
-                Ok(Scalar::Bits {
-                    bits: Double::to_bits(Single::from_bits(bits).convert(&mut false).value),
-                    size: 8,
-                })
+                Ok(Scalar::from_uint(
+                    Double::to_bits(Single::from_bits(bits).convert(&mut false).value),
+                    Size::from_bits(64),
+                ))
             },
             // identity cast
-            Float(FloatTy:: F64) => Ok(Scalar::Bits {
-                bits,
-                size: 8,
-            }),
-            Float(FloatTy:: F32) => Ok(Scalar::Bits {
-                bits,
-                size: 4,
-            }),
+            Float(FloatTy:: F64) => Ok(Scalar::from_uint(bits, Size::from_bits(64))),
+            Float(FloatTy:: F32) => Ok(Scalar::from_uint(bits, Size::from_bits(32))),
             _ => err!(Unimplemented(format!("float to {:?} cast", dest_ty))),
         }
     }
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 455c3fc281a..6e144ba7ed2 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -270,7 +270,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for &'a EvalContext<'
 }
 
 impl<'c, 'b, 'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout
-    for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M> {
+    for &'c &'b mut EvalContext<'a, 'mir, 'tcx, M>
+{
     #[inline]
     fn data_layout(&self) -> &layout::TargetDataLayout {
         &self.tcx.data_layout
diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs
index 35e3253ca7f..db27df3723c 100644
--- a/src/librustc_mir/interpret/intrinsics.rs
+++ b/src/librustc_mir/interpret/intrinsics.rs
@@ -41,7 +41,7 @@ fn numeric_intrinsic<'tcx>(
         "bswap" => (bits << extra).swap_bytes(),
         _ => bug!("not a numeric intrinsic: {}", name),
     };
-    Ok(Scalar::Bits { bits: bits_out, size: size.bytes() as u8 })
+    Ok(Scalar::from_uint(bits_out, size))
 }
 
 impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
@@ -59,30 +59,21 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             "min_align_of" => {
                 let elem_ty = substs.type_at(0);
                 let elem_align = self.layout_of(elem_ty)?.align.abi();
-                let align_val = Scalar::Bits {
-                    bits: elem_align as u128,
-                    size: dest.layout.size.bytes() as u8,
-                };
+                let align_val = Scalar::from_uint(elem_align, dest.layout.size);
                 self.write_scalar(align_val, dest)?;
             }
 
             "size_of" => {
                 let ty = substs.type_at(0);
                 let size = self.layout_of(ty)?.size.bytes() as u128;
-                let size_val = Scalar::Bits {
-                    bits: size,
-                    size: dest.layout.size.bytes() as u8,
-                };
+                let size_val = Scalar::from_uint(size, dest.layout.size);
                 self.write_scalar(size_val, dest)?;
             }
 
             "type_id" => {
                 let ty = substs.type_at(0);
                 let type_id = self.tcx.type_id_hash(ty) as u128;
-                let id_val = Scalar::Bits {
-                    bits: type_id,
-                    size: dest.layout.size.bytes() as u8,
-                };
+                let id_val = Scalar::from_uint(type_id, dest.layout.size);
                 self.write_scalar(id_val, dest)?;
             }
             "ctpop" | "cttz" | "cttz_nonzero" | "ctlz" | "ctlz_nonzero" | "bswap" => {
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index 240f977a5a0..4063447fbb1 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -23,7 +23,8 @@ use std::ptr;
 use rustc::ty::{self, Instance, query::TyCtxtAt};
 use rustc::ty::layout::{self, Align, TargetDataLayout, Size, HasDataLayout};
 use rustc::mir::interpret::{Pointer, AllocId, Allocation, ScalarMaybeUndef, GlobalId,
-                            EvalResult, Scalar, EvalErrorKind, AllocType, truncate};
+                            EvalResult, Scalar, EvalErrorKind, AllocType, PointerArithmetic,
+                            truncate};
 pub use rustc::mir::interpret::{write_target_uint, read_target_uint};
 use rustc_data_structures::fx::{FxHashSet, FxHashMap, FxHasher};
 
@@ -60,6 +61,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for &'a Memory<'a, 'm
         &self.tcx.data_layout
     }
 }
+impl<'a, 'b, 'c, 'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout
+    for &'b &'c mut Memory<'a, 'mir, 'tcx, M>
+{
+    #[inline]
+    fn data_layout(&self) -> &TargetDataLayout {
+        &self.tcx.data_layout
+    }
+}
 
 impl<'a, 'mir, 'tcx, M> Eq for Memory<'a, 'mir, 'tcx, M>
     where M: Machine<'mir, 'tcx>,
@@ -277,14 +286,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         Ok(())
     }
 
-    pub fn pointer_size(&self) -> Size {
-        self.tcx.data_layout.pointer_size
-    }
-
-    pub fn endianness(&self) -> layout::Endian {
-        self.tcx.data_layout.endian
-    }
-
     /// Check that the pointer is aligned AND non-NULL. This supports scalars
     /// for the benefit of other parts of miri that need to check alignment even for ZST.
     pub fn check_align(&self, ptr: Scalar, required_align: Align) -> EvalResult<'tcx> {
@@ -773,7 +774,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
     ) -> EvalResult<'tcx, ScalarMaybeUndef> {
         // Make sure we don't read part of a pointer as a pointer
         self.check_relocation_edges(ptr, size)?;
-        let endianness = self.endianness();
         // get_bytes_unchecked tests alignment
         let bytes = self.get_bytes_unchecked(ptr, size, ptr_align.min(self.int_align(size)))?;
         // Undef check happens *after* we established that the alignment is correct.
@@ -784,7 +784,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
             return Ok(ScalarMaybeUndef::Undef);
         }
         // Now we do the actual reading
-        let bits = read_target_uint(endianness, bytes).unwrap();
+        let bits = read_target_uint(self.tcx.data_layout.endian, bytes).unwrap();
         // See if we got a pointer
         if size != self.pointer_size() {
             if self.relocations(ptr, size)?.len() != 0 {
@@ -801,10 +801,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
             }
         }
         // We don't. Just return the bits.
-        Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
-            bits,
-            size: size.bytes() as u8,
-        }))
+        Ok(ScalarMaybeUndef::Scalar(Scalar::from_uint(bits, size)))
     }
 
     pub fn read_ptr_sized(&self, ptr: Pointer, ptr_align: Align)
@@ -820,8 +817,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         val: ScalarMaybeUndef,
         type_size: Size,
     ) -> EvalResult<'tcx> {
-        let endianness = self.endianness();
-
         let val = match val {
             ScalarMaybeUndef::Scalar(scalar) => scalar,
             ScalarMaybeUndef::Undef => return self.mark_definedness(ptr, type_size, false),
@@ -835,7 +830,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
 
             Scalar::Bits { bits, size } => {
                 assert_eq!(size as u64, type_size.bytes());
-                assert_eq!(truncate(bits, Size::from_bytes(size.into())), bits,
+                debug_assert_eq!(truncate(bits, Size::from_bytes(size.into())), bits,
                     "Unexpected value of size {} when writing to memory", size);
                 bits
             },
@@ -843,8 +838,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
 
         {
             // get_bytes_mut checks alignment
+            let endian = self.tcx.data_layout.endian;
             let dst = self.get_bytes_mut(ptr, type_size, ptr_align)?;
-            write_target_uint(endianness, dst, bytes).unwrap();
+            write_target_uint(endian, dst, bytes).unwrap();
         }
 
         // See if we have to also write a relocation
diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs
index 9681b705d7e..b2a668b961f 100644
--- a/src/librustc_mir/interpret/operand.rs
+++ b/src/librustc_mir/interpret/operand.rs
@@ -42,10 +42,7 @@ impl<'tcx> Value {
         len: u64,
         cx: impl HasDataLayout
     ) -> Self {
-        Value::ScalarPair(val.into(), Scalar::Bits {
-            bits: len as u128,
-            size: cx.data_layout().pointer_size.bytes() as u8,
-        }.into())
+        Value::ScalarPair(val.into(), Scalar::from_uint(len, cx.data_layout().pointer_size).into())
     }
 
     pub fn new_dyn_trait(val: Scalar, vtable: Pointer) -> Self {
diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs
index 13ed527e349..4f4f00e320a 100644
--- a/src/librustc_mir/interpret/operator.rs
+++ b/src/librustc_mir/interpret/operator.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use rustc::mir;
-use rustc::ty::{self, layout::TyLayout};
+use rustc::ty::{self, layout::{Size, TyLayout}};
 use syntax::ast::FloatTy;
 use rustc_apfloat::ieee::{Double, Single};
 use rustc_apfloat::Float;
@@ -105,10 +105,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             ($ty:path, $size:expr) => {{
                 let l = <$ty>::from_bits(l);
                 let r = <$ty>::from_bits(r);
-                let bitify = |res: ::rustc_apfloat::StatusAnd<$ty>| Scalar::Bits {
-                    bits: res.value.to_bits(),
-                    size: $size,
-                };
+                let bitify = |res: ::rustc_apfloat::StatusAnd<$ty>|
+                    Scalar::from_uint(res.value.to_bits(), Size::from_bytes($size));
                 let val = match bin_op {
                     Eq => Scalar::from_bool(l == r),
                     Ne => Scalar::from_bool(l != r),
@@ -169,10 +167,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 }
             };
             let truncated = self.truncate(result, left_layout);
-            return Ok((Scalar::Bits {
-                bits: truncated,
-                size: size.bytes() as u8,
-            }, oflo));
+            return Ok((Scalar::from_uint(truncated, size), oflo));
         }
 
         // For the remaining ops, the types must be the same on both sides
@@ -220,7 +215,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                     Rem | Div => {
                         // int_min / -1
                         if r == -1 && l == (1 << (size.bits() - 1)) {
-                            return Ok((Scalar::Bits { bits: l, size: size.bytes() as u8 }, true));
+                            return Ok((Scalar::from_uint(l, size), true));
                         }
                     },
                     _ => {},
@@ -232,16 +227,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                     let max = 1 << (size.bits() - 1);
                     oflo = result >= max || result < -max;
                 }
+                // this may be out-of-bounds for the result type, so we have to truncate ourselves
                 let result = result as u128;
                 let truncated = self.truncate(result, left_layout);
-                return Ok((Scalar::Bits {
-                    bits: truncated,
-                    size: size.bytes() as u8,
-                }, oflo));
+                return Ok((Scalar::from_uint(truncated, size), oflo));
             }
         }
 
-        let size = left_layout.size.bytes() as u8;
+        let size = left_layout.size;
 
         // only ints left
         let val = match bin_op {
@@ -253,11 +246,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             Gt => Scalar::from_bool(l > r),
             Ge => Scalar::from_bool(l >= r),
 
-            BitOr => Scalar::Bits { bits: l | r, size },
-            BitAnd => Scalar::Bits { bits: l & r, size },
-            BitXor => Scalar::Bits { bits: l ^ r, size },
+            BitOr => Scalar::from_uint(l | r, size),
+            BitAnd => Scalar::from_uint(l & r, size),
+            BitXor => Scalar::from_uint(l ^ r, size),
 
             Add | Sub | Mul | Rem | Div => {
+                debug_assert!(!left_layout.abi.is_signed());
                 let op: fn(u128, u128) -> (u128, bool) = match bin_op {
                     Add => u128::overflowing_add,
                     Sub => u128::overflowing_sub,
@@ -270,10 +264,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 };
                 let (result, oflo) = op(l, r);
                 let truncated = self.truncate(result, left_layout);
-                return Ok((Scalar::Bits {
-                    bits: truncated,
-                    size,
-                }, oflo || truncated != result));
+                return Ok((Scalar::from_uint(truncated, size), oflo || truncated != result));
             }
 
             _ => {
@@ -373,7 +364,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                     (Neg, FloatTy::F64) => Double::to_bits(-Double::from_bits(val)),
                     _ => bug!("Invalid float op {:?}", un_op)
                 };
-                Ok(Scalar::Bits { bits: res, size: layout.size.bytes() as u8 })
+                Ok(Scalar::from_uint(res, layout.size))
             }
             _ => {
                 assert!(layout.ty.is_integral());
@@ -386,10 +377,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                     }
                 };
                 // res needs tuncating
-                Ok(Scalar::Bits {
-                    bits: self.truncate(res, layout),
-                    size: layout.size.bytes() as u8,
-                })
+                Ok(Scalar::from_uint(self.truncate(res, layout), layout.size))
             }
         }
     }
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 0a6fef30084..5bf6b2b46b7 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -20,7 +20,7 @@ use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout};
 use rustc_data_structures::indexed_vec::Idx;
 
 use rustc::mir::interpret::{
-    GlobalId, Scalar, EvalResult, Pointer, ScalarMaybeUndef
+    GlobalId, Scalar, EvalResult, Pointer, ScalarMaybeUndef, PointerArithmetic
 };
 use super::{EvalContext, Machine, Value, ValTy, Operand, OpTy, MemoryKind};
 
@@ -344,10 +344,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             ty::Array(inner, _) =>
                 (None, self.tcx.mk_array(inner, inner_len)),
             ty::Slice(..) => {
-                let len = Scalar::Bits {
-                    bits: inner_len.into(),
-                    size: self.memory.pointer_size().bytes() as u8
-                };
+                let len = Scalar::from_uint(inner_len, self.pointer_size());
                 (Some(len), base.layout.ty)
             }
             _ =>
@@ -716,10 +713,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 let discr_val = (discr_val << shift) >> shift;
 
                 let discr_dest = self.place_field(dest, 0)?;
-                self.write_scalar(Scalar::Bits {
-                    bits: discr_val,
-                    size: size.bytes() as u8,
-                }, discr_dest)?;
+                self.write_scalar(Scalar::from_uint(discr_val, size), discr_dest)?;
             }
             layout::Variants::NicheFilling {
                 dataful_variant,
@@ -733,10 +727,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                         self.place_field(dest, 0)?;
                     let niche_value = ((variant_index - niche_variants.start()) as u128)
                         .wrapping_add(niche_start);
-                    self.write_scalar(Scalar::Bits {
-                        bits: niche_value,
-                        size: niche_dest.layout.size.bytes() as u8,
-                    }, niche_dest)?;
+                    self.write_scalar(
+                        Scalar::from_uint(niche_value, niche_dest.layout.size),
+                        niche_dest
+                    )?;
                 }
             }
         }
@@ -766,11 +760,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         let layout = self.layout_of(ty)?;
 
         // More sanity checks
-        let (size, align) = self.read_size_and_align_from_vtable(vtable)?;
-        assert_eq!(size, layout.size);
-        assert_eq!(align.abi(), layout.align.abi()); // only ABI alignment is preserved
-        // FIXME: More checks for the vtable? We could make sure it is exactly
-        // the one one would expect for this type.
+        if cfg!(debug_assertions) {
+            let (size, align) = self.read_size_and_align_from_vtable(vtable)?;
+            assert_eq!(size, layout.size);
+            assert_eq!(align.abi(), layout.align.abi()); // only ABI alignment is preserved
+        }
 
         let mplace = MPlaceTy {
             mplace: MemPlace { extra: None, ..*mplace },
diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs
index 933f06d3d10..114ef093ec2 100644
--- a/src/librustc_mir/interpret/step.rs
+++ b/src/librustc_mir/interpret/step.rs
@@ -14,7 +14,7 @@
 
 use rustc::mir;
 use rustc::ty::layout::LayoutOf;
-use rustc::mir::interpret::{EvalResult, Scalar};
+use rustc::mir::interpret::{EvalResult, Scalar, PointerArithmetic};
 
 use super::{EvalContext, Machine};
 
@@ -269,12 +269,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 let src = self.eval_place(place)?;
                 let mplace = self.force_allocation(src)?;
                 let len = mplace.len(&self)?;
-                let size = self.memory.pointer_size().bytes() as u8;
+                let size = self.pointer_size();
                 self.write_scalar(
-                    Scalar::Bits {
-                        bits: len as u128,
-                        size,
-                    },
+                    Scalar::from_uint(len, size),
                     dest,
                 )?;
             }
@@ -294,12 +291,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 let layout = self.layout_of(ty)?;
                 assert!(!layout.is_unsized(),
                         "SizeOf nullary MIR operator called for unsized type");
-                let size = self.memory.pointer_size().bytes() as u8;
+                let size = self.pointer_size();
                 self.write_scalar(
-                    Scalar::Bits {
-                        bits: layout.size.bytes() as u128,
-                        size,
-                    },
+                    Scalar::from_uint(layout.size.bytes(), size),
                     dest,
                 )?;
             }
@@ -313,11 +307,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             Discriminant(ref place) => {
                 let place = self.eval_place(place)?;
                 let discr_val = self.read_discriminant(self.place_to_op(place)?)?.0;
-                let size = dest.layout.size.bytes() as u8;
-                self.write_scalar(Scalar::Bits {
-                    bits: discr_val,
-                    size,
-                }, dest)?;
+                let size = dest.layout.size;
+                self.write_scalar(Scalar::from_uint(discr_val, size), dest)?;
             }
         }
 
diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs
index 11826e0ce0c..8fc7c11c6ab 100644
--- a/src/librustc_mir/interpret/terminator.rs
+++ b/src/librustc_mir/interpret/terminator.rs
@@ -16,7 +16,7 @@ use rustc::ty::layout::LayoutOf;
 use syntax::source_map::Span;
 use rustc_target::spec::abi::Abi;
 
-use rustc::mir::interpret::{EvalResult, Scalar};
+use rustc::mir::interpret::{EvalResult, Scalar, PointerArithmetic};
 use super::{
     EvalContext, Machine, Value, OpTy, Place, PlaceTy, ValTy, Operand, StackPopCleanup
 };
@@ -60,10 +60,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
 
                 for (index, &const_int) in values.iter().enumerate() {
                     // Compare using binary_op
-                    let const_int = Scalar::Bits {
-                        bits: const_int,
-                        size: discr.layout.size.bytes() as u8
-                    };
+                    let const_int = Scalar::from_uint(const_int, discr.layout.size);
                     let (res, _) = self.binary_op(mir::BinOp::Eq,
                         discr,
                         ValTy { value: Value::Scalar(const_int.into()), layout: discr.layout }
@@ -411,7 +408,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             }
             // cannot use the shim here, because that will only result in infinite recursion
             ty::InstanceDef::Virtual(_, idx) => {
-                let ptr_size = self.memory.pointer_size();
+                let ptr_size = self.pointer_size();
                 let ptr_align = self.tcx.data_layout.pointer_align;
                 let ptr = self.ref_to_mplace(self.read_value(args[0])?)?;
                 let vtable = ptr.vtable()?;
diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs
index 74567b42974..0e09f65f0a8 100644
--- a/src/librustc_mir/interpret/traits.rs
+++ b/src/librustc_mir/interpret/traits.rs
@@ -10,7 +10,7 @@
 
 use rustc::ty::{self, Ty};
 use rustc::ty::layout::{Size, Align, LayoutOf};
-use rustc::mir::interpret::{Scalar, Pointer, EvalResult};
+use rustc::mir::interpret::{Scalar, Pointer, EvalResult, PointerArithmetic};
 
 use syntax::ast::Mutability;
 
@@ -35,7 +35,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         let size = layout.size.bytes();
         let align = layout.align.abi();
 
-        let ptr_size = self.memory.pointer_size();
+        let ptr_size = self.pointer_size();
         let ptr_align = self.tcx.data_layout.pointer_align;
         let methods = self.tcx.vtable_methods(trait_ref);
         let vtable = self.memory.allocate(
@@ -49,15 +49,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         self.memory.write_ptr_sized(vtable, ptr_align, Scalar::Ptr(drop).into())?;
 
         let size_ptr = vtable.offset(ptr_size, &self)?;
-        self.memory.write_ptr_sized(size_ptr, ptr_align, Scalar::Bits {
-            bits: size as u128,
-            size: ptr_size.bytes() as u8,
-        }.into())?;
+        self.memory.write_ptr_sized(size_ptr, ptr_align, Scalar::from_uint(size, ptr_size).into())?;
         let align_ptr = vtable.offset(ptr_size * 2, &self)?;
-        self.memory.write_ptr_sized(align_ptr, ptr_align, Scalar::Bits {
-            bits: align as u128,
-            size: ptr_size.bytes() as u8,
-        }.into())?;
+        self.memory.write_ptr_sized(align_ptr, ptr_align,
+            Scalar::from_uint(align, ptr_size).into())?;
 
         for (i, method) in methods.iter().enumerate() {
             if let Some((def_id, substs)) = *method {
@@ -97,7 +92,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         &self,
         vtable: Pointer,
     ) -> EvalResult<'tcx, (Size, Align)> {
-        let pointer_size = self.memory.pointer_size();
+        let pointer_size = self.pointer_size();
         let pointer_align = self.tcx.data_layout.pointer_align;
         let size = self.memory.read_ptr_sized(vtable.offset(pointer_size, self)?,pointer_align)?
             .to_bits(pointer_size)? as u64;
diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs
index d50fd6e13c1..ef2ae8f5337 100644
--- a/src/librustc_mir/interpret/validity.rs
+++ b/src/librustc_mir/interpret/validity.rs
@@ -15,7 +15,7 @@ use rustc::ty::layout::{self, Size, Primitive};
 use rustc::ty::{self, Ty};
 use rustc_data_structures::fx::FxHashSet;
 use rustc::mir::interpret::{
-    Scalar, AllocType, EvalResult, ScalarMaybeUndef, EvalErrorKind
+    Scalar, AllocType, EvalResult, ScalarMaybeUndef, EvalErrorKind, PointerArithmetic
 };
 
 use super::{
@@ -118,7 +118,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 bits
             },
             Scalar::Ptr(_) => {
-                let ptr_size = self.memory.pointer_size();
+                let ptr_size = self.pointer_size();
                 let ptr_max = u128::max_value() >> (128 - ptr_size.bits());
                 return if lo > hi {
                     if lo - hi == 1 {
@@ -376,6 +376,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                                         "non-pointer vtable in fat pointer", path
                                     ),
                             }
+                            // FIXME: More checks for the vtable.
                         }
                         ty::Slice(..) | ty::Str => {
                             match ptr.extra.unwrap().to_usize(self) {