diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_mir_build/src/build/expr/as_rvalue.rs | 56 | ||||
| -rw-r--r-- | compiler/rustc_type_ir/src/lib.rs | 22 |
2 files changed, 55 insertions, 23 deletions
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 140d1154718..3b775f590a4 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -566,41 +566,51 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Rvalue::Use(Operand::Move(val)) } BinOp::Shl | BinOp::Shr if self.check_overflow && ty.is_integral() => { - // Consider that the shift overflows if `rhs < 0` or `rhs >= bits`. - // This can be encoded as a single operation as `(rhs & -bits) != 0`. - let (size, _) = ty.int_size_and_signed(self.tcx); - let bits = size.bits(); - debug_assert!(bits.is_power_of_two()); - let mask = !((bits - 1) as u128); - + // For an unsigned RHS, the shift is in-range for `rhs < bits`. + // For a signed RHS, `IntToInt` cast to the equivalent unsigned + // type and do that same comparison. Because the type is the + // same size, there's no negative shift amount that ends up + // overlapping with valid ones, thus it catches negatives too. + let (lhs_size, _) = ty.int_size_and_signed(self.tcx); let rhs_ty = rhs.ty(&self.local_decls, self.tcx); let (rhs_size, _) = rhs_ty.int_size_and_signed(self.tcx); - let mask = Operand::const_from_scalar( + + let (unsigned_rhs, unsigned_ty) = match rhs_ty.kind() { + ty::Uint(_) => (rhs.to_copy(), rhs_ty), + ty::Int(int_width) => { + let uint_ty = self.tcx.mk_mach_uint(int_width.to_unsigned()); + let rhs_temp = self.temp(uint_ty, span); + self.cfg.push_assign( + block, + source_info, + rhs_temp, + Rvalue::Cast(CastKind::IntToInt, rhs.to_copy(), uint_ty), + ); + (Operand::Move(rhs_temp), uint_ty) + } + _ => unreachable!("only integers are shiftable"), + }; + + // This can't overflow because the largest shiftable types are 128-bit, + // which fits in `u8`, the smallest possible `unsigned_ty`. + // (And `from_uint` will `bug!` if that's ever no longer true.) + let lhs_bits = Operand::const_from_scalar( self.tcx, - rhs_ty, - Scalar::from_uint(rhs_size.truncate(mask), rhs_size), + unsigned_ty, + Scalar::from_uint(lhs_size.bits(), rhs_size), span, ); - let outer_bits = self.temp(rhs_ty, span); - self.cfg.push_assign( - block, - source_info, - outer_bits, - Rvalue::BinaryOp(BinOp::BitAnd, Box::new((rhs.to_copy(), mask))), - ); - - let overflows = self.temp(bool_ty, span); - let zero = self.zero_literal(span, rhs_ty); + let inbounds = self.temp(bool_ty, span); self.cfg.push_assign( block, source_info, - overflows, - Rvalue::BinaryOp(BinOp::Ne, Box::new((Operand::Move(outer_bits), zero))), + inbounds, + Rvalue::BinaryOp(BinOp::Lt, Box::new((unsigned_rhs, lhs_bits))), ); let overflow_err = AssertKind::Overflow(op, lhs.to_copy(), rhs.to_copy()); - block = self.assert(block, Operand::Move(overflows), false, overflow_err, span); + block = self.assert(block, Operand::Move(inbounds), true, overflow_err, span); Rvalue::BinaryOp(op, Box::new((lhs, rhs))) } BinOp::Div | BinOp::Rem if ty.is_integral() => { diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 5a991e03dee..8b23fbc7583 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -432,6 +432,17 @@ impl IntTy { _ => *self, } } + + pub fn to_unsigned(self) -> UintTy { + match self { + IntTy::Isize => UintTy::Usize, + IntTy::I8 => UintTy::U8, + IntTy::I16 => UintTy::U16, + IntTy::I32 => UintTy::U32, + IntTy::I64 => UintTy::U64, + IntTy::I128 => UintTy::U128, + } + } } #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Debug)] @@ -479,6 +490,17 @@ impl UintTy { _ => *self, } } + + pub fn to_signed(self) -> IntTy { + match self { + UintTy::Usize => IntTy::Isize, + UintTy::U8 => IntTy::I8, + UintTy::U16 => IntTy::I16, + UintTy::U32 => IntTy::I32, + UintTy::U64 => IntTy::I64, + UintTy::U128 => IntTy::I128, + } + } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] |
