Skip to content

Commit 298a19d

Browse files
committed
Remove overflow checks from ConstProp.
1 parent 90d43a2 commit 298a19d

File tree

3 files changed

+18
-98
lines changed

3 files changed

+18
-98
lines changed

compiler/rustc_mir_transform/src/const_prop.rs

Lines changed: 14 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -499,55 +499,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
499499
}
500500
}
501501

502-
fn check_unary_op(&mut self, op: UnOp, arg: &Operand<'tcx>) -> Option<()> {
503-
if self.use_ecx(|this| {
504-
let val = this.ecx.read_immediate(&this.ecx.eval_operand(arg, None)?)?;
505-
let (_res, overflow, _ty) = this.ecx.overflowing_unary_op(op, &val)?;
506-
Ok(overflow)
507-
})? {
508-
// `AssertKind` only has an `OverflowNeg` variant, so make sure that is
509-
// appropriate to use.
510-
assert_eq!(op, UnOp::Neg, "Neg is the only UnOp that can overflow");
511-
return None;
512-
}
513-
514-
Some(())
515-
}
516-
517-
fn check_binary_op(
518-
&mut self,
519-
op: BinOp,
520-
left: &Operand<'tcx>,
521-
right: &Operand<'tcx>,
522-
) -> Option<()> {
523-
let r = self.use_ecx(|this| this.ecx.read_immediate(&this.ecx.eval_operand(right, None)?));
524-
let l = self.use_ecx(|this| this.ecx.read_immediate(&this.ecx.eval_operand(left, None)?));
525-
// Check for exceeding shifts *even if* we cannot evaluate the LHS.
526-
if matches!(op, BinOp::Shr | BinOp::Shl) {
527-
let r = r.clone()?;
528-
// We need the type of the LHS. We cannot use `place_layout` as that is the type
529-
// of the result, which for checked binops is not the same!
530-
let left_ty = left.ty(self.local_decls, self.tcx);
531-
let left_size = self.ecx.layout_of(left_ty).ok()?.size;
532-
let right_size = r.layout.size;
533-
let r_bits = r.to_scalar().to_bits(right_size).ok();
534-
if r_bits.map_or(false, |b| b >= left_size.bits() as u128) {
535-
return None;
536-
}
537-
}
538-
539-
if let (Some(l), Some(r)) = (&l, &r) {
540-
// The remaining operators are handled through `overflowing_binary_op`.
541-
if self.use_ecx(|this| {
542-
let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?;
543-
Ok(overflow)
544-
})? {
545-
return None;
546-
}
547-
}
548-
Some(())
549-
}
550-
551502
fn propagate_operand(&mut self, operand: &mut Operand<'tcx>) {
552503
match *operand {
553504
Operand::Copy(l) | Operand::Move(l) => {
@@ -583,28 +534,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
583534
// 2. Working around bugs in other parts of the compiler
584535
// - In this case, we'll return `None` from this function to stop evaluation.
585536
match rvalue {
586-
// Additional checking: give lints to the user if an overflow would occur.
587-
// We do this here and not in the `Assert` terminator as that terminator is
588-
// only sometimes emitted (overflow checks can be disabled), but we want to always
589-
// lint.
590-
Rvalue::UnaryOp(op, arg) => {
591-
trace!("checking UnaryOp(op = {:?}, arg = {:?})", op, arg);
592-
self.check_unary_op(*op, arg)?;
593-
}
594-
Rvalue::BinaryOp(op, box (left, right)) => {
595-
trace!("checking BinaryOp(op = {:?}, left = {:?}, right = {:?})", op, left, right);
596-
self.check_binary_op(*op, left, right)?;
597-
}
598-
Rvalue::CheckedBinaryOp(op, box (left, right)) => {
599-
trace!(
600-
"checking CheckedBinaryOp(op = {:?}, left = {:?}, right = {:?})",
601-
op,
602-
left,
603-
right
604-
);
605-
self.check_binary_op(*op, left, right)?;
606-
}
607-
608537
// Do not try creating references (#67862)
609538
Rvalue::AddressOf(_, place) | Rvalue::Ref(_, _, place) => {
610539
trace!("skipping AddressOf | Ref for {:?}", place);
@@ -634,7 +563,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
634563
| Rvalue::Cast(..)
635564
| Rvalue::ShallowInitBox(..)
636565
| Rvalue::Discriminant(..)
637-
| Rvalue::NullaryOp(..) => {}
566+
| Rvalue::NullaryOp(..)
567+
| Rvalue::UnaryOp(..)
568+
| Rvalue::BinaryOp(..)
569+
| Rvalue::CheckedBinaryOp(..) => {}
638570
}
639571

640572
// FIXME we need to revisit this for #67176
@@ -1071,31 +1003,18 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
10711003

10721004
match &mut terminator.kind {
10731005
TerminatorKind::Assert { expected, ref mut cond, .. } => {
1074-
if let Some(ref value) = self.eval_operand(&cond) {
1075-
trace!("assertion on {:?} should be {:?}", value, expected);
1076-
let expected = Scalar::from_bool(*expected);
1006+
if let Some(ref value) = self.eval_operand(&cond)
10771007
// FIXME should be used use_ecx rather than a local match... but we have
10781008
// quite a few of these read_scalar/read_immediate that need fixing.
1079-
if let Ok(value_const) = self.ecx.read_scalar(&value) {
1080-
if expected != value_const {
1081-
// Poison all places this operand references so that further code
1082-
// doesn't use the invalid value
1083-
match cond {
1084-
Operand::Move(ref place) | Operand::Copy(ref place) => {
1085-
Self::remove_const(&mut self.ecx, place.local);
1086-
}
1087-
Operand::Constant(_) => {}
1088-
}
1089-
} else {
1090-
if self.should_const_prop(value) {
1091-
*cond = self.operand_from_scalar(
1092-
value_const,
1093-
self.tcx.types.bool,
1094-
source_info.span,
1095-
);
1096-
}
1097-
}
1098-
}
1009+
&& let Ok(value_const) = self.ecx.read_scalar(&value)
1010+
&& self.should_const_prop(value)
1011+
{
1012+
trace!("assertion on {:?} should be {:?}", value, expected);
1013+
*cond = self.operand_from_scalar(
1014+
value_const,
1015+
self.tcx.types.bool,
1016+
source_info.span,
1017+
);
10991018
}
11001019
}
11011020
TerminatorKind::SwitchInt { ref mut discr, .. } => {

tests/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,10 @@
2424
StorageLive(_3); // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:18: +2:19
2525
- _3 = _1; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:18: +2:19
2626
- _4 = Eq(_3, const 0_i32); // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
27+
- assert(!move _4, "attempt to divide `{}` by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
2728
+ _3 = const 0_i32; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:18: +2:19
2829
+ _4 = const true; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
29-
assert(!move _4, "attempt to divide `{}` by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
30+
+ assert(!const true, "attempt to divide `{}` by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:+2:14: +2:19
3031
}
3132

3233
bb1: {

tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.diff

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
bb0: {
1919
_1 = const u8::MAX; // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
2020
_2 = const 1_u8; // scope 0 at $DIR/inherit_overflow.rs:+3:13: +3:47
21-
_5 = CheckedAdd(const u8::MAX, const 1_u8); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
22-
assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> bb1; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
21+
_5 = const (0_u8, true); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
22+
assert(!const true, "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> bb1; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL
2323
}
2424

2525
bb1: {

0 commit comments

Comments
 (0)