diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs index ca5feaee12ee4..56173dfe304fc 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -2,7 +2,6 @@ use super::{ Pointer, EvalResult, AllocId, ScalarMaybeUndef, write_target_uint, read_target_uint, Scalar, - truncate, }; use crate::ty::layout::{Size, Align}; @@ -382,18 +381,9 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { ScalarMaybeUndef::Undef => return self.mark_definedness(ptr, type_size, false), }; - let bytes = match val { - Scalar::Ptr(val) => { - assert_eq!(type_size, cx.data_layout().pointer_size); - val.offset.bytes() as u128 - } - - Scalar::Bits { bits, size } => { - assert_eq!(size as u64, type_size.bytes()); - debug_assert_eq!(truncate(bits, Size::from_bytes(size.into())), bits, - "Unexpected value of size {} when writing to memory", size); - bits - }, + let bytes = match val.to_bits_or_ptr(type_size, cx) { + Err(val) => val.offset.bytes() as u128, + Ok(data) => data, }; let endian = cx.data_layout().endian; diff --git a/src/librustc/mir/interpret/pointer.rs b/src/librustc/mir/interpret/pointer.rs index 356c4cc16c23c..33c85a6f46e8e 100644 --- a/src/librustc/mir/interpret/pointer.rs +++ b/src/librustc/mir/interpret/pointer.rs @@ -20,30 +20,20 @@ pub trait PointerArithmetic: layout::HasDataLayout { self.data_layout().pointer_size } - //// Trunace the given value to the pointer size; also return whether there was an overflow + /// Helper function: truncate given value-"overflowed flag" pair to pointer size and + /// update "overflowed flag" if there was an overflow. + /// This should be called by all the other methods before returning! #[inline] - fn truncate_to_ptr(&self, val: u128) -> (u64, bool) { + fn truncate_to_ptr(&self, (val, over): (u64, bool)) -> (u64, bool) { + let val = val as u128; let max_ptr_plus_1 = 1u128 << self.pointer_size().bits(); - ((val % max_ptr_plus_1) as u64, val >= max_ptr_plus_1) - } - - #[inline] - fn offset<'tcx>(&self, val: u64, i: u64) -> EvalResult<'tcx, u64> { - let (res, over) = self.overflowing_offset(val, i); - if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) } + ((val % max_ptr_plus_1) as u64, over || val >= max_ptr_plus_1) } #[inline] fn overflowing_offset(&self, val: u64, i: u64) -> (u64, bool) { - let (res, over1) = val.overflowing_add(i); - let (res, over2) = self.truncate_to_ptr(u128::from(res)); - (res, over1 || over2) - } - - #[inline] - fn signed_offset<'tcx>(&self, val: u64, i: i64) -> EvalResult<'tcx, u64> { - let (res, over) = self.overflowing_signed_offset(val, i128::from(i)); - if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) } + let res = val.overflowing_add(i); + self.truncate_to_ptr(res) } // Overflow checking only works properly on the range from -u64 to +u64. @@ -51,14 +41,27 @@ pub trait PointerArithmetic: layout::HasDataLayout { fn overflowing_signed_offset(&self, val: u64, i: i128) -> (u64, bool) { // FIXME: is it possible to over/underflow here? if i < 0 { - // trickery to ensure that i64::min_value() works fine - // this formula only works for true negative values, it panics for zero! + // Trickery to ensure that i64::min_value() works fine: compute n = -i. + // This formula only works for true negative values, it overflows for zero! let n = u64::max_value() - (i as u64) + 1; - val.overflowing_sub(n) + let res = val.overflowing_sub(n); + self.truncate_to_ptr(res) } else { self.overflowing_offset(val, i as u64) } } + + #[inline] + fn offset<'tcx>(&self, val: u64, i: u64) -> EvalResult<'tcx, u64> { + let (res, over) = self.overflowing_offset(val, i); + if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) } + } + + #[inline] + fn signed_offset<'tcx>(&self, val: u64, i: i64) -> EvalResult<'tcx, u64> { + let (res, over) = self.overflowing_signed_offset(val, i128::from(i)); + if over { err!(Overflow(mir::BinOp::Add)) } else { Ok(res) } + } } impl PointerArithmetic for T {} diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 72545f23f8e2b..3aed90c70adf7 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -87,11 +87,11 @@ impl<'tcx> ConstValue<'tcx> { RustcEncodable, RustcDecodable, Hash, HashStable)] pub enum Scalar { /// The raw bytes of a simple value. - Bits { - /// The first `size` bytes are the value. + Raw { + /// The first `size` bytes of `data` are the value. /// Do not try to read less or more bytes than that. The remaining bytes must be 0. + data: u128, size: u8, - bits: u128, }, /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of @@ -108,16 +108,16 @@ impl fmt::Debug for Scalar { match self { Scalar::Ptr(ptr) => write!(f, "{:?}", ptr), - &Scalar::Bits { bits, size } => { + &Scalar::Raw { data, size } => { if size == 0 { - assert_eq!(bits, 0, "ZST value must be 0"); + assert_eq!(data, 0, "ZST value must be 0"); write!(f, "") } else { - assert_eq!(truncate(bits, Size::from_bytes(size as u64)), bits, - "Scalar value {:#x} exceeds size of {} bytes", bits, size); + assert_eq!(truncate(data, Size::from_bytes(size as u64)), data, + "Scalar value {:#x} exceeds size of {} bytes", data, size); // Format as hex number wide enough to fit any value of the given `size`. - // So bits=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014". - write!(f, "0x{:>0width$x}", bits, width=(size*2) as usize) + // So data=20, size=1 will be "0x14", but with size=4 it'll be "0x00000014". + write!(f, "0x{:>0width$x}", data, width=(size*2) as usize) } } } @@ -128,7 +128,7 @@ impl fmt::Display for Scalar { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Scalar::Ptr(_) => write!(f, "a pointer"), - Scalar::Bits { bits, .. } => write!(f, "{}", bits), + Scalar::Raw { data, .. } => write!(f, "{}", data), } } } @@ -138,7 +138,7 @@ impl<'tcx> Scalar<()> { pub fn with_tag(self, new_tag: Tag) -> Scalar { match self { Scalar::Ptr(ptr) => Scalar::Ptr(ptr.with_tag(new_tag)), - Scalar::Bits { bits, size } => Scalar::Bits { bits, size }, + Scalar::Raw { data, size } => Scalar::Raw { data, size }, } } @@ -155,31 +155,31 @@ impl<'tcx, Tag> Scalar { pub fn erase_tag(self) -> Scalar { match self { Scalar::Ptr(ptr) => Scalar::Ptr(ptr.erase_tag()), - Scalar::Bits { bits, size } => Scalar::Bits { bits, size }, + Scalar::Raw { data, size } => Scalar::Raw { data, size }, } } #[inline] pub fn ptr_null(cx: &impl HasDataLayout) -> Self { - Scalar::Bits { - bits: 0, + Scalar::Raw { + data: 0, size: cx.data_layout().pointer_size.bytes() as u8, } } #[inline] pub fn zst() -> Self { - Scalar::Bits { bits: 0, size: 0 } + Scalar::Raw { data: 0, size: 0 } } #[inline] pub fn ptr_offset(self, i: Size, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> { let dl = cx.data_layout(); match self { - Scalar::Bits { bits, size } => { + Scalar::Raw { data, size } => { assert_eq!(size as u64, dl.pointer_size.bytes()); - Ok(Scalar::Bits { - bits: dl.offset(bits as u64, i.bytes())? as u128, + Ok(Scalar::Raw { + data: dl.offset(data as u64, i.bytes())? as u128, size, }) } @@ -191,10 +191,10 @@ impl<'tcx, Tag> Scalar { pub fn ptr_wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self { let dl = cx.data_layout(); match self { - Scalar::Bits { bits, size } => { + Scalar::Raw { data, size } => { assert_eq!(size as u64, dl.pointer_size.bytes()); - Scalar::Bits { - bits: dl.overflowing_offset(bits as u64, i.bytes()).0 as u128, + Scalar::Raw { + data: dl.overflowing_offset(data as u64, i.bytes()).0 as u128, size, } } @@ -206,10 +206,10 @@ impl<'tcx, Tag> Scalar { pub fn ptr_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> EvalResult<'tcx, Self> { let dl = cx.data_layout(); match self { - Scalar::Bits { bits, size } => { + Scalar::Raw { data, size } => { assert_eq!(size as u64, dl.pointer_size().bytes()); - Ok(Scalar::Bits { - bits: dl.signed_offset(bits as u64, i)? as u128, + Ok(Scalar::Raw { + data: dl.signed_offset(data as u64, i)? as u128, size, }) } @@ -221,10 +221,10 @@ impl<'tcx, Tag> Scalar { pub fn ptr_wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self { let dl = cx.data_layout(); match self { - Scalar::Bits { bits, size } => { + Scalar::Raw { data, size } => { assert_eq!(size as u64, dl.pointer_size.bytes()); - Scalar::Bits { - bits: dl.overflowing_signed_offset(bits as u64, i128::from(i)).0 as u128, + Scalar::Raw { + data: dl.overflowing_signed_offset(data as u64, i128::from(i)).0 as u128, size, } } @@ -232,14 +232,14 @@ impl<'tcx, Tag> Scalar { } } - /// Returns this pointers offset from the allocation base, or from NULL (for + /// Returns this pointer's offset from the allocation base, or from NULL (for /// integer pointers). #[inline] pub fn get_ptr_offset(self, cx: &impl HasDataLayout) -> Size { match self { - Scalar::Bits { bits, size } => { + Scalar::Raw { data, size } => { assert_eq!(size as u64, cx.pointer_size().bytes()); - Size::from_bytes(bits as u64) + Size::from_bytes(data as u64) } Scalar::Ptr(ptr) => ptr.offset, } @@ -248,9 +248,9 @@ impl<'tcx, Tag> Scalar { #[inline] pub fn is_null_ptr(self, cx: &impl HasDataLayout) -> bool { match self { - Scalar::Bits { bits, size } => { + Scalar::Raw { data, size } => { assert_eq!(size as u64, cx.data_layout().pointer_size.bytes()); - bits == 0 + data == 0 }, Scalar::Ptr(_) => false, } @@ -258,20 +258,20 @@ impl<'tcx, Tag> Scalar { #[inline] pub fn from_bool(b: bool) -> Self { - Scalar::Bits { bits: b as u128, size: 1 } + Scalar::Raw { data: b as u128, size: 1 } } #[inline] pub fn from_char(c: char) -> Self { - Scalar::Bits { bits: c as u128, size: 4 } + Scalar::Raw { data: c as u128, size: 4 } } #[inline] pub fn from_uint(i: impl Into, size: Size) -> Self { let i = i.into(); - debug_assert_eq!(truncate(i, size), i, + assert_eq!(truncate(i, size), i, "Unsigned value {} does not fit in {} bits", i, size.bits()); - Scalar::Bits { bits: i, size: size.bytes() as u8 } + Scalar::Raw { data: i, size: size.bytes() as u8 } } #[inline] @@ -279,28 +279,51 @@ impl<'tcx, Tag> Scalar { let i = i.into(); // `into` performed sign extension, we have to truncate let truncated = truncate(i as u128, size); - debug_assert_eq!(sign_extend(truncated, size) as i128, i, + assert_eq!(sign_extend(truncated, size) as i128, i, "Signed value {} does not fit in {} bits", i, size.bits()); - Scalar::Bits { bits: truncated, size: size.bytes() as u8 } + Scalar::Raw { data: truncated, size: size.bytes() as u8 } } #[inline] pub fn from_f32(f: f32) -> Self { - Scalar::Bits { bits: f.to_bits() as u128, size: 4 } + Scalar::Raw { data: f.to_bits() as u128, size: 4 } } #[inline] pub fn from_f64(f: f64) -> Self { - Scalar::Bits { bits: f.to_bits() as u128, size: 8 } + Scalar::Raw { data: f.to_bits() as u128, size: 8 } + } + + #[inline] + pub fn to_bits_or_ptr( + self, + target_size: Size, + cx: &impl HasDataLayout, + ) -> Result> { + match self { + Scalar::Raw { data, size } => { + assert_eq!(target_size.bytes(), size as u64); + assert_ne!(size, 0, "to_bits cannot be used with zsts"); + assert_eq!(truncate(data, target_size), data, + "Scalar value {:#x} exceeds size of {} bytes", data, size); + Ok(data) + } + Scalar::Ptr(ptr) => { + assert_eq!(target_size, cx.data_layout().pointer_size); + Err(ptr) + } + } } #[inline] pub fn to_bits(self, target_size: Size) -> EvalResult<'tcx, u128> { match self { - Scalar::Bits { bits, size } => { + Scalar::Raw { data, size } => { assert_eq!(target_size.bytes(), size as u64); assert_ne!(size, 0, "to_bits cannot be used with zsts"); - Ok(bits) + assert_eq!(truncate(data, target_size), data, + "Scalar value {:#x} exceeds size of {} bytes", data, size); + Ok(data) } Scalar::Ptr(_) => err!(ReadPointerAsBytes), } @@ -309,8 +332,8 @@ impl<'tcx, Tag> Scalar { #[inline] pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> { match self { - Scalar::Bits { bits: 0, .. } => err!(InvalidNullPointerUsage), - Scalar::Bits { .. } => err!(ReadBytesAsPointer), + Scalar::Raw { data: 0, .. } => err!(InvalidNullPointerUsage), + Scalar::Raw { .. } => err!(ReadBytesAsPointer), Scalar::Ptr(p) => Ok(p), } } @@ -318,7 +341,7 @@ impl<'tcx, Tag> Scalar { #[inline] pub fn is_bits(self) -> bool { match self { - Scalar::Bits { .. } => true, + Scalar::Raw { .. } => true, _ => false, } } @@ -333,8 +356,8 @@ impl<'tcx, Tag> Scalar { pub fn to_bool(self) -> EvalResult<'tcx, bool> { match self { - Scalar::Bits { bits: 0, size: 1 } => Ok(false), - Scalar::Bits { bits: 1, size: 1 } => Ok(true), + Scalar::Raw { data: 0, size: 1 } => Ok(false), + Scalar::Raw { data: 1, size: 1 } => Ok(true), _ => err!(InvalidBool), } } @@ -350,27 +373,23 @@ impl<'tcx, Tag> Scalar { pub fn to_u8(self) -> EvalResult<'static, u8> { let sz = Size::from_bits(8); let b = self.to_bits(sz)?; - assert_eq!(b as u8 as u128, b); Ok(b as u8) } pub fn to_u32(self) -> EvalResult<'static, u32> { let sz = Size::from_bits(32); let b = self.to_bits(sz)?; - assert_eq!(b as u32 as u128, b); Ok(b as u32) } pub fn to_u64(self) -> EvalResult<'static, u64> { let sz = Size::from_bits(64); let b = self.to_bits(sz)?; - assert_eq!(b as u64 as u128, b); Ok(b as u64) } pub fn to_usize(self, cx: &impl HasDataLayout) -> EvalResult<'static, u64> { let b = self.to_bits(cx.data_layout().pointer_size)?; - assert_eq!(b as u64 as u128, b); Ok(b as u64) } @@ -378,7 +397,6 @@ impl<'tcx, Tag> Scalar { let sz = Size::from_bits(8); let b = self.to_bits(sz)?; let b = sign_extend(b, sz) as i128; - assert_eq!(b as i8 as i128, b); Ok(b as i8) } @@ -386,7 +404,6 @@ impl<'tcx, Tag> Scalar { let sz = Size::from_bits(32); let b = self.to_bits(sz)?; let b = sign_extend(b, sz) as i128; - assert_eq!(b as i32 as i128, b); Ok(b as i32) } @@ -394,14 +411,13 @@ impl<'tcx, Tag> Scalar { let sz = Size::from_bits(64); let b = self.to_bits(sz)?; let b = sign_extend(b, sz) as i128; - assert_eq!(b as i64 as i128, b); Ok(b as i64) } pub fn to_isize(self, cx: &impl HasDataLayout) -> EvalResult<'static, i64> { - let b = self.to_bits(cx.data_layout().pointer_size)?; - let b = sign_extend(b, cx.data_layout().pointer_size) as i128; - assert_eq!(b as i64 as i128, b); + let sz = cx.data_layout().pointer_size; + let b = self.to_bits(sz)?; + let b = sign_extend(b, sz) as i128; Ok(b as i64) } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 84aff8101a09d..e2a8cd6b17df6 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1669,10 +1669,7 @@ impl<'tcx> TerminatorKind<'tcx> { .map(|&u| { tcx.mk_const(ty::Const { val: ConstValue::Scalar( - Scalar::Bits { - bits: u, - size: size.bytes() as u8, - }.into(), + Scalar::from_uint(u, size).into(), ), ty: switch_ty, }).to_string().into() diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index a56fe7d7003a1..92de3e28d1903 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1001,7 +1001,7 @@ impl<'tcx> CommonConsts<'tcx> { CommonConsts { err: mk_const(ty::Const { - val: ConstValue::Scalar(Scalar::Bits { bits: 0, size: 0 }), + val: ConstValue::Scalar(Scalar::zst()), ty: types.err, }), } diff --git a/src/librustc/ty/print/pretty.rs b/src/librustc/ty/print/pretty.rs index 6726563331844..eae05bab2a435 100644 --- a/src/librustc/ty/print/pretty.rs +++ b/src/librustc/ty/print/pretty.rs @@ -845,22 +845,22 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>: p!(write("{}", name)); return Ok(self); } - if let ConstValue::Scalar(Scalar::Bits { bits, .. }) = ct.val { + if let ConstValue::Scalar(Scalar::Raw { data, .. }) = ct.val { match ct.ty.sty { ty::Bool => { - p!(write("{}", if bits == 0 { "false" } else { "true" })); + p!(write("{}", if data == 0 { "false" } else { "true" })); return Ok(self); }, ty::Float(ast::FloatTy::F32) => { - p!(write("{}f32", Single::from_bits(bits))); + p!(write("{}f32", Single::from_bits(data))); return Ok(self); }, ty::Float(ast::FloatTy::F64) => { - p!(write("{}f64", Double::from_bits(bits))); + p!(write("{}f64", Double::from_bits(data))); return Ok(self); }, ty::Uint(ui) => { - p!(write("{}{}", bits, ui)); + p!(write("{}{}", data, ui)); return Ok(self); }, ty::Int(i) =>{ @@ -868,11 +868,11 @@ pub trait PrettyPrinter<'gcx: 'tcx, 'tcx>: let size = self.tcx().layout_of(ty::ParamEnv::empty().and(ty)) .unwrap() .size; - p!(write("{}{}", sign_extend(bits, size) as i128, i)); + p!(write("{}{}", sign_extend(data, size) as i128, i)); return Ok(self); }, ty::Char => { - p!(write("{:?}", ::std::char::from_u32(bits as u32).unwrap())); + p!(write("{:?}", ::std::char::from_u32(data as u32).unwrap())); return Ok(self); } _ => {}, diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 2049341327495..75d227d8067c3 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -613,7 +613,7 @@ where (ConstValue::Placeholder(p1), ConstValue::Placeholder(p2)) if p1 == p2 => { Ok(a) } - (ConstValue::Scalar(Scalar::Bits { .. }), _) if a == b => { + (ConstValue::Scalar(Scalar::Raw { .. }), _) if a == b => { Ok(a) } (ConstValue::ByRef(..), _) => { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index a2b2fc7a4451a..e3c1e6bc22faf 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -3,7 +3,7 @@ use crate::hir; use crate::hir::def_id::DefId; use crate::infer::canonical::Canonical; -use crate::mir::interpret::{ConstValue, truncate}; +use crate::mir::interpret::ConstValue; use crate::middle::region; use polonius_engine::Atom; use rustc_data_structures::indexed_vec::Idx; @@ -2232,14 +2232,12 @@ impl<'tcx> Const<'tcx> { let size = tcx.layout_of(ty).unwrap_or_else(|e| { panic!("could not compute layout for {:?}: {:?}", ty, e) }).size; - let truncated = truncate(bits, size); - assert_eq!(truncated, bits, "from_bits called with untruncated value"); - Self::from_scalar(tcx, Scalar::Bits { bits, size: size.bytes() as u8 }, ty.value) + Self::from_scalar(tcx, Scalar::from_uint(bits, size), ty.value) } #[inline] pub fn zero_sized(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> &'tcx Self { - Self::from_scalar(tcx, Scalar::Bits { bits: 0, size: 0 }, ty) + Self::from_scalar(tcx, Scalar::zst(), ty) } #[inline] diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs index b9fd9629e6ff1..c713362440d97 100644 --- a/src/librustc_codegen_llvm/common.rs +++ b/src/librustc_codegen_llvm/common.rs @@ -294,13 +294,13 @@ impl ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { ) -> &'ll Value { let bitsize = if layout.is_bool() { 1 } else { layout.value.size(self).bits() }; match cv { - Scalar::Bits { size: 0, .. } => { + Scalar::Raw { size: 0, .. } => { assert_eq!(0, layout.value.size(self).bytes()); self.const_undef(self.type_ix(0)) }, - Scalar::Bits { bits, size } => { + Scalar::Raw { data, size } => { assert_eq!(size as u64, layout.value.size(self).bytes()); - let llval = self.const_uint_big(self.type_ix(bitsize), bits); + let llval = self.const_uint_big(self.type_ix(bitsize), data); if layout.value == layout::Pointer { unsafe { llvm::LLVMConstIntToPtr(llval, llty) } } else { diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs index 864071629078a..bf81b7f0da525 100644 --- a/src/librustc_codegen_utils/symbol_names.rs +++ b/src/librustc_codegen_utils/symbol_names.rs @@ -443,7 +443,7 @@ impl Printer<'tcx, 'tcx> for SymbolPrinter<'_, 'tcx> { ct: &'tcx ty::Const<'tcx>, ) -> Result { // only print integers - if let ConstValue::Scalar(Scalar::Bits { .. }) = ct.val { + if let ConstValue::Scalar(Scalar::Raw { .. }) = ct.val { if ct.ty.is_integral() { return self.pretty_print_const(ct); } diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 776d4c242415a..370b76520fc1a 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -115,7 +115,7 @@ fn op_to_const<'tcx>( ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id), ptr.offset.bytes(), ), - Scalar::Bits { .. } => ( + Scalar::Raw { .. } => ( ecx.tcx.intern_const_alloc(Allocation::from_byte_aligned_bytes(b"", ())), 0, ), diff --git a/src/librustc_mir/hair/constant.rs b/src/librustc_mir/hair/constant.rs index d2c86d36238e1..69df36348a69e 100644 --- a/src/librustc_mir/hair/constant.rs +++ b/src/librustc_mir/hair/constant.rs @@ -1,5 +1,5 @@ use syntax::ast; -use rustc::ty::{self, Ty, TyCtxt, ParamEnv}; +use rustc::ty::{self, Ty, TyCtxt, ParamEnv, layout::Size}; use syntax_pos::symbol::Symbol; use rustc::mir::interpret::{ConstValue, Scalar}; @@ -23,10 +23,7 @@ crate fn lit_to_const<'a, 'gcx, 'tcx>( trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits()); let result = truncate(n, width); trace!("trunc result: {}", result); - Ok(ConstValue::Scalar(Scalar::Bits { - bits: result, - size: width.bytes() as u8, - })) + Ok(ConstValue::Scalar(Scalar::from_uint(result, width))) }; use rustc::mir::interpret::*; @@ -50,10 +47,7 @@ crate fn lit_to_const<'a, 'gcx, 'tcx>( let id = tcx.allocate_bytes(data); ConstValue::Scalar(Scalar::Ptr(id.into())) }, - LitKind::Byte(n) => ConstValue::Scalar(Scalar::Bits { - bits: n as u128, - size: 1, - }), + LitKind::Byte(n) => ConstValue::Scalar(Scalar::from_uint(n, Size::from_bytes(1))), LitKind::Int(n, _) if neg => { let n = n as i128; let n = n.overflowing_neg().0; @@ -84,7 +78,7 @@ fn parse_float<'tcx>( let num = num.as_str(); use rustc_apfloat::ieee::{Single, Double}; use rustc_apfloat::Float; - let (bits, size) = match fty { + let (data, size) = match fty { ast::FloatTy::F32 => { num.parse::().map_err(|_| ())?; let mut f = num.parse::().unwrap_or_else(|e| { @@ -107,5 +101,5 @@ fn parse_float<'tcx>( } }; - Ok(ConstValue::Scalar(Scalar::Bits { bits, size })) + Ok(ConstValue::Scalar(Scalar::from_uint(data, Size::from_bytes(size)))) } diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 2512525b4bb7e..76b11ac2fe646 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -6,7 +6,7 @@ use syntax::symbol::sym; use rustc_apfloat::ieee::{Single, Double}; use rustc::mir::interpret::{ - Scalar, EvalResult, Pointer, PointerArithmetic, InterpError, truncate + Scalar, EvalResult, Pointer, PointerArithmetic, InterpError, }; use rustc::mir::CastKind; use rustc_apfloat::Float; @@ -135,29 +135,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> use rustc::ty::TyKind::*; trace!("Casting {:?}: {:?} to {:?}", val, src_layout.ty, dest_layout.ty); - match val { - Scalar::Ptr(ptr) => self.cast_from_ptr(ptr, dest_layout.ty), - Scalar::Bits { bits, size } => { - debug_assert_eq!(size as u64, src_layout.size.bytes()); - debug_assert_eq!(truncate(bits, Size::from_bytes(size.into())), bits, - "Unexpected value of size {} before casting", size); - - let res = match src_layout.ty.sty { - Float(fty) => self.cast_from_float(bits, fty, dest_layout.ty)?, - _ => self.cast_from_int(bits, src_layout, dest_layout)?, - }; - - // Sanity check - match res { - Scalar::Ptr(_) => bug!("Fabricated a ptr value from an int...?"), - Scalar::Bits { bits, size } => { - debug_assert_eq!(size as u64, dest_layout.size.bytes()); - debug_assert_eq!(truncate(bits, Size::from_bytes(size.into())), bits, - "Unexpected value of size {} after casting", size); - } + match val.to_bits_or_ptr(src_layout.size, self) { + Err(ptr) => self.cast_from_ptr(ptr, dest_layout.ty), + Ok(data) => { + match src_layout.ty.sty { + Float(fty) => self.cast_from_float(data, fty, dest_layout.ty), + _ => self.cast_from_int(data, src_layout, dest_layout), } - // Done - Ok(res) } } } @@ -177,7 +161,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> trace!("cast_from_int: {}, {}, {}", v, src_layout.ty, dest_layout.ty); use rustc::ty::TyKind::*; match dest_layout.ty.sty { - Int(_) | Uint(_) => { + Int(_) | Uint(_) | RawPtr(_) => { let v = self.truncate(v, dest_layout); Ok(Scalar::from_uint(v, dest_layout.size)) } @@ -205,15 +189,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> Ok(Scalar::from_uint(v, Size::from_bytes(4))) }, - // No alignment check needed for raw pointers. - // But we have to truncate to target ptr size. - RawPtr(_) => { - Ok(Scalar::from_uint( - self.truncate_to_ptr(v).0, - self.pointer_size(), - )) - }, - // Casts to bool are not permitted by rustc, no need to handle them here. _ => err!(Unimplemented(format!("int to {:?} cast", dest_layout.ty))), } diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 9674822b47a3d..e3a843993abba 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -12,7 +12,6 @@ use std::borrow::Cow; use rustc::ty::{self, Instance, ParamEnv, query::TyCtxtAt}; use rustc::ty::layout::{Align, TargetDataLayout, Size, HasDataLayout}; -pub use rustc::mir::interpret::{truncate, write_target_uint, read_target_uint}; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use syntax::ast::Mutability; @@ -248,22 +247,20 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { required_align: Align ) -> EvalResult<'tcx> { // Check non-NULL/Undef, extract offset - let (offset, alloc_align) = match ptr { - Scalar::Ptr(ptr) => { + let (offset, alloc_align) = match ptr.to_bits_or_ptr(self.pointer_size(), self) { + Err(ptr) => { // check this is not NULL -- which we can ensure only if this is in-bounds // of some (potentially dead) allocation. let align = self.check_bounds_ptr(ptr, InboundsCheck::MaybeDead)?; (ptr.offset.bytes(), align) } - Scalar::Bits { bits, size } => { - assert_eq!(size as u64, self.pointer_size().bytes()); - assert!(bits < (1u128 << self.pointer_size().bits())); + Ok(data) => { // check this is not NULL - if bits == 0 { + if data == 0 { return err!(InvalidNullPointerUsage); } // the "base address" is 0 and hence always aligned - (bits as u64, required_align) + (data as u64, required_align) } }; // Check alignment diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index de788a22886ab..80fdec1dcc4ff 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -641,18 +641,19 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> } => { let variants_start = niche_variants.start().as_u32() as u128; let variants_end = niche_variants.end().as_u32() as u128; - match raw_discr { - ScalarMaybeUndef::Scalar(Scalar::Ptr(ptr)) => { + let raw_discr = raw_discr.not_undef() + .map_err(|_| InterpError::InvalidDiscriminant(ScalarMaybeUndef::Undef))?; + match raw_discr.to_bits_or_ptr(discr_val.layout.size, self) { + Err(ptr) => { // The niche must be just 0 (which an inbounds pointer value never is) let ptr_valid = niche_start == 0 && variants_start == variants_end && self.memory.check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok(); if !ptr_valid { - return err!(InvalidDiscriminant(raw_discr.erase_tag())); + return err!(InvalidDiscriminant(raw_discr.erase_tag().into())); } (dataful_variant.as_u32() as u128, dataful_variant) }, - ScalarMaybeUndef::Scalar(Scalar::Bits { bits: raw_discr, size }) => { - assert_eq!(size as u64, discr_val.layout.size.bytes()); + Ok(raw_discr) => { let adjusted_discr = raw_discr.wrapping_sub(niche_start) .wrapping_add(variants_start); if variants_start <= adjusted_discr && adjusted_discr <= variants_end { @@ -667,8 +668,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M> (dataful_variant.as_u32() as u128, dataful_variant) } }, - ScalarMaybeUndef::Undef => - return err!(InvalidDiscriminant(ScalarMaybeUndef::Undef)), } } }) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 65e5e23e38424..6a22fde360c5c 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -686,7 +686,7 @@ where Immediate::Scalar(ScalarMaybeUndef::Scalar(Scalar::Ptr(_))) => assert_eq!(self.pointer_size(), dest.layout.size, "Size mismatch when writing pointer"), - Immediate::Scalar(ScalarMaybeUndef::Scalar(Scalar::Bits { size, .. })) => + Immediate::Scalar(ScalarMaybeUndef::Scalar(Scalar::Raw { size, .. })) => assert_eq!(Size::from_bytes(size.into()), dest.layout.size, "Size mismatch when writing bits"), Immediate::Scalar(ScalarMaybeUndef::Undef) => {}, // undef can have any size diff --git a/src/librustc_mir/interpret/snapshot.rs b/src/librustc_mir/interpret/snapshot.rs index 83bd3666b3d3b..c0bc7ce6b39ad 100644 --- a/src/librustc_mir/interpret/snapshot.rs +++ b/src/librustc_mir/interpret/snapshot.rs @@ -186,9 +186,9 @@ impl<'a, Ctx> Snapshot<'a, Ctx> for Scalar fn snapshot(&self, ctx: &'a Ctx) -> Self::Item { match self { Scalar::Ptr(p) => Scalar::Ptr(p.snapshot(ctx)), - Scalar::Bits{ size, bits } => Scalar::Bits { + Scalar::Raw{ size, data } => Scalar::Raw { + data: *data, size: *size, - bits: *bits, }, } } diff --git a/src/librustc_mir/interpret/validity.rs b/src/librustc_mir/interpret/validity.rs index 0d3ee830574ba..d88d0af75fb75 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/src/librustc_mir/interpret/validity.rs @@ -480,8 +480,8 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> wrapping_range_format(&layout.valid_range, max_hi), ) ); - let bits = match value { - Scalar::Ptr(ptr) => { + let bits = match value.to_bits_or_ptr(op.layout.size, self.ecx) { + Err(ptr) => { if lo == 1 && hi == max_hi { // only NULL is not allowed. // We can call `check_align` to check non-NULL-ness, but have to also look @@ -509,10 +509,8 @@ impl<'rt, 'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> ); } } - Scalar::Bits { bits, size } => { - assert_eq!(size as u64, op.layout.size.bytes()); - bits - } + Ok(data) => + data }; // Now compare. This is slightly subtle because this is a special "wrap-around" range. if wrapping_range_contains(&layout.valid_range, bits) { diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index b2976cd501e7f..c5a30e5a29483 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -379,10 +379,7 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some( ImmTy { imm: Immediate::Scalar( - Scalar::Bits { - bits: n as u128, - size: self.tcx.data_layout.pointer_size.bytes() as u8, - }.into() + Scalar::from_uint(n, self.tcx.data_layout.pointer_size).into() ), layout: self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?, }.into() @@ -710,18 +707,18 @@ impl<'b, 'a, 'tcx> MutVisitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { .eval_operand(len, source_info) .expect("len must be const"); let len = match self.ecx.read_scalar(len) { - Ok(ScalarMaybeUndef::Scalar(Scalar::Bits { - bits, .. - })) => bits, + Ok(ScalarMaybeUndef::Scalar(Scalar::Raw { + data, .. + })) => data, other => bug!("const len not primitive: {:?}", other), }; let index = self .eval_operand(index, source_info) .expect("index must be const"); let index = match self.ecx.read_scalar(index) { - Ok(ScalarMaybeUndef::Scalar(Scalar::Bits { - bits, .. - })) => bits, + Ok(ScalarMaybeUndef::Scalar(Scalar::Raw { + data, .. + })) => data, other => bug!("const index not primitive: {:?}", other), }; format!(