about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOliver Scherer <github35764891676564198441@oli-obk.de>2020-06-22 14:03:18 +0200
committerWesley Wiser <wwiser@gmail.com>2020-07-25 10:55:12 -0400
commit4e1eaf44ff72d981b42b9e4cacc7ef9a1f97598a (patch)
tree67a738582353ce431d6d5fcdd11b3b45a18227cf
parent14485ee1257703df51313efe39daf35e886e4dac (diff)
downloadrust-4e1eaf44ff72d981b42b9e4cacc7ef9a1f97598a.tar.gz
rust-4e1eaf44ff72d981b42b9e4cacc7ef9a1f97598a.zip
The const propagator cannot trace references.
Thus we avoid propagation of a local the moment we encounter references to it.
-rw-r--r--src/librustc_mir/transform/const_prop.rs46
-rw-r--r--src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/32bit/rustc.main.ConstProp.diff18
-rw-r--r--src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/64bit/rustc.main.ConstProp.diff18
-rw-r--r--src/test/mir-opt/const_prop_miscompile.rs22
-rw-r--r--src/test/mir-opt/const_prop_miscompile/rustc.bar.ConstProp.diff75
-rw-r--r--src/test/mir-opt/const_prop_miscompile/rustc.foo.ConstProp.diff63
-rw-r--r--src/test/ui/mir/mir_detects_invalid_ops.rs2
-rw-r--r--src/test/ui/mir/mir_detects_invalid_ops.stderr8
8 files changed, 202 insertions, 50 deletions
diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs
index 92000e64113..75032eafe30 100644
--- a/src/librustc_mir/transform/const_prop.rs
+++ b/src/librustc_mir/transform/const_prop.rs
@@ -580,8 +580,16 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
             }
 
             // Do not try creating references (#67862)
-            Rvalue::Ref(_, _, place_ref) => {
-                trace!("skipping Ref({:?})", place_ref);
+            Rvalue::AddressOf(_, place) | Rvalue::Ref(_, _, place) => {
+                trace!("skipping AddressOf | Ref for {:?}", place);
+
+                // This may be creating mutable references or immutable references to cells.
+                // If that happens, the pointed to value could be mutated via that reference.
+                // Since we aren't tracking references, the const propagator loses track of what
+                // value the local has right now.
+                // Thus, all locals that have their reference taken
+                // must not take part in propagation.
+                Self::remove_const(&mut self.ecx, place.local);
 
                 return None;
             }
@@ -726,7 +734,8 @@ enum ConstPropMode {
     OnlyInsideOwnBlock,
     /// The `Local` can be propagated into but reads cannot be propagated.
     OnlyPropagateInto,
-    /// No propagation is allowed at all.
+    /// The `Local` cannot be part of propagation at all. Any statement
+    /// referencing it either for reading or writing will not get propagated.
     NoPropagation,
 }
 
@@ -793,7 +802,9 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
                         // end of the block anyway, and inside the block we overwrite previous
                         // states as applicable.
                         ConstPropMode::OnlyInsideOwnBlock => {}
-                        other => {
+                        ConstPropMode::NoPropagation => {}
+                        ConstPropMode::OnlyPropagateInto => {}
+                        other @ ConstPropMode::FullConstProp => {
                             trace!(
                                 "local {:?} can't be propagated because of multiple assignments",
                                 local,
@@ -880,13 +891,22 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
                             }
                         }
                     }
-                    if can_const_prop == ConstPropMode::OnlyPropagateInto
-                        || can_const_prop == ConstPropMode::NoPropagation
-                    {
-                        trace!("can't propagate into {:?}", place);
-                        if place.local != RETURN_PLACE {
-                            Self::remove_const(&mut self.ecx, place.local);
+                    match can_const_prop {
+                        ConstPropMode::OnlyInsideOwnBlock => {
+                            trace!(
+                                "found local restricted to its block. \
+                                Will remove it from const-prop after block is finished. Local: {:?}",
+                                place.local
+                            );
+                            self.locals_of_current_block.insert(place.local);
+                        }
+                        ConstPropMode::OnlyPropagateInto | ConstPropMode::NoPropagation => {
+                            trace!("can't propagate into {:?}", place);
+                            if place.local != RETURN_PLACE {
+                                Self::remove_const(&mut self.ecx, place.local);
+                            }
                         }
+                        ConstPropMode::FullConstProp => {}
                     }
                 } else {
                     // Const prop failed, so erase the destination, ensuring that whatever happens
@@ -906,6 +926,12 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
                     );
                     Self::remove_const(&mut self.ecx, place.local);
                 }
+            } else {
+                trace!(
+                    "cannot propagate into {:?}, because the type of the local is generic.",
+                    place,
+                );
+                Self::remove_const(&mut self.ecx, place.local);
             }
         } else {
             match statement.kind {
diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/32bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/32bit/rustc.main.ConstProp.diff
index 7071f31dbf1..7ceec94d81e 100644
--- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/32bit/rustc.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/32bit/rustc.main.ConstProp.diff
@@ -46,22 +46,8 @@
                                            // mir::Constant
                                            // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
                                            // + literal: Const { ty: usize, val: Value(Scalar(0x00000003)) }
--         _7 = Len((*_1));                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
--         _8 = Lt(_6, _7);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+         _7 = const 3usize;               // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // ty::Const
-+                                          // + ty: usize
-+                                          // + val: Value(Scalar(0x00000003))
-+                                          // mir::Constant
-+                                          // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // + literal: Const { ty: usize, val: Value(Scalar(0x00000003)) }
-+         _8 = const false;                // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // ty::Const
-+                                          // + ty: bool
-+                                          // + val: Value(Scalar(0x00))
-+                                          // mir::Constant
-+                                          // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          _7 = Len((*_1));                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+          _8 = Lt(_6, _7);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
           assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
       }
   
diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/64bit/rustc.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/64bit/rustc.main.ConstProp.diff
index 15995ab0700..483a6f232ef 100644
--- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/64bit/rustc.main.ConstProp.diff
+++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices/64bit/rustc.main.ConstProp.diff
@@ -46,22 +46,8 @@
                                            // mir::Constant
                                            // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24
                                            // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000003)) }
--         _7 = Len((*_1));                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
--         _8 = Lt(_6, _7);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+         _7 = const 3usize;               // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // ty::Const
-+                                          // + ty: usize
-+                                          // + val: Value(Scalar(0x0000000000000003))
-+                                          // mir::Constant
-+                                          // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000003)) }
-+         _8 = const false;                // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // ty::Const
-+                                          // + ty: bool
-+                                          // + val: Value(Scalar(0x00))
-+                                          // mir::Constant
-+                                          // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
-+                                          // + literal: Const { ty: bool, val: Value(Scalar(0x00)) }
+          _7 = Len((*_1));                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
+          _8 = Lt(_6, _7);                 // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
           assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25
       }
   
