Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/librustc/mir/interpret/allocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,11 +388,11 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
val.offset.bytes() as u128
}

Scalar::Bits { bits, size } => {
Scalar::Raw { data, size } => {
assert_eq!(size as u64, type_size.bytes());
debug_assert_eq!(truncate(bits, Size::from_bytes(size.into())), bits,
debug_assert_eq!(truncate(data, Size::from_bytes(size.into())), data,
"Unexpected value of size {} when writing to memory", size);
bits
data
},
};

Expand Down
45 changes: 24 additions & 21 deletions src/librustc/mir/interpret/pointer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,45 +20,48 @@ 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.
#[inline]
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<T: layout::HasDataLayout> PointerArithmetic for T {}
Expand Down
88 changes: 44 additions & 44 deletions src/librustc/mir/interpret/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,11 @@ impl<'tcx> ConstValue<'tcx> {
RustcEncodable, RustcDecodable, Hash, HashStable)]
pub enum Scalar<Tag=(), Id=AllocId> {
/// 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
Expand All @@ -108,16 +108,16 @@ impl<Tag: fmt::Debug, Id: fmt::Debug> fmt::Debug for Scalar<Tag, Id> {
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, "<ZST>")
} 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)
}
}
}
Expand All @@ -128,7 +128,7 @@ impl<Tag> fmt::Display for Scalar<Tag> {
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),
}
}
}
Expand All @@ -138,7 +138,7 @@ impl<'tcx> Scalar<()> {
pub fn with_tag<Tag>(self, new_tag: Tag) -> Scalar<Tag> {
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 },
}
}

Expand All @@ -155,31 +155,31 @@ impl<'tcx, Tag> Scalar<Tag> {
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,
})
}
Expand All @@ -191,10 +191,10 @@ impl<'tcx, Tag> Scalar<Tag> {
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,
}
}
Expand All @@ -206,10 +206,10 @@ impl<'tcx, Tag> Scalar<Tag> {
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,
})
}
Expand All @@ -221,10 +221,10 @@ impl<'tcx, Tag> Scalar<Tag> {
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,
}
}
Expand All @@ -237,9 +237,9 @@ impl<'tcx, Tag> Scalar<Tag> {
#[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,
}
Expand All @@ -248,30 +248,30 @@ impl<'tcx, Tag> Scalar<Tag> {
#[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,
}
}

#[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<u128>, size: Size) -> Self {
let i = i.into();
debug_assert_eq!(truncate(i, size), i,
"Unsigned value {} does not fit in {} bits", i, size.bits());
Scalar::Bits { bits: i, size: size.bytes() as u8 }
Scalar::Raw { data: i, size: size.bytes() as u8 }
}

#[inline]
Expand All @@ -281,26 +281,26 @@ impl<'tcx, Tag> Scalar<Tag> {
let truncated = truncate(i as u128, size);
debug_assert_eq!(sign_extend(truncated, size) as i128, i,
"Signed value {} does not fit in {} bits", i, size.bits());
Scalar::Bits { bits: truncated, size: size.bytes() as u8 }
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(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)
Ok(data)
}
Scalar::Ptr(_) => err!(ReadPointerAsBytes),
}
Expand All @@ -309,16 +309,16 @@ impl<'tcx, Tag> Scalar<Tag> {
#[inline]
pub fn to_ptr(self) -> EvalResult<'tcx, Pointer<Tag>> {
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),
}
}

#[inline]
pub fn is_bits(self) -> bool {
match self {
Scalar::Bits { .. } => true,
Scalar::Raw { .. } => true,
_ => false,
}
}
Expand All @@ -333,8 +333,8 @@ impl<'tcx, Tag> Scalar<Tag> {

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),
}
}
Expand Down
5 changes: 1 addition & 4 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}),
}
Expand Down
14 changes: 7 additions & 7 deletions src/librustc/ty/print/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -845,34 +845,34 @@ 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) =>{
let ty = self.tcx().lift_to_global(&ct.ty).unwrap();
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);
}
_ => {},
Expand Down
Loading