From 64a75ecc8014df45b5b875c5820a0406f41ae7bb Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 22 May 2018 10:28:46 +0200 Subject: [PATCH] change `Value::Bytes` to `Value::Bits` --- src/librustc/ich/impls_ty.rs | 23 ++- src/librustc/mir/interpret/value.rs | 160 ++++++++---------- src/librustc/mir/mod.rs | 27 +-- src/librustc/ty/mod.rs | 2 +- src/librustc/ty/sty.rs | 48 ++++-- src/librustc_codegen_llvm/mir/constant.rs | 10 +- src/librustc_mir/build/expr/as_rvalue.rs | 4 +- src/librustc_mir/build/matches/test.rs | 2 +- src/librustc_mir/build/misc.rs | 9 - src/librustc_mir/hair/cx/expr.rs | 3 +- src/librustc_mir/hair/cx/mod.rs | 47 ++--- src/librustc_mir/hair/pattern/_match.rs | 2 +- src/librustc_mir/hair/pattern/mod.rs | 39 +++-- src/librustc_mir/interpret/cast.rs | 80 +++++++-- src/librustc_mir/interpret/const_eval.rs | 21 ++- src/librustc_mir/interpret/eval_context.rs | 87 ++++++---- src/librustc_mir/interpret/memory.rs | 35 ++-- src/librustc_mir/interpret/operator.rs | 64 ++++--- src/librustc_mir/interpret/place.rs | 10 +- src/librustc_mir/interpret/terminator/drop.rs | 2 +- src/librustc_mir/interpret/terminator/mod.rs | 8 +- src/librustc_mir/interpret/traits.rs | 17 +- src/librustc_mir/transform/const_prop.rs | 15 +- .../transform/simplify_branches.rs | 2 +- 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> +for ::mir::interpret::Scalar { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + 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 { - match self.to_primval() { - Some(Scalar::Bytes(val)) => Some(val), - _ => None, - } + pub fn to_bits(&self, size: Size) -> Option { + self.to_primval()?.to_bits(size).ok() } #[inline] pub fn to_ptr(&self) -> Option { - 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(cx: C) -> Self { + Scalar::Bits { + bits: 0, + defined: cx.data_layout().pointer_size.bits() as u8, + } } pub fn ptr_signed_offset(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(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(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(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(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 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(fmt: &mut W, const_val: &ty::Const) -> fmt::Resul pub fn print_miri_value(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( + &self, + cx: C, + ) -> Option { + 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 { + pub fn to_bits(&self, cx: C, ty: Ty<'tcx>) -> Option { 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 { + pub fn assert_bits(&self, cx: C, ty: Ty<'tcx>) -> Option { 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 { - 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 { - 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::().map_err(|_| ())?; let mut f = num.parse::().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::().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>> { // 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()) {