diff --git a/src/test/mir-opt/const_prop_miscompile.rs b/src/test/mir-opt/const_prop_miscompile.rs
new file mode 100644
index 00000000000..043b22870f4
--- /dev/null
+++ b/src/test/mir-opt/const_prop_miscompile.rs
@@ -0,0 +1,22 @@
+#![feature(raw_ref_op)]
+
+// EMIT_MIR rustc.foo.ConstProp.diff
+fn foo() {
+    let mut u = (1,);
+    *&mut u.0 = 5;
+    let y = { u.0 } == 5;
+}
+
+// EMIT_MIR rustc.bar.ConstProp.diff
+fn bar() {
+    let mut v = (1,);
+    unsafe {
+        *&raw mut v.0 = 5;
+    }
+    let y = { v.0 } == 5;
+}
+
+fn main() {
+    foo();
+    bar();
+}
diff --git a/src/test/mir-opt/const_prop_miscompile/rustc.bar.ConstProp.diff b/src/test/mir-opt/const_prop_miscompile/rustc.bar.ConstProp.diff
new file mode 100644
index 00000000000..c87f67bf9f5
--- /dev/null
+++ b/src/test/mir-opt/const_prop_miscompile/rustc.bar.ConstProp.diff
@@ -0,0 +1,75 @@
+- // MIR for `bar` before ConstProp
++ // MIR for `bar` after ConstProp
+  
+  fn bar() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/const_prop_miscompile.rs:11:10: 11:10
+      let mut _1: (i32,);                  // in scope 0 at $DIR/const_prop_miscompile.rs:12:9: 12:14
+      let _2: ();                          // in scope 0 at $DIR/const_prop_miscompile.rs:13:5: 15:6
+      let mut _3: *mut i32;                // in scope 0 at $DIR/const_prop_miscompile.rs:14:10: 14:22
+      let mut _5: i32;                     // in scope 0 at $DIR/const_prop_miscompile.rs:16:13: 16:20
+      scope 1 {
+          debug v => _1;                   // in scope 1 at $DIR/const_prop_miscompile.rs:12:9: 12:14
+          let _4: bool;                    // in scope 1 at $DIR/const_prop_miscompile.rs:16:9: 16:10
+          scope 2 {
+          }
+          scope 3 {
+              debug y => _4;               // in scope 3 at $DIR/const_prop_miscompile.rs:16:9: 16:10
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:12:9: 12:14
+-         _1 = (const 1i32,);              // scope 0 at $DIR/const_prop_miscompile.rs:12:17: 12:21
++         _1 = const (1i32,);              // scope 0 at $DIR/const_prop_miscompile.rs:12:17: 12:21
+                                           // ty::Const
+-                                          // + ty: i32
++                                          // + ty: (i32,)
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+-                                          // + span: $DIR/const_prop_miscompile.rs:12:18: 12:19
+-                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
++                                          // + span: $DIR/const_prop_miscompile.rs:12:17: 12:21
++                                          // + literal: Const { ty: (i32,), val: Value(Scalar(0x00000001)) }
+          StorageLive(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:13:5: 15:6
+          StorageLive(_3);                 // scope 2 at $DIR/const_prop_miscompile.rs:14:10: 14:22
+          _3 = &raw mut (_1.0: i32);       // scope 2 at $DIR/const_prop_miscompile.rs:14:10: 14:22
+          (*_3) = const 5i32;              // scope 2 at $DIR/const_prop_miscompile.rs:14:9: 14:26
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000005))
+                                           // mir::Constant
+                                           // + span: $DIR/const_prop_miscompile.rs:14:25: 14:26
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
+          StorageDead(_3);                 // scope 2 at $DIR/const_prop_miscompile.rs:14:26: 14:27
+          _2 = const ();                   // scope 2 at $DIR/const_prop_miscompile.rs:13:5: 15:6
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/const_prop_miscompile.rs:13:5: 15:6
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:15:5: 15:6
+          StorageLive(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:16:9: 16:10
+          StorageLive(_5);                 // scope 1 at $DIR/const_prop_miscompile.rs:16:13: 16:20
+          _5 = (_1.0: i32);                // scope 1 at $DIR/const_prop_miscompile.rs:16:15: 16:18
+          _4 = Eq(move _5, const 5i32);    // scope 1 at $DIR/const_prop_miscompile.rs:16:13: 16:25
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000005))
+                                           // mir::Constant
+                                           // + span: $DIR/const_prop_miscompile.rs:16:24: 16:25
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
+          StorageDead(_5);                 // scope 1 at $DIR/const_prop_miscompile.rs:16:24: 16:25
+          _0 = const ();                   // scope 0 at $DIR/const_prop_miscompile.rs:11:10: 17:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/const_prop_miscompile.rs:11:10: 17:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:17:1: 17:2
+          StorageDead(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:17:1: 17:2
+          return;                          // scope 0 at $DIR/const_prop_miscompile.rs:17:2: 17:2
+      }
+  }
+  
diff --git a/src/test/mir-opt/const_prop_miscompile/rustc.foo.ConstProp.diff b/src/test/mir-opt/const_prop_miscompile/rustc.foo.ConstProp.diff
new file mode 100644
index 00000000000..8a6850d2fe3
--- /dev/null
+++ b/src/test/mir-opt/const_prop_miscompile/rustc.foo.ConstProp.diff
@@ -0,0 +1,63 @@
+- // MIR for `foo` before ConstProp
++ // MIR for `foo` after ConstProp
+  
+  fn foo() -> () {
+      let mut _0: ();                      // return place in scope 0 at $DIR/const_prop_miscompile.rs:4:10: 4:10
+      let mut _1: (i32,);                  // in scope 0 at $DIR/const_prop_miscompile.rs:5:9: 5:14
+      let mut _2: &mut i32;                // in scope 0 at $DIR/const_prop_miscompile.rs:6:6: 6:14
+      let mut _4: i32;                     // in scope 0 at $DIR/const_prop_miscompile.rs:7:13: 7:20
+      scope 1 {
+          debug u => _1;                   // in scope 1 at $DIR/const_prop_miscompile.rs:5:9: 5:14
+          let _3: bool;                    // in scope 1 at $DIR/const_prop_miscompile.rs:7:9: 7:10
+          scope 2 {
+              debug y => _3;               // in scope 2 at $DIR/const_prop_miscompile.rs:7:9: 7:10
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:5:9: 5:14
+-         _1 = (const 1i32,);              // scope 0 at $DIR/const_prop_miscompile.rs:5:17: 5:21
++         _1 = const (1i32,);              // scope 0 at $DIR/const_prop_miscompile.rs:5:17: 5:21
+                                           // ty::Const
+-                                          // + ty: i32
++                                          // + ty: (i32,)
+                                           // + val: Value(Scalar(0x00000001))
+                                           // mir::Constant
+-                                          // + span: $DIR/const_prop_miscompile.rs:5:18: 5:19
+-                                          // + literal: Const { ty: i32, val: Value(Scalar(0x00000001)) }
++                                          // + span: $DIR/const_prop_miscompile.rs:5:17: 5:21
++                                          // + literal: Const { ty: (i32,), val: Value(Scalar(0x00000001)) }
+          StorageLive(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:6:6: 6:14
+          _2 = &mut (_1.0: i32);           // scope 1 at $DIR/const_prop_miscompile.rs:6:6: 6:14
+          (*_2) = const 5i32;              // scope 1 at $DIR/const_prop_miscompile.rs:6:5: 6:18
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000005))
+                                           // mir::Constant
+                                           // + span: $DIR/const_prop_miscompile.rs:6:17: 6:18
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
+          StorageDead(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:6:18: 6:19
+          StorageLive(_3);                 // scope 1 at $DIR/const_prop_miscompile.rs:7:9: 7:10
+          StorageLive(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:7:13: 7:20
+          _4 = (_1.0: i32);                // scope 1 at $DIR/const_prop_miscompile.rs:7:15: 7:18
+          _3 = Eq(move _4, const 5i32);    // scope 1 at $DIR/const_prop_miscompile.rs:7:13: 7:25
+                                           // ty::Const
+                                           // + ty: i32
+                                           // + val: Value(Scalar(0x00000005))
+                                           // mir::Constant
+                                           // + span: $DIR/const_prop_miscompile.rs:7:24: 7:25
+                                           // + literal: Const { ty: i32, val: Value(Scalar(0x00000005)) }
+          StorageDead(_4);                 // scope 1 at $DIR/const_prop_miscompile.rs:7:24: 7:25
+          _0 = const ();                   // scope 0 at $DIR/const_prop_miscompile.rs:4:10: 8:2
+                                           // ty::Const
+                                           // + ty: ()
+                                           // + val: Value(Scalar(<ZST>))
+                                           // mir::Constant
+                                           // + span: $DIR/const_prop_miscompile.rs:4:10: 8:2
+                                           // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+          StorageDead(_3);                 // scope 1 at $DIR/const_prop_miscompile.rs:8:1: 8:2
+          StorageDead(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:8:1: 8:2
+          return;                          // scope 0 at $DIR/const_prop_miscompile.rs:8:2: 8:2
+      }
+  }
+  
diff --git a/src/test/ui/mir/mir_detects_invalid_ops.rs b/src/test/ui/mir/mir_detects_invalid_ops.rs
index 0940dbe6a5e..136c03cd9f1 100644
--- a/src/test/ui/mir/mir_detects_invalid_ops.rs
+++ b/src/test/ui/mir/mir_detects_invalid_ops.rs
@@ -19,6 +19,6 @@ fn mod_by_zero() {
 fn oob_error_for_slices() {
     let a: *const [_] = &[1, 2, 3];
     unsafe {
-        let _b = (*a)[3]; //~ ERROR this operation will panic at runtime [unconditional_panic]
+        let _b = (*a)[3];
     }
 }
diff --git a/src/test/ui/mir/mir_detects_invalid_ops.stderr b/src/test/ui/mir/mir_detects_invalid_ops.stderr
index 41f03789f23..0b6dbfd7c3d 100644
--- a/src/test/ui/mir/mir_detects_invalid_ops.stderr
+++ b/src/test/ui/mir/mir_detects_invalid_ops.stderr
@@ -12,11 +12,5 @@ error: this operation will panic at runtime
 LL |     let _z = 1 % y;
    |              ^^^^^ attempt to calculate the remainder with a divisor of zero
 
-error: this operation will panic at runtime
-  --> $DIR/mir_detects_invalid_ops.rs:22:18
-   |
-LL |         let _b = (*a)[3];
-   |                  ^^^^^^^ index out of bounds: the len is 3 but the index is 3
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors