support computing the remainder of a ptr, if covered by alignment
This commit is contained in:
parent
93fef9a6a2
commit
2b40d39c1e
@ -130,8 +130,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
|
||||
err!(InvalidPointerMath)
|
||||
}
|
||||
}
|
||||
// These work if one operand is a pointer, the other an integer
|
||||
Add | BitAnd | Sub
|
||||
// These work if the left operand is a pointer, the right an integer
|
||||
Add | BitAnd | Sub | Rem
|
||||
if left_kind == right_kind && (left_kind == usize || left_kind == isize) &&
|
||||
left.is_ptr() && right.is_bits() => {
|
||||
// Cast to i128 is fine as we checked the kind to be ptr-sized
|
||||
@ -142,6 +142,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
|
||||
left_kind == isize,
|
||||
).map(Some)
|
||||
}
|
||||
// Commutative operators also work if the integer is on the left
|
||||
Add | BitAnd
|
||||
if left_kind == right_kind && (left_kind == usize || left_kind == isize) &&
|
||||
left.is_bits() && right.is_ptr() => {
|
||||
@ -180,7 +181,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
|
||||
map_to_primval(left.overflowing_offset(Size::from_bytes(right as u64), self)),
|
||||
|
||||
BitAnd if !signed => {
|
||||
let base_mask : u64 = !(self.memory.get(left.alloc_id)?.align.abi() - 1);
|
||||
let ptr_base_align = self.memory.get(left.alloc_id)?.align.abi();
|
||||
let base_mask : u64 = !(ptr_base_align - 1);
|
||||
let right = right as u64;
|
||||
let ptr_size = self.memory.pointer_size().bytes() as u8;
|
||||
if right & base_mask == base_mask {
|
||||
@ -194,6 +196,23 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super:
|
||||
}
|
||||
}
|
||||
|
||||
Rem if !signed => {
|
||||
// Doing modulo a multiple of the alignment is allowed
|
||||
let ptr_base_align = self.memory.get(left.alloc_id)?.align.abi();
|
||||
let right = right as u64;
|
||||
let ptr_size = self.memory.pointer_size().bytes() as u8;
|
||||
if right == 1 {
|
||||
// modulo 1 is always 0
|
||||
(Scalar::Bits { bits: 0, size: ptr_size }, false)
|
||||
} else if right % ptr_base_align == 0 {
|
||||
// the base address would be cancelled out by the modulo operation, so we can
|
||||
// just take the modulo of the offset
|
||||
(Scalar::Bits { bits: (left.offset.bytes() % right) as u128, size: ptr_size }, false)
|
||||
} else {
|
||||
return err!(ReadPointerAsBytes);
|
||||
}
|
||||
}
|
||||
|
||||
_ => {
|
||||
let msg = format!("unimplemented binary op on pointer {:?}: {:?}, {:?} ({})", bin_op, left, right, if signed { "signed" } else { "unsigned" });
|
||||
return err!(Unimplemented(msg));
|
||||
|
@ -3,6 +3,6 @@ fn main() {
|
||||
let y = &x;
|
||||
let z = &y as *const &i32 as *const usize;
|
||||
let ptr_bytes = unsafe { *z }; // the actual deref is fine, because we read the entire pointer at once
|
||||
let _ = ptr_bytes % 432; //~ ERROR constant evaluation error
|
||||
let _ = ptr_bytes / 432; //~ ERROR constant evaluation error
|
||||
//~^ NOTE tried to access part of a pointer value as raw bytes
|
||||
}
|
||||
|
5
tests/compile-fail/ptr_bitops2.rs
Normal file
5
tests/compile-fail/ptr_bitops2.rs
Normal file
@ -0,0 +1,5 @@
|
||||
fn main() {
|
||||
let val = 13usize;
|
||||
let addr = &val as *const _ as usize;
|
||||
let _ = addr & 13; //~ ERROR access part of a pointer value as raw bytes
|
||||
}
|
5
tests/compile-fail/ptr_rem.rs
Normal file
5
tests/compile-fail/ptr_rem.rs
Normal file
@ -0,0 +1,5 @@
|
||||
fn main() {
|
||||
let val = 13usize;
|
||||
let addr = &val as *const _ as usize;
|
||||
let _ = addr % 2; //~ ERROR access part of a pointer value as raw bytes
|
||||
}
|
20
tests/run-pass/ptr_int_ops.rs
Normal file
20
tests/run-pass/ptr_int_ops.rs
Normal file
@ -0,0 +1,20 @@
|
||||
fn main() {
|
||||
let v = [1i16, 2];
|
||||
let x = &v[1] as *const i16 as usize;
|
||||
// arithmetic
|
||||
let _y = x + 4;
|
||||
let _y = 4 + x;
|
||||
let _y = x - 2;
|
||||
// bit-operations, covered by alignment
|
||||
assert_eq!(x & 1, 0);
|
||||
assert_eq!(x & 0, 0);
|
||||
assert_eq!(1 & (x+1), 1);
|
||||
let _y = !1 & x;
|
||||
let _y = !0 & x;
|
||||
let _y = x & !1;
|
||||
// remainder, covered by alignment
|
||||
assert_eq!(x % 2, 0);
|
||||
assert_eq!((x+1) % 2, 1);
|
||||
// remainder with 1 is always 0
|
||||
assert_eq!(x % 1, 0);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user