miri: simplify shift operator overflow checking
This commit is contained in:
parent
cdb50c6f25
commit
5be304b0b4
1 changed files with 13 additions and 12 deletions
|
|
@ -1,3 +1,5 @@
|
|||
use std::convert::TryFrom;
|
||||
|
||||
use rustc::mir;
|
||||
use rustc::mir::interpret::{InterpResult, Scalar};
|
||||
use rustc::ty::{
|
||||
|
|
@ -130,28 +132,27 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
// Shift ops can have an RHS with a different numeric type.
|
||||
if bin_op == Shl || bin_op == Shr {
|
||||
let signed = left_layout.abi.is_signed();
|
||||
let mut oflo = (r as u32 as u128) != r;
|
||||
let mut r = r as u32;
|
||||
let size = left_layout.size;
|
||||
oflo |= r >= size.bits() as u32;
|
||||
r %= size.bits() as u32;
|
||||
let size = u128::from(left_layout.size.bits());
|
||||
let overflow = r >= size;
|
||||
let r = r % size; // mask to type size
|
||||
let r = u32::try_from(r).unwrap(); // we masked so this will always fit
|
||||
let result = if signed {
|
||||
let l = self.sign_extend(l, left_layout) as i128;
|
||||
let result = match bin_op {
|
||||
Shl => l << r,
|
||||
Shr => l >> r,
|
||||
Shl => l.checked_shl(r).unwrap(),
|
||||
Shr => l.checked_shr(r).unwrap(),
|
||||
_ => bug!("it has already been checked that this is a shift op"),
|
||||
};
|
||||
result as u128
|
||||
} else {
|
||||
match bin_op {
|
||||
Shl => l << r,
|
||||
Shr => l >> r,
|
||||
Shl => l.checked_shl(r).unwrap(),
|
||||
Shr => l.checked_shr(r).unwrap(),
|
||||
_ => bug!("it has already been checked that this is a shift op"),
|
||||
}
|
||||
};
|
||||
let truncated = self.truncate(result, left_layout);
|
||||
return Ok((Scalar::from_uint(truncated, size), oflo, left_layout.ty));
|
||||
return Ok((Scalar::from_uint(truncated, left_layout.size), overflow, left_layout.ty));
|
||||
}
|
||||
|
||||
// For the remaining ops, the types must be the same on both sides
|
||||
|
|
@ -193,7 +194,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
_ => None,
|
||||
};
|
||||
if let Some(op) = op {
|
||||
let l128 = self.sign_extend(l, left_layout) as i128;
|
||||
let r = self.sign_extend(r, right_layout) as i128;
|
||||
// We need a special check for overflowing remainder:
|
||||
// "int_min % -1" overflows and returns 0, but after casting things to a larger int
|
||||
|
|
@ -206,8 +206,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
}
|
||||
_ => {}
|
||||
}
|
||||
let l = self.sign_extend(l, left_layout) as i128;
|
||||
|
||||
let (result, oflo) = op(l128, r);
|
||||
let (result, oflo) = op(l, r);
|
||||
// This may be out-of-bounds for the result type, so we have to truncate ourselves.
|
||||
// If that truncation loses any information, we have an overflow.
|
||||
let result = result as u128;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue