diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index f30dc741abb..2d7768105eb 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -7,7 +7,7 @@ use rustc_mir_dataflow::value_analysis::{ Map, ProjElem, State, ValueAnalysis, ValueOrPlace, ValueOrPlaceOrRef, }; use rustc_mir_dataflow::{lattice::FlatSet, Analysis, ResultsVisitor, SwitchIntEdgeEffects}; -use rustc_span::DUMMY_SP; +use rustc_span::{sym, DUMMY_SP}; use crate::MirPass; @@ -38,6 +38,7 @@ struct ConstAnalysis<'tcx> { tcx: TyCtxt<'tcx>, ecx: InterpCx<'tcx, 'tcx, DummyMachine>, param_env: ty::ParamEnv<'tcx>, + propagate_overflow: bool, } impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'tcx> { @@ -72,7 +73,11 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'tcx> { }); if value_target.is_some() || overflow_target.is_some() { - let (val, overflow) = self.binary_op(state, *op, left, right); + let (val, mut overflow) = self.binary_op(state, *op, left, right); + + if !self.propagate_overflow { + overflow = FlatSet::Top; + } if let Some(value_target) = value_target { state.assign_idx(value_target, ValueOrPlaceOrRef::Value(val), self.map()); @@ -202,11 +207,20 @@ impl<'tcx> std::fmt::Debug for ScalarTy<'tcx> { impl<'tcx> ConstAnalysis<'tcx> { pub fn new(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, map: Map) -> Self { + // It can happen that overflow will be detected even though overflow checks are disabled. + // This is caused by inlining functions that have #[rustc_inherit_overflow_checks]. Such + // overflows must not be propagated if `-C overflow-checks=off`. Also, if the function we + // are optimizing here has #[rustc_inherit_overflow_checks], the overflow checks may + // actually not be triggered by the consuming crate, so we have to ignore them too. + // Related to https://github.com/rust-lang/rust/issues/35310. + let propagate_overflow = tcx.sess.overflow_checks() + && !tcx.has_attr(body.source.def_id(), sym::rustc_inherit_overflow_checks); Self { map, tcx, ecx: InterpCx::new(tcx, DUMMY_SP, ty::ParamEnv::empty(), DummyMachine), param_env: tcx.param_env(body.source.def_id()), + propagate_overflow, } } diff --git a/src/test/mir-opt/dataflow-const-prop/inherit_overflow_checks_use.main.DataflowConstProp.diff b/src/test/mir-opt/dataflow-const-prop/inherit_overflow_checks_use.main.DataflowConstProp.diff new file mode 100644 index 00000000000..53c7ec41680 --- /dev/null +++ b/src/test/mir-opt/dataflow-const-prop/inherit_overflow_checks_use.main.DataflowConstProp.diff @@ -0,0 +1,45 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/inherit_overflow_checks_use.rs:+0:11: +0:11 + let mut _1: u8; // in scope 0 at $DIR/inherit_overflow_checks_use.rs:+3:13: +3:47 + let mut _2: u8; // in scope 0 at $DIR/inherit_overflow_checks_use.rs:+3:13: +3:47 + let mut _3: u8; // in scope 0 at $DIR/inherit_overflow_checks_use.rs:+3:13: +3:47 + scope 1 { + } + scope 2 (inlined ::add) { // at $DIR/inherit_overflow_checks_use.rs:7:13: 7:47 + debug self => _2; // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL + debug other => _3; // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL + let mut _4: u8; // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL + let mut _5: u8; // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL + let mut _6: (u8, bool); // in scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inherit_overflow_checks_use.rs:+3:13: +3:47 + StorageLive(_2); // scope 0 at $DIR/inherit_overflow_checks_use.rs:+3:13: +3:47 + _2 = const u8::MAX; // scope 0 at $DIR/inherit_overflow_checks_use.rs:+3:13: +3:47 + StorageLive(_3); // scope 0 at $DIR/inherit_overflow_checks_use.rs:+3:13: +3:47 + _3 = const 1_u8; // scope 0 at $DIR/inherit_overflow_checks_use.rs:+3:13: +3:47 + StorageLive(_4); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL + _4 = const u8::MAX; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL + StorageLive(_5); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL + _5 = const 1_u8; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL + _6 = CheckedAdd(const u8::MAX, const 1_u8); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL + assert(!move (_6.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 + } + + bb1: { +- _1 = move (_6.0: u8); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL ++ _1 = const 0_u8; // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL + StorageDead(_5); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL + StorageDead(_4); // scope 2 at $SRC_DIR/core/src/ops/arith.rs:LL:COL + StorageDead(_3); // scope 0 at $DIR/inherit_overflow_checks_use.rs:+3:13: +3:47 + StorageDead(_2); // scope 0 at $DIR/inherit_overflow_checks_use.rs:+3:13: +3:47 + StorageDead(_1); // scope 0 at $DIR/inherit_overflow_checks_use.rs:+3:47: +3:48 + nop; // scope 0 at $DIR/inherit_overflow_checks_use.rs:+0:11: +4:2 + return; // scope 0 at $DIR/inherit_overflow_checks_use.rs:+4:2: +4:2 + } + } + diff --git a/src/test/mir-opt/dataflow-const-prop/inherit_overflow_checks_use.rs b/src/test/mir-opt/dataflow-const-prop/inherit_overflow_checks_use.rs new file mode 100644 index 00000000000..d4fcb1d7705 --- /dev/null +++ b/src/test/mir-opt/dataflow-const-prop/inherit_overflow_checks_use.rs @@ -0,0 +1,8 @@ +// compile-flags: -C overflow-checks=off + +// EMIT_MIR inherit_overflow_checks_use.main.DataflowConstProp.diff +fn main() { + // After inlining, this will contain a `CheckedBinaryOp`. The overflow + // must be ignored by the constant propagation to avoid triggering a panic. + let _ = ::add(255, 1); +}