about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJannis Christopher Köhl <mail@koehl.dev>2022-10-15 19:24:02 +0200
committerJannis Christopher Köhl <mail@koehl.dev>2022-11-07 10:35:23 +0100
commitbe9013f02b629ec7b6d40a5a4ff7966e2df751f6 (patch)
treee66c4deeb94b59bee026b720e8eaf45c738ef642
parent1dde908fae0c5c1f33d4a19bee1c58fd36c42cf6 (diff)
downloadrust-be9013f02b629ec7b6d40a5a4ff7966e2df751f6.tar.gz
rust-be9013f02b629ec7b6d40a5a4ff7966e2df751f6.zip
Make overflow flag propagation conditional
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs18
-rw-r--r--src/test/mir-opt/dataflow-const-prop/inherit_overflow_checks_use.main.DataflowConstProp.diff45
-rw-r--r--src/test/mir-opt/dataflow-const-prop/inherit_overflow_checks_use.rs8
3 files changed, 69 insertions, 2 deletions
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 <u8 as Add>::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 _ = <u8 as std::ops::Add>::add(255, 1);
+}