about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc/ich/impls_ty.rs23
-rw-r--r--src/librustc/mir/interpret/value.rs160
-rw-r--r--src/librustc/mir/mod.rs27
-rw-r--r--src/librustc/ty/mod.rs2
-rw-r--r--src/librustc/ty/sty.rs48
-rw-r--r--src/librustc_codegen_llvm/mir/constant.rs10
-rw-r--r--src/librustc_mir/build/expr/as_rvalue.rs4
-rw-r--r--src/librustc_mir/build/matches/test.rs2
-rw-r--r--src/librustc_mir/build/misc.rs9
-rw-r--r--src/librustc_mir/hair/cx/expr.rs3
-rw-r--r--src/librustc_mir/hair/cx/mod.rs47
-rw-r--r--src/librustc_mir/hair/pattern/_match.rs2
-rw-r--r--src/librustc_mir/hair/pattern/mod.rs39
-rw-r--r--src/librustc_mir/interpret/cast.rs80
-rw-r--r--src/librustc_mir/interpret/const_eval.rs21
-rw-r--r--src/librustc_mir/interpret/eval_context.rs87
-rw-r--r--src/librustc_mir/interpret/memory.rs35
-rw-r--r--src/librustc_mir/interpret/operator.rs64
-rw-r--r--src/librustc_mir/interpret/place.rs10
-rw-r--r--src/librustc_mir/interpret/terminator/drop.rs2
-rw-r--r--src/librustc_mir/interpret/terminator/mod.rs8
-rw-r--r--src/librustc_mir/interpret/traits.rs17
-rw-r--r--src/librustc_mir/transform/const_prop.rs15
-rw-r--r--src/librustc_mir/transform/simplify_branches.rs2
24 files changed, 436 insertions, 281 deletions
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 155efd0c43e..43c9fc0b8fd 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -473,11 +473,24 @@ impl_stable_hash_for!(enum ::syntax::ast::Mutability {
     Mutable
 });
 
-impl_stable_hash_for!(enum mir::interpret::Scalar {
-    Bytes(b),
-    Ptr(p),
-    Undef
-});
+
+impl<'a> HashStable<StableHashingContext<'a>>
+for ::mir::interpret::Scalar {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a>,
+                                          hasher: &mut StableHasher<W>) {
+        use mir::interpret::Scalar::*;
+
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            Bits { bits, defined } => {
+                bits.hash_stable(hcx, hasher);
+                defined.hash_stable(hcx, hasher);
+            },
+            Ptr(ptr) => ptr.hash_stable(hcx, hasher),
+        }
+    }
+}
 
 impl_stable_hash_for!(struct ty::Const<'tcx> {
     ty,
diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs
index 53bc56cffe6..9a9c351f39e 100644
--- a/src/librustc/mir/interpret/value.rs
+++ b/src/librustc/mir/interpret/value.rs
@@ -51,19 +51,13 @@ impl<'tcx> ConstValue<'tcx> {
     }
 
     #[inline]
-    pub fn to_bits(&self) -> Option<u128> {
-        match self.to_primval() {
-            Some(Scalar::Bytes(val)) => Some(val),
-            _ => None,
-        }
+    pub fn to_bits(&self, size: Size) -> Option<u128> {
+        self.to_primval()?.to_bits(size).ok()
     }
 
     #[inline]
     pub fn to_ptr(&self) -> Option<Pointer> {
-        match self.to_primval() {
-            Some(Scalar::Ptr(ptr)) => Some(ptr),
-            _ => None,
-        }
+        self.to_primval()?.to_ptr().ok()
     }
 }
 
@@ -93,56 +87,85 @@ impl<'tcx> ty::TypeFoldable<'tcx> for Value {
 }
 
 impl<'tcx> Scalar {
-    pub fn ptr_null() -> Self {
-        Scalar::Bytes(0)
+    pub fn ptr_null<C: HasDataLayout>(cx: C) -> Self {
+        Scalar::Bits {
+            bits: 0,
+            defined: cx.data_layout().pointer_size.bits() as u8,
+    }
     }
 
     pub fn ptr_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
         let layout = cx.data_layout();
         match self {
-            Scalar::Bytes(b) => {
-                assert_eq!(b as u64 as u128, b);
-                Ok(Scalar::Bytes(layout.signed_offset(b as u64, i)? as u128))
+            Scalar::Bits { bits, defined } => {
+                let pointer_size = layout.pointer_size.bits() as u8;
+                if defined < pointer_size {
+                    err!(ReadUndefBytes)
+                } else {
+                    Ok(Scalar::Bits {
+                        bits: layout.signed_offset(bits as u64, i)? as u128,
+                        defined: pointer_size,
+                    })
+            }
             }
             Scalar::Ptr(ptr) => ptr.signed_offset(i, layout).map(Scalar::Ptr),
-            Scalar::Undef => err!(ReadUndefBytes),
         }
     }
 
     pub fn ptr_offset<C: HasDataLayout>(self, i: Size, cx: C) -> EvalResult<'tcx, Self> {
         let layout = cx.data_layout();
         match self {
-            Scalar::Bytes(b) => {
-                assert_eq!(b as u64 as u128, b);
-                Ok(Scalar::Bytes(layout.offset(b as u64, i.bytes())? as u128))
+            Scalar::Bits { bits, defined } => {
+                let pointer_size = layout.pointer_size.bits() as u8;
+                if defined < pointer_size {
+                    err!(ReadUndefBytes)
+                } else {
+                    Ok(Scalar::Bits {
+                        bits: layout.offset(bits as u64, i.bytes())? as u128,
+                        defined: pointer_size,
+                    })
+            }
             }
             Scalar::Ptr(ptr) => ptr.offset(i, layout).map(Scalar::Ptr),
-            Scalar::Undef => err!(ReadUndefBytes),
         }
     }
 
     pub fn ptr_wrapping_signed_offset<C: HasDataLayout>(self, i: i64, cx: C) -> EvalResult<'tcx, Self> {
         let layout = cx.data_layout();
         match self {
-            Scalar::Bytes(b) => {
-                assert_eq!(b as u64 as u128, b);
-                Ok(Scalar::Bytes(layout.wrapping_signed_offset(b as u64, i) as u128))
+            Scalar::Bits { bits, defined } => {
+                let pointer_size = layout.pointer_size.bits() as u8;
+                if defined < pointer_size {
+                    err!(ReadUndefBytes)
+                } else {
+                    Ok(Scalar::Bits {
+                        bits: layout.wrapping_signed_offset(bits as u64, i) as u128,
+                        defined: pointer_size,
+                    })
+            }
             }
             Scalar::Ptr(ptr) => Ok(Scalar::Ptr(ptr.wrapping_signed_offset(i, layout))),
-            Scalar::Undef => err!(ReadUndefBytes),
         }
     }
 
-    pub fn is_null(self) -> EvalResult<'tcx, bool> {
+    pub fn is_null_ptr<C: HasDataLayout>(self, cx: C) -> EvalResult<'tcx, bool> {
         match self {
-            Scalar::Bytes(b) => Ok(b == 0),
+            Scalar::Bits {
+                bits, defined,
+            } => if defined < cx.data_layout().pointer_size.bits() as u8 {
+                err!(ReadUndefBytes)
+            } else {
+                Ok(bits == 0)
+            },
             Scalar::Ptr(_) => Ok(false),
-            Scalar::Undef => err!(ReadUndefBytes),
         }
     }
 
-    pub fn to_value_with_len(self, len: u64) -> Value {
-        Value::ScalarPair(self, Scalar::from_u128(len as u128))
+    pub fn to_value_with_len<C: HasDataLayout>(self, len: u64, cx: C) -> Value {
+        Value::ScalarPair(self, Scalar::Bits {
+            bits: len as u128,
+            defined: cx.data_layout().pointer_size.bits() as u8,
+        })
     }
 
     pub fn to_value_with_vtable(self, vtable: Pointer) -> Value {
@@ -163,20 +186,20 @@ impl From<Pointer> for Scalar {
 /// A `Scalar` represents an immediate, primitive value existing outside of a
 /// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in
 /// size. Like a range of bytes in an `Allocation`, a `Scalar` can either represent the raw bytes
-/// of a simple value, a pointer into another `Allocation`, or be undefined.
+/// of a simple value or a pointer into another `Allocation`
 #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)]
 pub enum Scalar {
     /// The raw bytes of a simple value.
-    Bytes(u128),
+    Bits {
+        /// number of bits that are valid and may be read
+        defined: u8,
+        bits: u128,
+    },
 
     /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of
     /// relocations, but a `Scalar` is only large enough to contain one, so we just represent the
     /// relocation and its associated offset together as a `Pointer` here.
     Ptr(Pointer),
-
-    /// An undefined `Scalar`, for representing values that aren't safe to examine, but are safe
-    /// to copy around, just like undefined bytes in an `Allocation`.
-    Undef,
 }
 
 #[derive(Clone, Copy, Debug, PartialEq)]
@@ -190,41 +213,38 @@ pub enum ScalarKind {
 }
 
 impl<'tcx> Scalar {
-    pub fn from_u128(n: u128) -> Self {
-        Scalar::Bytes(n)
-    }
-
-    pub fn from_i128(n: i128) -> Self {
-        Scalar::Bytes(n as u128)
+    pub fn undef() -> Self {
+        Scalar::Bits { bits: 0, defined: 0 }
     }
 
     pub fn from_bool(b: bool) -> Self {
-        Scalar::Bytes(b as u128)
+        // FIXME: can we make defined `1`?
+        Scalar::Bits { bits: b as u128, defined: 8 }
     }
 
     pub fn from_char(c: char) -> Self {
-        Scalar::Bytes(c as u128)
+        Scalar::Bits { bits: c as u128, defined: 32 }
     }
 
-    pub fn to_bytes(self) -> EvalResult<'tcx, u128> {
+    pub fn to_bits(self, size: Size) -> EvalResult<'tcx, u128> {
         match self {
-            Scalar::Bytes(b) => Ok(b),
+            Scalar::Bits { defined: 0, .. } => err!(ReadUndefBytes),
+            Scalar::Bits { bits, defined } if size.bits() <= defined as u64 => Ok(bits),
+            Scalar::Bits { .. } => err!(ReadUndefBytes),
             Scalar::Ptr(_) => err!(ReadPointerAsBytes),
-            Scalar::Undef => err!(ReadUndefBytes),
         }
     }
 
     pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> {
         match self {
-            Scalar::Bytes(_) => err!(ReadBytesAsPointer),
+            Scalar::Bits {..} => err!(ReadBytesAsPointer),
             Scalar::Ptr(p) => Ok(p),
-            Scalar::Undef => err!(ReadUndefBytes),
         }
     }
 
-    pub fn is_bytes(self) -> bool {
+    pub fn is_bits(self) -> bool {
         match self {
-            Scalar::Bytes(_) => true,
+            Scalar::Bits { .. } => true,
             _ => false,
         }
     }
@@ -236,46 +256,10 @@ impl<'tcx> Scalar {
         }
     }
 
-    pub fn is_undef(self) -> bool {
-        match self {
-            Scalar::Undef => true,
-            _ => false,
-        }
-    }
-
-    pub fn to_u128(self) -> EvalResult<'tcx, u128> {
-        self.to_bytes()
-    }
-
-    pub fn to_u64(self) -> EvalResult<'tcx, u64> {
-        self.to_bytes().map(|b| {
-            assert_eq!(b as u64 as u128, b);
-            b as u64
-        })
-    }
-
-    pub fn to_i32(self) -> EvalResult<'tcx, i32> {
-        self.to_bytes().map(|b| {
-            assert_eq!(b as i32 as u128, b);
-            b as i32
-        })
-    }
-
-    pub fn to_i128(self) -> EvalResult<'tcx, i128> {
-        self.to_bytes().map(|b| b as i128)
-    }
-
-    pub fn to_i64(self) -> EvalResult<'tcx, i64> {
-        self.to_bytes().map(|b| {
-            assert_eq!(b as i64 as u128, b);
-            b as i64
-        })
-    }
-
     pub fn to_bool(self) -> EvalResult<'tcx, bool> {
