diff options
| author | Ralf Jung <post@ralfj.de> | 2020-03-17 14:11:51 +0100 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2020-03-25 15:48:53 +0100 |
| commit | 5be304b0b411af49e4f0e7196a35c034f430cc85 (patch) | |
| tree | 975a433572c037afce0d8889feccbdc47644c4f7 | |
| parent | cdb50c6f2507319f29104a25765bfb79ad53395c (diff) | |
| download | rust-5be304b0b411af49e4f0e7196a35c034f430cc85.tar.gz rust-5be304b0b411af49e4f0e7196a35c034f430cc85.zip | |
miri: simplify shift operator overflow checking
| -rw-r--r-- | src/librustc_mir/interpret/operator.rs | 25 |
1 files changed, 13 insertions, 12 deletions
diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs index 76a5aecb9db..cb0aaa4d40d 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/src/librustc_mir/interpret/operator.rs @@ -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; |