-        match self.to_bytes()? {
-            0 => Ok(false),
-            1 => Ok(true),
+        match self {
+            Scalar::Bits { bits: 0, defined: 8 } => Ok(false),
+            Scalar::Bits { bits: 1, defined: 8 } => Ok(true),
             _ => err!(InvalidBool),
         }
     }
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 0dc860d360f..a177b9055c5 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1149,11 +1149,13 @@ impl<'tcx> TerminatorKind<'tcx> {
             Return | Resume | Abort | Unreachable | GeneratorDrop => vec![],
             Goto { .. } => vec!["".into()],
             SwitchInt { ref values, switch_ty, .. } => {
+                let size = ty::tls::with(|tcx| switch_ty.scalar_size(tcx));
+                let size = size.map_or(0, |size| size.bytes()) as u8;
                 values.iter()
                       .map(|&u| {
                           let mut s = String::new();
                           print_miri_value(
-                              Value::Scalar(Scalar::Bytes(u)),
+                              Value::Scalar(Scalar::Bits { bits: u, defined: size }),
                               switch_ty,
                               &mut s,
                           ).unwrap();
@@ -1893,19 +1895,22 @@ pub fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Resul
 pub fn print_miri_value<W: Write>(value: Value, ty: Ty, f: &mut W) -> fmt::Result {
     use ty::TypeVariants::*;
     match (value, &ty.sty) {
-        (Value::Scalar(Scalar::Bytes(0)), &TyBool) => write!(f, "false"),
-        (Value::Scalar(Scalar::Bytes(1)), &TyBool) => write!(f, "true"),
-        (Value::Scalar(Scalar::Bytes(bits)), &TyFloat(ast::FloatTy::F32)) =>
+        (Value::Scalar(Scalar::Bits { bits: 0, defined: 8 }), &TyBool) => write!(f, "false"),
+        (Value::Scalar(Scalar::Bits { bits: 1, defined: 8 }), &TyBool) => write!(f, "true"),
+        (Value::Scalar(Scalar::Bits { bits, defined: 32 }), &TyFloat(ast::FloatTy::F32)) =>
             write!(f, "{}f32", Single::from_bits(bits)),
-        (Value::Scalar(Scalar::Bytes(bits)), &TyFloat(ast::FloatTy::F64)) =>
+        (Value::Scalar(Scalar::Bits { bits, defined: 64 }), &TyFloat(ast::FloatTy::F64)) =>
             write!(f, "{}f64", Double::from_bits(bits)),
-        (Value::Scalar(Scalar::Bytes(n)), &TyUint(ui)) => write!(f, "{:?}{}", n, ui),
-        (Value::Scalar(Scalar::Bytes(n)), &TyInt(i)) => write!(f, "{:?}{}", n as i128, i),
-        (Value::Scalar(Scalar::Bytes(n)), &TyChar) =>
-            write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()),
-        (Value::Scalar(Scalar::Undef), &TyFnDef(did, _)) =>
+        (Value::Scalar(Scalar::Bits { bits, .. }), &TyUint(ui)) => write!(f, "{:?}{}", bits, ui),
+        (Value::Scalar(Scalar::Bits { bits, defined }), &TyInt(i)) => {
+            let amt = 128 - defined;
+            write!(f, "{:?}{}", ((bits as i128) << amt) >> amt, i)
+        },
+        (Value::Scalar(Scalar::Bits { bits, defined: 32 }), &TyChar) =>
+            write!(f, "{:?}", ::std::char::from_u32(bits as u32).unwrap()),
+        (Value::Scalar(Scalar::Bits { defined: 0, .. }), &TyFnDef(did, _)) =>
             write!(f, "{}", item_path_str(did)),
-        (Value::ScalarPair(Scalar::Ptr(ptr), Scalar::Bytes(len)),
+        (Value::ScalarPair(Scalar::Ptr(ptr), Scalar::Bits { bits: len, .. }),
          &TyRef(_, &ty::TyS { sty: TyStr, .. }, _)) => {
             ty::tls::with(|tcx| {
                 match tcx.alloc_map.lock().get(ptr.alloc_id) {
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 4507da1c698..3802735b85b 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1982,7 +1982,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         match tcx.const_eval(param_env.and(cid)) {
             Ok(val) => {
                 // FIXME: Find the right type and use it instead of `val.ty` here
-                if let Some(b) = val.assert_bits(val.ty) {
+                if let Some(b) = val.assert_bits(tcx, val.ty) {
                     trace!("discriminants: {} ({:?})", b, repr_type);
                     Some(Discr {
                         val: b,
diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs
index 3095027b4ef..411c86d7cca 100644
--- a/src/librustc/ty/sty.rs
+++ b/src/librustc/ty/sty.rs
@@ -17,15 +17,17 @@ use middle::region;
 use rustc_data_structures::indexed_vec::Idx;
 use ty::subst::{Substs, Subst, Kind, UnpackedKind};
 use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
-use ty::{Slice, TyS};
+use ty::{Slice, TyS, layout};
 use util::captures::Captures;
 use mir::interpret::{Scalar, Pointer, Value, ConstValue};
+use rustc_target::abi::{Size, HasDataLayout};
 
 use std::iter;
 use std::cmp::Ordering;
 use rustc_target::spec::abi;
 use syntax::ast::{self, Name};
 use syntax::symbol::{keywords, InternedString};
+use syntax::attr;
 
 use serialize;
 
@@ -1755,6 +1757,23 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
             _ => bug!("cannot convert type `{:?}` to a closure kind", self),
         }
     }
+
+    /// If this type is a scalar, compute its size without
+    /// going through `tcx.layout_of`
+    pub fn scalar_size<C: HasDataLayout>(
+        &self,
+        cx: C,
+    ) -> Option<Size> {
+        let ty = match self.sty {
+            ty::TyBool => return Some(Size::from_bytes(1)),
+            ty::TyChar => return Some(Size::from_bytes(4)),
+            ty::TyInt(ity) => attr::IntType::SignedInt(ity),
+            ty::TyUint(uty) => attr::IntType::UnsignedInt(uty),
+            _ => return None,
+        };
+        use ty::layout::IntegerExt;
+        Some(layout::Integer::from_attr(cx, ty).size())
+    }
 }
 
 /// Typed constant value.
@@ -1820,15 +1839,18 @@ impl<'tcx> Const<'tcx> {
     #[inline]
     pub fn from_bits(
         tcx: TyCtxt<'_, '_, 'tcx>,
-        val: u128,
+        bits: u128,
         ty: Ty<'tcx>,
     ) -> &'tcx Self {
-        Self::from_primval(tcx, Scalar::Bytes(val), ty)
+        let defined = ty.scalar_size(tcx).unwrap_or_else(|| {
+            panic!("non-scalar type in from_bits: {:?}", ty)
+        }).bits() as u8;
+        Self::from_primval(tcx, Scalar::Bits { bits, defined }, ty)
     }
 
     #[inline]
     pub fn zero_sized(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> &'tcx Self {
-        Self::from_primval(tcx, Scalar::Undef, ty)
+        Self::from_primval(tcx, Scalar::undef(), ty)
     }
 
     #[inline]
@@ -1842,12 +1864,13 @@ impl<'tcx> Const<'tcx> {
     }
 
     #[inline]
-    pub fn to_bits(&self, ty: Ty<'_>) -> Option<u128> {
+    pub fn to_bits<C: HasDataLayout>(&self, cx: C, ty: Ty<'tcx>) -> Option<u128> {
         if self.ty != ty {
             return None;
         }
+        let size = ty.scalar_size(cx)?;
         match self.val {
-            ConstVal::Value(val) => val.to_bits(),
+            ConstVal::Value(val) => val.to_bits(size),
             _ => None,
         }
     }
@@ -1877,17 +1900,18 @@ impl<'tcx> Const<'tcx> {
     }
 
     #[inline]
-    pub fn assert_bits(&self, ty: Ty<'_>) -> Option<u128> {
+    pub fn assert_bits<C: HasDataLayout>(&self, cx: C, ty: Ty<'tcx>) -> Option<u128> {
         assert_eq!(self.ty, ty);
+        let size = ty.scalar_size(cx)?;
         match self.val {
-            ConstVal::Value(val) => val.to_bits(),
+            ConstVal::Value(val) => val.to_bits(size),
             _ => None,
         }
     }
 
     #[inline]
     pub fn assert_bool(&self, tcx: TyCtxt<'_, '_, '_>) -> Option<bool> {
-        self.assert_bits(tcx.types.bool).and_then(|v| match v {
+        self.assert_bits(tcx, tcx.types.bool).and_then(|v| match v {
             0 => Some(false),
             1 => Some(true),
             _ => None,
@@ -1896,12 +1920,12 @@ impl<'tcx> Const<'tcx> {
 
     #[inline]
     pub fn assert_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> Option<u64> {
-        self.assert_bits(tcx.types.usize).map(|v| v as u64)
+        self.assert_bits(tcx, tcx.types.usize).map(|v| v as u64)
     }
 
     #[inline]
-    pub fn unwrap_bits(&self, ty: Ty<'_>) -> u128 {
-        match self.assert_bits(ty) {
+    pub fn unwrap_bits(&self, tcx: TyCtxt<'_, '_, '_>, ty: Ty<'tcx>) -> u128 {
+        match self.assert_bits(tcx, ty) {
             Some(val) => val,
             None => bug!("expected bits of {}, got {:#?}", ty, self),
         }
diff --git a/src/librustc_codegen_llvm/mir/constant.rs b/src/librustc_codegen_llvm/mir/constant.rs
index b1161a04128..fc3733f1398 100644
--- a/src/librustc_codegen_llvm/mir/constant.rs
+++ b/src/librustc_codegen_llvm/mir/constant.rs
@@ -32,11 +32,13 @@ pub fn primval_to_llvm(cx: &CodegenCx,
                        cv: Scalar,
                        layout: &layout::Scalar,
                        llty: Type) -> ValueRef {
-    let bits = if layout.is_bool() { 1 } else { layout.value.size(cx).bits() };
+    let bitsize = if layout.is_bool() { 1 } else { layout.value.size(cx).bits() };
     match cv {
-        Scalar::Undef => C_undef(Type::ix(cx, bits)),
-        Scalar::Bytes(b) => {
-            let llval = C_uint_big(Type::ix(cx, bits), b);
+        Scalar::Bits { defined, .. } if (defined as u64) < bitsize || defined == 0 => {
+            C_undef(Type::ix(cx, bitsize))
+        },
+        Scalar::Bits { bits, .. } => {
+            let llval = C_uint_big(Type::ix(cx, bitsize), bits);
             if layout.value == layout::Pointer {
                 unsafe { llvm::LLVMConstIntToPtr(llval, llty.to_ref()) }
             } else {
diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs
index 4115dbe6274..c054d038353 100644
--- a/src/librustc_mir/build/expr/as_rvalue.rs
+++ b/src/librustc_mir/build/expr/as_rvalue.rs
@@ -374,7 +374,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
 
     // Helper to get a `-1` value of the appropriate type
     fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
-        let bits = self.hir.integer_bit_width(ty);
+        let bits = ty.scalar_size(self.hir.tcx()).expect("neg_1_literal expects integers").bits();
         let n = (!0u128) >> (128 - bits);
         let literal = Literal::Value {
             value: ty::Const::from_bits(self.hir.tcx(), n, ty)
@@ -386,7 +386,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     // Helper to get the minimum value of the appropriate type
     fn minval_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
         assert!(ty.is_signed());
-        let bits = self.hir.integer_bit_width(ty);
+        let bits = ty.scalar_size(self.hir.tcx()).expect("minval_literal expects integers").bits();
         let n = 1 << (bits - 1);
         let literal = Literal::Value {
             value: ty::Const::from_bits(self.hir.tcx(), n, ty)
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index 5dbe8d850bd..471b6defdc9 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -124,7 +124,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             PatternKind::Constant { value } => {
                 indices.entry(value)
                        .or_insert_with(|| {
-                           options.push(value.unwrap_bits(switch_ty));
+                           options.push(value.unwrap_bits(self.hir.tcx(), switch_ty));
                            options.len() - 1
                        });
                 true
diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs
index 6501dd00fe8..26cf669fd8e 100644
--- a/src/librustc_mir/build/misc.rs
+++ b/src/librustc_mir/build/misc.rs
@@ -52,15 +52,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
     // Returns a zero literal operand for the appropriate type, works for
     // bool, char and integers.
     pub fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
-        match ty.sty {
-            ty::TyBool |
-            ty::TyChar |
-            ty::TyUint(_) |
-            ty::TyInt(_) => {}
-            _ => {
-                span_bug!(span, "Invalid type for zero_literal: `{:?}`", ty)
-            }
-        }
         let literal = Literal::Value {
             value: ty::Const::from_bits(self.hir.tcx(), 0, ty)
         };
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index 0d93634981f..71cf983d7a1 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -614,7 +614,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
                                 let idx = adt_def.variant_index_with_id(variant_id);
                                 let (d, o) = adt_def.discriminant_def_for_variant(idx);
                                 use rustc::ty::util::IntTypeExt;
-                                let ty = adt_def.repr.discr_type().to_ty(cx.tcx());
+                                let ty = adt_def.repr.discr_type();
+                                let ty = ty.to_ty(cx.tcx());
                                 Some((d, o, ty))
                             }
                             _ => None,
diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs
index 562e4cec6b8..4d78925e806 100644
--- a/src/librustc_mir/hair/cx/mod.rs
+++ b/src/librustc_mir/hair/cx/mod.rs
@@ -21,9 +21,8 @@ use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::middle::region;
 use rustc::infer::InferCtxt;
-use rustc::ty::layout::IntegerExt;
 use rustc::ty::subst::Subst;
-use rustc::ty::{self, Ty, TyCtxt, layout};
+use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::subst::{Kind, Substs};
 use syntax::ast::{self, LitKind};
 use syntax::attr;
@@ -139,18 +138,6 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn integer_bit_width(
-        &self,
-        ty: Ty,
-    ) -> u64 {
-        let ty = match ty.sty {
-            ty::TyInt(ity) => attr::IntType::SignedInt(ity),
-            ty::TyUint(uty) => attr::IntType::UnsignedInt(uty),
-            _ => bug!("{} is not an integer", ty),
-        };
-        layout::Integer::from_attr(self.tcx, ty).size().bits()
-    }
-
     // FIXME: Combine with rustc_mir::hair::pattern::lit_to_const
     pub fn const_eval_literal(
         &mut self,
@@ -169,12 +156,15 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
         };
 
         let clamp = |n| {
-            let size = self.integer_bit_width(ty);
+            let size = ty.scalar_size(self.tcx).expect("const_eval_lit::clamp expects ints").bits();
             trace!("clamp {} with size {} and amt {}", n, size, 128 - size);
             let amt = 128 - size;
             let result = (n << amt) >> amt;
             trace!("clamp result: {}", result);
-            result
+            ConstValue::Scalar(Scalar::Bits {
+                bits: result,
+                defined: size as u8,
+            })
         };
 
         use rustc::mir::interpret::*;
@@ -184,21 +174,26 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
                 let id = self.tcx.allocate_bytes(s.as_bytes());
                 ConstValue::ScalarPair(
                     Scalar::Ptr(id.into()),
-                    Scalar::from_u128(s.len() as u128),
+                    Scalar::Bits {
+                        bits: s.len() as u128,
+                        defined: self.tcx.data_layout.pointer_size.bits() as u8,
+                    }
                 )
             },
             LitKind::ByteStr(ref data) => {
                 let id = self.tcx.allocate_bytes(data);
                 ConstValue::Scalar(Scalar::Ptr(id.into()))
             },
-            LitKind::Byte(n) => ConstValue::Scalar(Scalar::Bytes(n as u128)),
+            LitKind::Byte(n) => ConstValue::Scalar(Scalar::Bits {
+                bits: n as u128,
+                defined: 8,
+            }),
             LitKind::Int(n, _) if neg => {
                 let n = n as i128;
                 let n = n.overflowing_neg().0;
-                let n = clamp(n as u128);
-                ConstValue::Scalar(Scalar::Bytes(n))
+                clamp(n as u128)
             },
-            LitKind::Int(n, _) => ConstValue::Scalar(Scalar::Bytes(clamp(n))),
+            LitKind::Int(n, _) => clamp(n),
             LitKind::Float(n, fty) => {
                 parse_float(n, fty)
             }
@@ -209,8 +204,14 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
                 };
                 parse_float(n, fty)
             }
-            LitKind::Bool(b) => ConstValue::Scalar(Scalar::Bytes(b as u128)),
-            LitKind::Char(c) => ConstValue::Scalar(Scalar::Bytes(c as u128)),
+            LitKind::Bool(b) => ConstValue::Scalar(Scalar::Bits {
+                bits: b as u128,
+                defined: 8,
+            }),
+            LitKind::Char(c) => ConstValue::Scalar(Scalar::Bits {
+                bits: c as u128,
+                defined: 32,
+            }),
         };
         Literal::Value {
             value: ty::Const::from_const_value(self.tcx, lit, ty)
diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs
index 70e8cd336a3..d916e866125 100644
--- a/src/librustc_mir/hair/pattern/_match.rs
+++ b/src/librustc_mir/hair/pattern/_match.rs
@@ -958,7 +958,7 @@ fn slice_pat_covered_by_constructor<'tcx>(
     {
         match pat.kind {
             box PatternKind::Constant { value } => {
-                let b = value.unwrap_bits(pat.ty);
+                let b = value.unwrap_bits(tcx, pat.ty);
                 assert_eq!(b as u8 as u128, b);
                 if b as u8 != *ch {
                     return Ok(false);
diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs
index e387a4fa61b..d813133b272 100644
--- a/src/librustc_mir/hair/pattern/mod.rs
+++ b/src/librustc_mir/hair/pattern/mod.rs
@@ -1057,7 +1057,7 @@ pub fn compare_const_vals<'a, 'tcx>(
 
     // FIXME: This should use assert_bits(ty) instead of use_bits
     // but triggers possibly bugs due to mismatching of arrays and slices
-    if let (Some(a), Some(b)) = (a.to_bits(ty), b.to_bits(ty)) {
+    if let (Some(a), Some(b)) = (a.to_bits(tcx, ty), b.to_bits(tcx, ty)) {
         use ::rustc_apfloat::Float;
         return match ty.sty {
             ty::TyFloat(ast::FloatTy::F32) => {
@@ -1130,20 +1130,26 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
             let id = tcx.allocate_bytes(s.as_bytes());
             ConstValue::ScalarPair(
                 Scalar::Ptr(id.into()),
-                Scalar::from_u128(s.len() as u128),
+                Scalar::Bits {
+                    bits: s.len() as u128,
+                    defined: tcx.data_layout.pointer_size.bits() as u8,
+                },
             )
         },
         LitKind::ByteStr(ref data) => {
             let id = tcx.allocate_bytes(data);
             ConstValue::Scalar(Scalar::Ptr(id.into()))
         },
-        LitKind::Byte(n) => ConstValue::Scalar(Scalar::Bytes(n as u128)),
+        LitKind::Byte(n) => ConstValue::Scalar(Scalar::Bits {
+            bits: n as u128,
+            defined: 8,
+        }),
         LitKind::Int(n, _) => {
             enum Int {
                 Signed(IntTy),
                 Unsigned(UintTy),
             }
-            let ty = match ty.sty {
+            let ity = match ty.sty {
                 ty::TyInt(IntTy::Isize) => Int::Signed(tcx.sess.target.isize_ty),
                 ty::TyInt(other) => Int::Signed(other),
                 ty::TyUint(UintTy::Usize) => Int::Unsigned(tcx.sess.target.usize_ty),
@@ -1152,7 +1158,7 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
             };
             // This converts from LitKind::Int (which is sign extended) to
             // Scalar::Bytes (which is zero extended)
-            let n = match ty {
+            let n = match ity {
                 // FIXME(oli-obk): are these casts correct?
                 Int::Signed(IntTy::I8) if neg =>
                     (n as i8).overflowing_neg().0 as u8 as u128,
@@ -1171,7 +1177,10 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
                 Int::Signed(IntTy::I128)| Int::Unsigned(UintTy::U128) => n,
                 _ => bug!(),
             };
-            ConstValue::Scalar(Scalar::Bytes(n))
+            ConstValue::Scalar(Scalar::Bits {
+                bits: n,
+                defined: ty.scalar_size(tcx).unwrap().bits() as u8,
+            })
         },
         LitKind::Float(n, fty) => {
             parse_float(n, fty, neg)?
@@ -1183,8 +1192,14 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind,
             };
             parse_float(n, fty, neg)?
         }
-        LitKind::Bool(b) => ConstValue::Scalar(Scalar::Bytes(b as u128)),
-        LitKind::Char(c) => ConstValue::Scalar(Scalar::Bytes(c as u128)),
+        LitKind::Bool(b) => ConstValue::Scalar(Scalar::Bits {
+            bits: b as u128,
+            defined: 8,
+        }),
+        LitKind::Char(c) => ConstValue::Scalar(Scalar::Bits {
+            bits: c as u128,
+            defined: 32,
+        }),
     };
     Ok(ty::Const::from_const_value(tcx, lit, ty))
 }
@@ -1197,7 +1212,7 @@ pub fn parse_float<'tcx>(
     let num = num.as_str();
     use rustc_apfloat::ieee::{Single, Double};
     use rustc_apfloat::Float;
-    let bits = match fty {
+    let (bits, defined) = match fty {
         ast::FloatTy::F32 => {
             num.parse::<f32>().map_err(|_| ())?;
             let mut f = num.parse::<Single>().unwrap_or_else(|e| {
@@ -1206,7 +1221,7 @@ pub fn parse_float<'tcx>(
             if neg {
                 f = -f;
             }
-            f.to_bits()
+            (f.to_bits(), 32)
         }
         ast::FloatTy::F64 => {
             num.parse::<f64>().map_err(|_| ())?;
@@ -1216,9 +1231,9 @@ pub fn parse_float<'tcx>(
             if neg {
                 f = -f;
             }
-            f.to_bits()
+            (f.to_bits(), 64)
         }
     };
 
-    Ok(ConstValue::Scalar(Scalar::Bytes(bits)))
+    Ok(ConstValue::Scalar(Scalar::Bits { bits, defined }))
 }
diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs
index 674f03691a8..6c0a26e1f23 100644
--- a/src/librustc_mir/interpret/cast.rs
+++ b/src/librustc_mir/interpret/cast.rs
@@ -18,12 +18,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         trace!("Casting {:?}: {:?} to {:?}", val, src_ty, dest_ty);
 
         match val {
-            Scalar::Undef => Ok(Scalar::Undef),
+            Scalar::Bits { defined: 0, .. } => Ok(val),
             Scalar::Ptr(ptr) => self.cast_from_ptr(ptr, dest_ty),
-            Scalar::Bytes(b) => {
+            Scalar::Bits { bits, .. } => {
+                // TODO(oli-obk): impl scalar_size for floats and check defined bits here
                 match src_ty.sty {
-                    TyFloat(fty) => self.cast_from_float(b, fty, dest_ty),
-                    _ => self.cast_from_int(b, src_ty, dest_ty),
+                    TyFloat(fty) => self.cast_from_float(bits, fty, dest_ty),
+                    _ => self.cast_from_int(bits, src_ty, dest_ty),
                 }
             }
         }
@@ -46,20 +47,38 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         match dest_ty.sty {
             TyInt(_) | TyUint(_) => {
                 let v = self.truncate(v, dest_ty)?;
-                Ok(Scalar::Bytes(v))
+                Ok(Scalar::Bits {
+                    bits: v,
+                    defined: dest_ty.scalar_size(self.tcx.tcx).unwrap().bits() as u8,
+                })
             }
 
-            TyFloat(FloatTy::F32) if signed => Ok(Scalar::Bytes(Single::from_i128(v as i128).value.to_bits())),
-            TyFloat(FloatTy::F64) if signed => Ok(Scalar::Bytes(Double::from_i128(v as i128).value.to_bits())),
-            TyFloat(FloatTy::F32) => Ok(Scalar::Bytes(Single::from_u128(v).value.to_bits())),
-            TyFloat(FloatTy::F64) => Ok(Scalar::Bytes(Double::from_u128(v).value.to_bits())),
+            TyFloat(FloatTy::F32) if signed => Ok(Scalar::Bits {
+                bits: Single::from_i128(v as i128).value.to_bits(),
+                defined: 32,
+            }),
+            TyFloat(FloatTy::F64) if signed => Ok(Scalar::Bits {
+                bits: Double::from_i128(v as i128).value.to_bits(),
+                defined: 64,
+            }),
+            TyFloat(FloatTy::F32) => Ok(Scalar::Bits {
+                bits: Single::from_u128(v).value.to_bits(),
+                defined: 32,
+            }),
+            TyFloat(FloatTy::F64) => Ok(Scalar::Bits {
+                bits: Double::from_u128(v).value.to_bits(),
+                defined: 64,
+            }),
 
-            TyChar if v as u8 as u128 == v => Ok(Scalar::Bytes(v)),
+            TyChar if v as u8 as u128 == v => Ok(Scalar::Bits { bits: v, defined: 32 }),
             TyChar => err!(InvalidChar(v)),
 
             // No alignment check needed for raw pointers.  But we have to truncate to target ptr size.
             TyRawPtr(_) => {
-                Ok(Scalar::Bytes(self.memory.truncate_to_ptr(v).0 as u128))
+                Ok(Scalar::Bits {
+                    bits: self.memory.truncate_to_ptr(v).0 as u128,
+                    defined: self.memory.pointer_size().bits() as u8,
+                })
             },
 
             // Casts to bool are not permitted by rustc, no need to handle them here.
@@ -75,28 +94,53 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             TyUint(t) => {
                 let width = t.bit_width().unwrap_or(self.memory.pointer_size().bytes() as usize * 8);
                 match fty {
-                    FloatTy::F32 => Ok(Scalar::Bytes(Single::from_bits(bits).to_u128(width).value)),
-                    FloatTy::F64 => Ok(Scalar::Bytes(Double::from_bits(bits).to_u128(width).value)),
+                    FloatTy::F32 => Ok(Scalar::Bits {
+                        bits: Single::from_bits(bits).to_u128(width).value,
+                        defined: 32,
+                    }),
+                    FloatTy::F64 => Ok(Scalar::Bits {
+                        bits: Double::from_bits(bits).to_u128(width).value,
+                        defined: 64,
+                    }),
                 }
             },
             // float -> int
             TyInt(t) => {
                 let width = t.bit_width().unwrap_or(self.memory.pointer_size().bytes() as usize * 8);
                 match fty {
-                    FloatTy::F32 => Ok(Scalar::from_i128(Single::from_bits(bits).to_i128(width).value)),
-                    FloatTy::F64 => Ok(Scalar::from_i128(Double::from_bits(bits).to_i128(width).value)),
+                    FloatTy::F32 => Ok(Scalar::Bits {
+                        bits: Single::from_bits(bits).to_i128(width).value as u128,
+                        defined: 32,
+                    }),
+                    FloatTy::F64 => Ok(Scalar::Bits {
+                        bits: Double::from_bits(bits).to_i128(width).value as u128,
+                        defined: 64,
+                    }),
                 }
             },
             // f64 -> f32
             TyFloat(FloatTy::F32) if fty == FloatTy::F64 => {
-                Ok(Scalar::Bytes(Single::to_bits(Double::from_bits(bits).convert(&mut false).value)))
+                Ok(Scalar::Bits {
+                    bits: Single::to_bits(Double::from_bits(bits).convert(&mut false).value),
+                    defined: 32,
+                })
             },
             // f32 -> f64
             TyFloat(FloatTy::F64) if fty == FloatTy::F32 => {
-                Ok(Scalar::Bytes(Double::to_bits(Single::from_bits(bits).convert(&mut false).value)))
+                Ok(Scalar::Bits {
+                    bits: Double::to_bits(Single::from_bits(bits).convert(&mut false).value),
+                    defined: 64,
+                })
             },
             // identity cast
-            TyFloat(_) => Ok(Scalar::Bytes(bits)),
+            TyFloat(FloatTy:: F64) => Ok(Scalar::Bits {
+                bits,
+                defined: 64,
+            }),
+            TyFloat(FloatTy:: F32) => Ok(Scalar::Bits {
+                bits,
+                defined: 32,
+            }),
             _ => err!(Unimplemented(format!("float to {:?} cast", dest_ty))),
         }
     }
diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs
index 729e900492a..14de0e14cd4 100644
--- a/src/librustc_mir/interpret/const_eval.rs
+++ b/src/librustc_mir/interpret/const_eval.rs
@@ -100,7 +100,7 @@ pub fn value_to_const_value<'tcx>(
 ) -> &'tcx ty::Const<'tcx> {
     let layout = ecx.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap();
     match (val, &layout.abi) {
-        (Value::Scalar(Scalar::Undef), _) if layout.is_zst() => {},
+        (Value::Scalar(Scalar::Bits { defined: 0, ..}), _) if layout.is_zst() => {},
         (Value::ByRef(..), _) |
         (Value::Scalar(_), &layout::Abi::Scalar(_)) |
         (Value::ScalarPair(..), &layout::Abi::ScalarPair(..)) => {},
@@ -319,20 +319,31 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
             "min_align_of" => {
                 let elem_ty = substs.type_at(0);
                 let elem_align = ecx.layout_of(elem_ty)?.align.abi();
-                let align_val = Scalar::from_u128(elem_align as u128);
+                let align_val = Scalar::Bits {
+                    bits: elem_align as u128,
+                    defined: dest_layout.size.bits() as u8,
+                };
                 ecx.write_primval(dest, align_val, dest_layout.ty)?;
             }
 
             "size_of" => {
                 let ty = substs.type_at(0);
                 let size = ecx.layout_of(ty)?.size.bytes() as u128;
-                ecx.write_primval(dest, Scalar::from_u128(size), dest_layout.ty)?;
+                let size_val = Scalar::Bits {
+                    bits: size,
+                    defined: dest_layout.size.bits() as u8,
+                };
+                ecx.write_primval(dest, size_val, dest_layout.ty)?;
             }
 
             "type_id" => {
                 let ty = substs.type_at(0);
                 let type_id = ecx.tcx.type_id_hash(ty) as u128;
-                ecx.write_primval(dest, Scalar::from_u128(type_id), dest_layout.ty)?;
+                let id_val = Scalar::Bits {
+                    bits: type_id,
+                    defined: dest_layout.size.bits() as u8,
+                };
+                ecx.write_primval(dest, id_val, dest_layout.ty)?;
             }
 
             name => return Err(ConstEvalError::NeedsRfc(format!("calling intrinsic `{}`", name)).into()),
@@ -354,7 +365,7 @@ impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
         right: Scalar,
         _right_ty: Ty<'tcx>,
     ) -> EvalResult<'tcx, Option<(Scalar, bool)>> {
-        if left.is_bytes() && right.is_bytes() {
+        if left.is_bits() && right.is_bits() {
             Ok(None)
         } else {
             Err(
diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs
index 40d997126c8..5e03e759af9 100644
--- a/src/librustc_mir/interpret/eval_context.rs
+++ b/src/librustc_mir/interpret/eval_context.rs
@@ -232,7 +232,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
         let ptr = self.memory.allocate_bytes(s.as_bytes());
         Ok(Value::ScalarPair(
             Scalar::Ptr(ptr),
-            Scalar::from_u128(s.len() as u128),
+            Scalar::Bits {
+                bits: s.len() as u128,
+                defined: self.tcx.data_layout.pointer_size.bits() as u8,
+            },
         ))
     }
 
@@ -408,7 +411,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
         ::log_settings::settings().indentation += 1;
 
         let locals = if mir.local_decls.len() > 1 {
-            let mut locals = IndexVec::from_elem(Some(Value::Scalar(Scalar::Undef)), &mir.local_decls);
+            let mut locals = IndexVec::from_elem(Some(Value::Scalar(Scalar::undef())), &mir.local_decls);
             match self.tcx.describe_def(instance.def_id()) {
                 // statics and constants don't have `Storage*` statements, no need to look for them
                 Some(Def::Static(..)) | Some(Def::Const(..)) | Some(Def::AssociatedConst(..)) => {},
@@ -606,9 +609,13 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
                 let src = self.eval_place(place)?;
                 let ty = self.place_ty(place);
                 let (_, len) = src.elem_ty_and_len(ty, self.tcx.tcx);
+                let defined = self.memory.pointer_size().bits() as u8;
                 self.write_primval(
                     dest,
-                    Scalar::from_u128(len as u128),
+                    Scalar::Bits {
+                        bits: len as u128,
+                        defined,
+                    },
                     dest_ty,
                 )?;
             }
@@ -621,7 +628,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
 
                 let val = match extra {
                     PlaceExtra::None => ptr.to_value(),
-                    PlaceExtra::Length(len) => ptr.to_value_with_len(len),
+                    PlaceExtra::Length(len) => ptr.to_value_with_len(len, self.tcx.tcx),
                     PlaceExtra::Vtable(vtable) => ptr.to_value_with_vtable(vtable),
                     PlaceExtra::DowncastVariant(..) => {
                         bug!("attempted to take a reference to an enum downcast place")
@@ -644,9 +651,13 @@ impl<'a, 'mir, 'tcx: 'mir, 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 defined = self.memory.pointer_size().bits() as u8;
                 self.write_primval(
                     dest,
-                    Scalar::from_u128(layout.size.bytes() as u128),
+                    Scalar::Bits {
+                        bits: layout.size.bytes() as u128,
+                        defined,
+                    },
                     dest_ty,
                 )?;
             }
@@ -694,9 +705,16 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
                                         let discr_val = def
                                             .discriminant_for_variant(*self.tcx, index)
                                             .val;
+                                        let defined = dest_ty
+                                                    .scalar_size(self.tcx.tcx)
+                                                    .expect("can only cast variants to ints")
+                                                    .bits() as u8;
                                         return self.write_primval(
                                             dest,
-                                            Scalar::Bytes(discr_val),
+                                            Scalar::Bits {
+                                                bits: discr_val,
+                                                defined,
+                                            },
                                             dest_ty);
                                     }
                                 }
@@ -780,7 +798,11 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
                 let ty = self.place_ty(place);
                 let place = self.eval_place(place)?;
                 let discr_val = self.read_discriminant_value(place, ty)?;
-                self.write_primval(dest, Scalar::Bytes(discr_val), dest_ty)?;
+                let defined = ty.scalar_size(self.tcx.tcx).expect("discriminant must be scalar").bits() as u8;
+                self.write_primval(dest, Scalar::Bits {
+                    bits: discr_val,
+                    defined,
+                }, dest_ty)?;
             }
         }
 
@@ -910,7 +932,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
             // FIXME: should we catch invalid discriminants here?
             layout::Variants::Tagged { .. } => {
                 if discr.ty.is_signed() {
-                    let i = raw_discr.to_bytes()? as i128;
+                    let i = raw_discr.to_bits(discr.size)? as i128;
                     // going from layout tag type to typeck discriminant type
                     // requires first sign extending with the layout discriminant
                     let amt = 128 - discr.size.bits();
@@ -925,7 +947,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
                     let truncatee = sexted as u128;
                     (truncatee << amt) >> amt
                 } else {
-                    raw_discr.to_bytes()?
+                    raw_discr.to_bits(discr.size)?
                 }
             },
             layout::Variants::NicheFilling {
@@ -942,7 +964,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
                         assert!(variants_start == variants_end);
                         dataful_variant as u128
                     },
-                    Scalar::Bytes(raw_discr) => {
+                    Scalar::Bits { bits: raw_discr, defined } => {
+                        if defined < discr.size.bits() as u8 {
+                            return err!(ReadUndefBytes);
+                        }
                         let discr = raw_discr.wrapping_sub(niche_start)
                             .wrapping_add(variants_start);
                         if variants_start <= discr && discr <= variants_end {
@@ -951,7 +976,6 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
                             dataful_variant as u128
                         }
                     },
-                    Scalar::Undef => return err!(ReadUndefBytes),
                 }
             }
         };
@@ -990,7 +1014,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
                 let discr_val = (discr_val << amt) >> amt;
 
                 let (discr_dest, tag) = self.place_field(dest, mir::Field::new(0), layout)?;
-                self.write_primval(discr_dest, Scalar::Bytes(discr_val), tag.ty)?;
+                self.write_primval(discr_dest, Scalar::Bits {
+                    bits: discr_val,
+                    defined: size as u8,
+                }, tag.ty)?;
             }
             layout::Variants::NicheFilling {
                 dataful_variant,
@@ -1003,7 +1030,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
                         self.place_field(dest, mir::Field::new(0), layout)?;
                     let niche_value = ((variant_index - niche_variants.start()) as u128)
                         .wrapping_add(niche_start);
-                    self.write_primval(niche_dest, Scalar::Bytes(niche_value), niche.ty)?;
+                    self.write_primval(niche_dest, Scalar::Bits {
+                        bits: niche_value,
+                        defined: niche.size.bits() as u8,
+                    }, niche.ty)?;
                 }
             }
         }
@@ -1216,8 +1246,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
                         layout::Primitive::Int(_, signed) => signed,
                         _ => false,
                     },
-                    _ if primval.is_undef() => false,
-                    _ => bug!("write_value_to_ptr: invalid ByVal layout: {:#?}", layout)
+                    _ => match primval {
+                        Scalar::Bits { defined: 0, .. } => false,
+                        _ => bug!("write_value_to_ptr: invalid ByVal layout: {:#?}", layout),
+                    }
                 };
                 self.memory.write_primval(dest, dest_align, primval, layout.size, signed)
             }
@@ -1308,10 +1340,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
 
     fn ensure_valid_value(&self, val: Scalar, ty: Ty<'tcx>) -> EvalResult<'tcx> {
         match ty.sty {
-            ty::TyBool if val.to_bytes()? > 1 => err!(InvalidBool),
+            ty::TyBool => val.to_bool().map(|_| ()),
 
-            ty::TyChar if ::std::char::from_u32(val.to_bytes()? as u32).is_none() => {
-                err!(InvalidChar(val.to_bytes()? as u32 as u128))
+            ty::TyChar if ::std::char::from_u32(val.to_bits(Size::from_bytes(4))? as u32).is_none() => {
+                err!(InvalidChar(val.to_bits(Size::from_bytes(4))? as u32 as u128))
             }
 
             _ => Ok(()),
@@ -1347,8 +1379,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
                     let len = self
                         .memory
                         .read_ptr_sized(extra, ptr_align)?
-                        .to_bytes()?;
-                    Ok(p.to_value_with_len(len as u64))
+                        .to_bits(ptr_size)?;
+                    Ok(p.to_value_with_len(len as u64, self.tcx.tcx))
                 },
                 _ => bug!("unsized primval ptr read from {:?}", pointee_ty),
             }
@@ -1363,15 +1395,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
     ) -> EvalResult<'tcx> {
         match ty.sty {
             ty::TyBool => {
-                let val = self.memory.read_primval(ptr, ptr_align, Size::from_bytes(1))?;
-                match val {
-                    Scalar::Bytes(0) | Scalar::Bytes(1) => (),
-                    // TODO: This seems a little overeager, should reading at bool type already be insta-UB?
-                    _ => return err!(InvalidBool),
-                }
+                self.memory.read_primval(ptr, ptr_align, Size::from_bytes(1))?.to_bool()?;
             }
             ty::TyChar => {
-                let c = self.memory.read_primval(ptr, ptr_align, Size::from_bytes(4))?.to_bytes()? as u32;
+                let c = self.memory.read_primval(ptr, ptr_align, Size::from_bytes(4))?.to_bits(Size::from_bytes(4))? as u32;
                 match ::std::char::from_u32(c) {
                     Some(..) => (),
                     None => return err!(InvalidChar(c as u128)),
@@ -1418,7 +1445,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
         self.memory.check_align(ptr, ptr_align)?;
 
         if layout.size.bytes() == 0 {
-            return Ok(Some(Value::Scalar(Scalar::Undef)));
+            return Ok(Some(Value::Scalar(Scalar::undef())));
         }
 
         let ptr = ptr.to_ptr()?;
@@ -1482,7 +1509,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M
                 let ptr = self.into_ptr(src)?;
                 // u64 cast is from usize to u64, which is always good
                 let valty = ValTy {
-                    value: ptr.to_value_with_len(length.unwrap_usize(self.tcx.tcx)),
+                    value: ptr.to_value_with_len(length.unwrap_usize(self.tcx.tcx), self.tcx.tcx),
                     ty: dest_ty,
                 };
                 self.write_value(valty, dest)
@@ -1796,7 +1823,7 @@ impl<'mir, 'tcx> Frame<'mir, 'tcx> {
         trace!("{:?} is now live", local);
 
         // StorageLive *always* kills the value that's currently stored
-        mem::replace(&mut self.locals[local], Some(Value::Scalar(Scalar::Undef)))
+        mem::replace(&mut self.locals[local], Some(Value::Scalar(Scalar::undef())))
     }
 
     /// Returns the old value of the local
diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs
index a929459f9bd..e0a12e5e9a4 100644
--- a/src/librustc_mir/interpret/memory.rs
+++ b/src/librustc_mir/interpret/memory.rs
@@ -232,15 +232,18 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
                 let alloc = self.get(ptr.alloc_id)?;
                 (ptr.offset.bytes(), alloc.align)
             }
-            Scalar::Bytes(bytes) => {
-                let v = ((bytes as u128) % (1 << self.pointer_size().bytes())) as u64;
+            Scalar::Bits { bits, defined } => {
+                if defined <= self.pointer_size().bits() as u8 {
+                    return err!(ReadUndefBytes);
+                }
+                // FIXME: what on earth does this line do? docs or fix needed!
+                let v = ((bits as u128) % (1 << self.pointer_size().bytes())) as u64;
                 if v == 0 {
                     return err!(InvalidNullPointerUsage);
                 }
                 // the base address if the "integer allocation" is 0 and hence always aligned
                 (v, required_align)
             }
-            Scalar::Undef => return err!(ReadUndefBytes),
         };
         // Check alignment
         if alloc_align.abi() < required_align.abi() {
@@ -711,10 +714,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         // Undef check happens *after* we established that the alignment is correct.
         // We must not return Ok() for unaligned pointers!
         if self.check_defined(ptr, size).is_err() {
-            return Ok(Scalar::Undef.into());
+            return Ok(Scalar::undef().into());
         }
         // Now we do the actual reading
-        let bytes = read_target_uint(endianness, bytes).unwrap();
+        let bits = read_target_uint(endianness, bytes).unwrap();
         // See if we got a pointer
         if size != self.pointer_size() {
             if self.relocations(ptr, size)?.len() != 0 {
@@ -723,12 +726,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
         } else {
             let alloc = self.get(ptr.alloc_id)?;
             match alloc.relocations.get(&ptr.offset) {
-                Some(&alloc_id) => return Ok(Pointer::new(alloc_id, Size::from_bytes(bytes as u64)).into()),
+                Some(&alloc_id) => return Ok(Pointer::new(alloc_id, Size::from_bytes(bits as u64)).into()),
                 None => {},
             }
         }
-        // We don't. Just return the bytes.
-        Ok(Scalar::Bytes(bytes))
+        // We don't. Just return the bits.
+        Ok(Scalar::Bits {
+            bits,
+            defined: size.bits() as u8,
+        })
     }
 
     pub fn read_ptr_sized(&self, ptr: Pointer, ptr_align: Align) -> EvalResult<'tcx, Scalar> {
@@ -744,9 +750,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> {
                 val.offset.bytes() as u128
             }
 
-            Scalar::Bytes(bytes) => bytes,
+            Scalar::Bits { bits, defined } if defined >= size.bits() as u8 && defined != 0 => bits,
 
-            Scalar::Undef => {
+            Scalar::Bits { .. } => {
                 self.check_align(ptr.into(), ptr_align)?;
                 self.mark_definedness(ptr, size, false)?;
                 return Ok(());
@@ -951,7 +957,7 @@ pub trait HasMemory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
 
             Value::ScalarPair(ptr, vtable) => Ok((ptr.into(), vtable.to_ptr()?)),
 
-            Value::Scalar(Scalar::Undef) => err!(ReadUndefBytes),
+            Value::Scalar(Scalar::Bits { defined: 0, .. }) => err!(ReadUndefBytes),
             _ => bug!("expected ptr and vtable, got {:?}", value),
         }
     }
@@ -967,15 +973,14 @@ pub trait HasMemory<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
                 let len = mem.read_ptr_sized(
                     ref_ptr.ptr_offset(mem.pointer_size(), &mem.tcx.data_layout)?.to_ptr()?,
                     align
-                )?.to_bytes()? as u64;
+                )?.to_bits(mem.pointer_size())? as u64;
                 Ok((ptr, len))
             }
             Value::ScalarPair(ptr, val) => {
-                let len = val.to_u128()?;
-                assert_eq!(len as u64 as u128, len);
+                let len = val.to_bits(self.memory().pointer_size())?;
                 Ok((ptr.into(), len as u64))
             }
-            Value::Scalar(Scalar::Undef) => err!(ReadUndefBytes),
+            Value::Scalar(Scalar::Bits { defined: 0, .. }) => err!(ReadUndefBytes),
             Value::Scalar(_) => bug!("expected ptr and length, got {:?}", value),
         }
     }
diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs
index 8e8b9466596..fff8da78dc1 100644
--- a/src/librustc_mir/interpret/operator.rs
+++ b/src/librustc_mir/interpret/operator.rs
@@ -79,11 +79,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             }
         }
 
-        // II: From now on, everything must be bytes, no pointers
-        let l = left.to_bytes()?;
-        let r = right.to_bytes()?;
-
         let left_layout = self.layout_of(left_ty)?;
+        let right_layout = self.layout_of(right_ty)?;
+
+        // II: From now on, everything must be bytes, no pointers
+        let l = left.to_bits(left_layout.size)?;
+        let r = right.to_bits(right_layout.size)?;
 
         // These ops can have an RHS with a different numeric type.
         if right_kind.is_int() && (bin_op == Shl || bin_op == Shr) {
@@ -110,7 +111,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 }
             };
             let truncated = self.truncate(result, left_ty)?;
-            return Ok((Scalar::Bytes(truncated), oflo));
+            return Ok((Scalar::Bits {
+                bits: truncated,
+                defined: size as u8,
+            }, oflo));
         }
 
         if left_kind != right_kind {
@@ -156,7 +160,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 - 1)) {
-                            return Ok((Scalar::Bytes(l), true));
+                            return Ok((Scalar::Bits { bits: l, defined: size as u8 }, true));
                         }
                     },
                     _ => {},
@@ -170,15 +174,22 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 }
                 let result = result as u128;
                 let truncated = self.truncate(result, left_ty)?;
-                return Ok((Scalar::Bytes(truncated), oflo));
+                return Ok((Scalar::Bits {
+                    bits: truncated,
+                    defined: size as u8,
+                }, oflo));
             }
         }
 
         if let ty::TyFloat(fty) = left_ty.sty {
             macro_rules! float_math {
-                ($ty:path) => {{
+                ($ty:path, $bitsize: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(),
+                        defined: $bitsize,
+                    };
                     let val = match bin_op {
                         Eq => Scalar::from_bool(l == r),
                         Ne => Scalar::from_bool(l != r),
@@ -186,22 +197,24 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                         Le => Scalar::from_bool(l <= r),
                         Gt => Scalar::from_bool(l > r),
                         Ge => Scalar::from_bool(l >= r),
-                        Add => Scalar::Bytes((l + r).value.to_bits()),
-                        Sub => Scalar::Bytes((l - r).value.to_bits()),
-                        Mul => Scalar::Bytes((l * r).value.to_bits()),
-                        Div => Scalar::Bytes((l / r).value.to_bits()),
-                        Rem => Scalar::Bytes((l % r).value.to_bits()),
+                        Add => bitify(l + r),
+                        Sub => bitify(l - r),
+                        Mul => bitify(l * r),
+                        Div => bitify(l / r),
+                        Rem => bitify(l % r),
                         _ => bug!("invalid float op: `{:?}`", bin_op),
                     };
                     return Ok((val, false));
                 }};
             }
             match fty {
-                FloatTy::F32 => float_math!(Single),
-                FloatTy::F64 => float_math!(Double),
+                FloatTy::F32 => float_math!(Single, 32),
+                FloatTy::F64 => float_math!(Double, 64),
             }
         }
 
+        let bitsize = left_ty.scalar_size(self).expect("operator type must be scalar").bits() as u8;
+
         // only ints left
         let val = match bin_op {
             Eq => Scalar::from_bool(l == r),
@@ -212,9 +225,9 @@ 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::Bytes(l | r),
-            BitAnd => Scalar::Bytes(l & r),
-            BitXor => Scalar::Bytes(l ^ r),
+            BitOr => Scalar::Bits { bits: l | r, defined: bitsize },
+            BitAnd => Scalar::Bits { bits: l & r, defined: bitsize },
+            BitXor => Scalar::Bits { bits: l ^ r, defined: bitsize },
 
             Add | Sub | Mul | Rem | Div => {
                 let op: fn(u128, u128) -> (u128, bool) = match bin_op {
@@ -229,7 +242,10 @@ 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_ty)?;
-                return Ok((Scalar::Bytes(truncated), oflo || truncated != result));
+                return Ok((Scalar::Bits {
+                    bits: truncated,
+                    defined: bitsize,
+                }, oflo || truncated != result));
             }
 
             _ => {
@@ -258,8 +274,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         use rustc_apfloat::ieee::{Single, Double};
         use rustc_apfloat::Float;
 
-        let bytes = val.to_bytes()?;
-        let size = self.layout_of(ty)?.size.bits();
+        let size = self.layout_of(ty)?.size;
+        let bytes = val.to_bits(size)?;
+        let size = size.bits();
 
         let result_bytes = match (un_op, &ty.sty) {
 
@@ -274,6 +291,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             (Neg, _) => (-(bytes as i128)) as u128,
         };
 
-        Ok(Scalar::Bytes(self.truncate(result_bytes, ty)?))
+        Ok(Scalar::Bits {
+            bits: self.truncate(result_bytes, ty)?,
+            defined: size as u8,
+        })
     }
 }
diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs
index 9d51fcce7c7..1f4925a0ab2 100644
--- a/src/librustc_mir/interpret/place.rs
+++ b/src/librustc_mir/interpret/place.rs
@@ -35,7 +35,7 @@ pub enum PlaceExtra {
 impl<'tcx> Place {
     /// Produces a Place that will error if attempted to be read from
     pub fn undef() -> Self {
-        Self::from_primval_ptr(Scalar::Undef.into(), Align::from_bytes(1, 1).unwrap())
+        Self::from_primval_ptr(Scalar::undef().into(), Align::from_bytes(1, 1).unwrap())
     }
 
     pub fn from_primval_ptr(ptr: Scalar, align: Align) -> Self {
@@ -128,7 +128,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         let field_index = field.index();
         let field = base_layout.field(self, field_index)?;
         if field.size.bytes() == 0 {
-            return Ok(Some((Value::Scalar(Scalar::Undef), field.ty)))
+            return Ok(Some((Value::Scalar(Scalar::undef()), field.ty)))
         }
         let offset = base_layout.fields.offset(field_index);
         match base {
@@ -387,8 +387,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
             Index(local) => {
                 let value = self.frame().get_local(local)?;
                 let ty = self.tcx.types.usize;
-                let n = self.value_to_primval(ValTy { value, ty })?.to_u64()?;
-                self.place_index(base, base_ty, n)
+                let n = self
+                    .value_to_primval(ValTy { value, ty })?
+                    .to_bits(self.tcx.data_layout.pointer_size)?;
+                self.place_index(base, base_ty, n as u64)
             }
 
             ConstantIndex {
diff --git a/src/librustc_mir/interpret/terminator/drop.rs b/src/librustc_mir/interpret/terminator/drop.rs
index d68cc7d10dc..c0fafa7f83e 100644
--- a/src/librustc_mir/interpret/terminator/drop.rs
+++ b/src/librustc_mir/interpret/terminator/drop.rs
@@ -28,7 +28,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 ptr,
                 align: _,
                 extra: PlaceExtra::Length(len),
-            } => ptr.to_value_with_len(len),
+            } => ptr.to_value_with_len(len, self.tcx.tcx),
             Place::Ptr {
                 ptr,
                 align: _,
diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs
index 2009d638a3f..8493a0849df 100644
--- a/src/librustc_mir/interpret/terminator/mod.rs
+++ b/src/librustc_mir/interpret/terminator/mod.rs
@@ -44,7 +44,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                 let mut target_block = targets[targets.len() - 1];
 
                 for (index, &const_int) in values.iter().enumerate() {
-                    if discr_prim.to_bytes()? == const_int {
+                    if discr_prim.to_bits(discr_val.ty.scalar_size(self.tcx.tcx).expect("discr must be scalar"))? == const_int {
                         target_block = targets[index];
                         break;
                     }
@@ -153,10 +153,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                         BoundsCheck { ref len, ref index } => {
                             let len = self.eval_operand_to_primval(len)
                                 .expect("can't eval len")
-                                .to_u64()?;
+                                .to_bits(self.memory().pointer_size())? as u64;
                             let index = self.eval_operand_to_primval(index)
                                 .expect("can't eval index")
-                                .to_u64()?;
+                                .to_bits(self.memory().pointer_size())? as u64;
                             err!(BoundsCheck { len, index })
                         }
                         Overflow(op) => Err(Overflow(op).into()),
@@ -359,7 +359,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
                                             self.write_value(valty, dest)?;
                                         }
                                     }
-                                    Value::Scalar(Scalar::Undef) => {}
+                                    Value::Scalar(Scalar::Bits { defined: 0, .. }) => {}
                                     other => {
                                         trace!("{:#?}, {:#?}", other, layout);
                                         let mut layout = layout;
diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs
index c94592cf159..373a0b0d0bf 100644
--- a/src/librustc_mir/interpret/traits.rs
+++ b/src/librustc_mir/interpret/traits.rs
@@ -38,9 +38,15 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
         self.memory.write_ptr_sized_unsigned(vtable, ptr_align, drop.into())?;
 
         let size_ptr = vtable.offset(ptr_size, &self)?;
-        self.memory.write_ptr_sized_unsigned(size_ptr, ptr_align, Scalar::Bytes(size as u128))?;
+        self.memory.write_ptr_sized_unsigned(size_ptr, ptr_align, Scalar::Bits {
+            bits: size as u128,
+            defined: ptr_size.bits() as u8,
+        })?;
         let align_ptr = vtable.offset(ptr_size * 2, &self)?;
-        self.memory.write_ptr_sized_unsigned(align_ptr, ptr_align, Scalar::Bytes(align as u128))?;
+        self.memory.write_ptr_sized_unsigned(align_ptr, ptr_align, Scalar::Bits {
+            bits: align as u128,
+            defined: ptr_size.bits() as u8,
+        })?;
 
         for (i, method) in methods.iter().enumerate() {
             if let Some((def_id, substs)) = *method {
@@ -65,9 +71,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
     ) -> EvalResult<'tcx, Option<ty::Instance<'tcx>>> {
         // we don't care about the pointee type, we just want a pointer
         let pointer_align = self.tcx.data_layout.pointer_align;
+        let pointer_size = self.tcx.data_layout.pointer_size.bits() as u8;
         match self.read_ptr(vtable, pointer_align, self.tcx.mk_nil_ptr())? {
             // some values don't need to call a drop impl, so the value is null
-            Value::Scalar(Scalar::Bytes(0)) => Ok(None),
+            Value::Scalar(Scalar::Bits { bits: 0, defined} ) if defined == pointer_size => Ok(None),
             Value::Scalar(Scalar::Ptr(drop_fn)) => self.memory.get_fn(drop_fn).map(Some),
             _ => err!(ReadBytesAsPointer),
         }
@@ -79,11 +86,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
     ) -> EvalResult<'tcx, (Size, Align)> {
         let pointer_size = self.memory.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_bytes()? as u64;
+        let size = self.memory.read_ptr_sized(vtable.offset(pointer_size, self)?, pointer_align)?.to_bits(pointer_size)? as u64;
         let align = self.memory.read_ptr_sized(
             vtable.offset(pointer_size * 2, self)?,
             pointer_align
-        )?.to_bytes()? as u64;
+        )?.to_bits(pointer_size)? as u64;
         Ok((Size::from_bytes(size), Align::from_bytes(align, align).unwrap()))
     }
 }
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 82979284b11..d9d9104c939 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -283,7 +283,10 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
             Rvalue::NullaryOp(NullOp::SizeOf, ty) => {
                 let param_env = self.tcx.param_env(self.source.def_id);
                 type_size_of(self.tcx, param_env, ty).map(|n| (
-                    Value::Scalar(Scalar::Bytes(n as u128)),
+                    Value::Scalar(Scalar::Bits {
+                        bits: n as u128,
+                        defined: self.tcx.data_layout.pointer_size.bits() as u8,
+                    }),
                     self.tcx.types.usize,
                     span,
                 ))
@@ -326,10 +329,10 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
                     this.ecx.value_to_primval(ValTy { value: right.0, ty: right.1 })
                 })?;
                 if op == BinOp::Shr || op == BinOp::Shl {
-                    let param_env = self.tcx.param_env(self.source.def_id);
                     let left_ty = left.ty(self.mir, self.tcx);
-                    let bits = self.tcx.layout_of(param_env.and(left_ty)).unwrap().size.bits();
-                    if r.to_bytes().ok().map_or(false, |b| b >= bits as u128) {
+                    let left_bits = left_ty.scalar_size(self.tcx).unwrap().bits();
+                    let right_size = right.1.scalar_size(self.tcx).unwrap();
+                    if r.to_bits(right_size).ok().map_or(false, |b| b >= left_bits as u128) {
                         let scope_info = match self.mir.visibility_scope_info {
                             ClearCrossCrate::Set(ref data) => data,
                             ClearCrossCrate::Clear => return None,
@@ -520,14 +523,14 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
                         BoundsCheck { ref len, ref index } => {
                             let len = self.eval_operand(len).expect("len must be const");
                             let len = match len.0 {
-                                Value::Scalar(Scalar::Bytes(n)) => n,
+                                Value::Scalar(Scalar::Bits { bits, ..}) => bits,
                                 _ => bug!("const len not primitive: {:?}", len),
                             };
                             let index = self
                                 .eval_operand(index)
                                 .expect("index must be const");
                             let index = match index.0 {
-                                Value::Scalar(Scalar::Bytes(n)) => n,
+                                Value::Scalar(Scalar::Bits { bits, .. }) => bits,
                                 _ => bug!("const index not primitive: {:?}", index),
                             };
                             format!(
diff --git a/src/librustc_mir/transform/simplify_branches.rs b/src/librustc_mir/transform/simplify_branches.rs
index 72bee040c06..ce2f5b0fe6a 100644
--- a/src/librustc_mir/transform/simplify_branches.rs
+++ b/src/librustc_mir/transform/simplify_branches.rs
@@ -39,7 +39,7 @@ impl MirPass for SimplifyBranches {
                 TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant {
                     literal: Literal::Value { ref value }, ..
                 }), switch_ty, ref values, ref targets, .. } => {
-                    if let Some(constint) = value.assert_bits(switch_ty) {
+                    if let Some(constint) = value.assert_bits(tcx, switch_ty) {
                         let (otherwise, targets) = targets.split_last().unwrap();
                         let mut ret = TerminatorKind::Goto { target: *otherwise };
                         for (&v, t) in values.iter().zip(targets.iter()) {