From 1ffe9059c31d17ea1b22099b0f64de0232ebadd5 Mon Sep 17 00:00:00 2001
From: Camille GILLOT <gillot.camille@gmail.com>
Date: Fri, 28 Apr 2023 16:57:40 +0000
Subject: [PATCH] Reject borrows of projections in ConstProp.

---
 .../rustc_mir_transform/src/const_prop.rs     | 20 ++++++++++++++-----
 .../address_of_pair.fn0.ConstProp.diff        | 15 +++++---------
 .../const_prop_miscompile.bar.ConstProp.diff  |  3 +--
 .../const_prop_miscompile.foo.ConstProp.diff  |  3 +--
 4 files changed, 22 insertions(+), 19 deletions(-)

diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index b3a3a25ebe8..7f995c69a48 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -714,13 +714,22 @@ impl CanConstProp {
     }
 }
 
-impl Visitor<'_> for CanConstProp {
+impl<'tcx> Visitor<'tcx> for CanConstProp {
+    fn visit_place(&mut self, place: &Place<'tcx>, mut context: PlaceContext, loc: Location) {
+        use rustc_middle::mir::visit::PlaceContext::*;
+
+        // Dereferencing just read the addess of `place.local`.
+        if place.projection.first() == Some(&PlaceElem::Deref) {
+            context = NonMutatingUse(NonMutatingUseContext::Copy);
+        }
+
+        self.visit_local(place.local, context, loc);
+        self.visit_projection(place.as_ref(), context, loc);
+    }
+
     fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) {
         use rustc_middle::mir::visit::PlaceContext::*;
         match context {
-            // Projections are fine, because `&mut foo.x` will be caught by
-            // `MutatingUseContext::Borrow` elsewhere.
-            MutatingUse(MutatingUseContext::Projection)
             // These are just stores, where the storing is not propagatable, but there may be later
             // mutations of the same local via `Store`
             | MutatingUse(MutatingUseContext::Call)
@@ -751,7 +760,6 @@ impl Visitor<'_> for CanConstProp {
             NonMutatingUse(NonMutatingUseContext::Copy)
             | NonMutatingUse(NonMutatingUseContext::Move)
             | NonMutatingUse(NonMutatingUseContext::Inspect)
-            | NonMutatingUse(NonMutatingUseContext::Projection)
             | NonMutatingUse(NonMutatingUseContext::PlaceMention)
             | NonUse(_) => {}
 
@@ -771,6 +779,8 @@ impl Visitor<'_> for CanConstProp {
                 trace!("local {:?} can't be propagated because it's used: {:?}", local, context);
                 self.can_const_prop[local] = ConstPropMode::NoPropagation;
             }
+            MutatingUse(MutatingUseContext::Projection)
+            | NonMutatingUse(NonMutatingUseContext::Projection) => bug!("visit_place should not pass {context:?} for {local:?}"),
         }
     }
 }
diff --git a/tests/mir-opt/const_prop/address_of_pair.fn0.ConstProp.diff b/tests/mir-opt/const_prop/address_of_pair.fn0.ConstProp.diff
index 8a8e869ba03..d50b12044ce 100644
--- a/tests/mir-opt/const_prop/address_of_pair.fn0.ConstProp.diff
+++ b/tests/mir-opt/const_prop/address_of_pair.fn0.ConstProp.diff
@@ -23,25 +23,20 @@
   
       bb0: {
           StorageLive(_2);                 // scope 0 at $DIR/address_of_pair.rs:+1:9: +1:17
--         _2 = (const 1_i32, const false); // scope 0 at $DIR/address_of_pair.rs:+1:20: +1:30
-+         _2 = const (1_i32, false);       // scope 0 at $DIR/address_of_pair.rs:+1:20: +1:30
+          _2 = (const 1_i32, const false); // scope 0 at $DIR/address_of_pair.rs:+1:20: +1:30
           StorageLive(_3);                 // scope 1 at $DIR/address_of_pair.rs:+2:9: +2:12
           _3 = &raw mut (_2.1: bool);      // scope 1 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
--         _2 = (const 1_i32, const false); // scope 2 at $DIR/address_of_pair.rs:+3:5: +3:22
-+         _2 = const (1_i32, false);       // scope 2 at $DIR/address_of_pair.rs:+3:5: +3:22
+          _2 = (const 1_i32, const false); // scope 2 at $DIR/address_of_pair.rs:+3:5: +3:22
           StorageLive(_4);                 // scope 2 at $DIR/address_of_pair.rs:+4:5: +6:6
           (*_3) = const true;              // scope 3 at $DIR/address_of_pair.rs:+5:9: +5:20
           _4 = const ();                   // scope 3 at $DIR/address_of_pair.rs:+4:5: +6:6
           StorageDead(_4);                 // scope 2 at $DIR/address_of_pair.rs:+6:5: +6:6
           StorageLive(_5);                 // scope 2 at $DIR/address_of_pair.rs:+7:9: +7:12
           StorageLive(_6);                 // scope 2 at $DIR/address_of_pair.rs:+7:16: +7:22
--         _6 = (_2.1: bool);               // scope 2 at $DIR/address_of_pair.rs:+7:16: +7:22
--         _5 = Not(move _6);               // scope 2 at $DIR/address_of_pair.rs:+7:15: +7:22
-+         _6 = const false;                // scope 2 at $DIR/address_of_pair.rs:+7:16: +7:22
-+         _5 = const true;                 // scope 2 at $DIR/address_of_pair.rs:+7:15: +7:22
+          _6 = (_2.1: bool);               // scope 2 at $DIR/address_of_pair.rs:+7:16: +7:22
+          _5 = Not(move _6);               // scope 2 at $DIR/address_of_pair.rs:+7:15: +7:22
           StorageDead(_6);                 // scope 2 at $DIR/address_of_pair.rs:+7:21: +7:22
--         _0 = _5;                         // scope 4 at $DIR/address_of_pair.rs:+8:12: +8:15
-+         _0 = const true;                 // scope 4 at $DIR/address_of_pair.rs:+8:12: +8:15
+          _0 = _5;                         // scope 4 at $DIR/address_of_pair.rs:+8:12: +8:15
           StorageDead(_5);                 // scope 2 at $DIR/address_of_pair.rs:+9:1: +9:2
           StorageDead(_3);                 // scope 1 at $DIR/address_of_pair.rs:+9:1: +9:2
           StorageDead(_2);                 // scope 0 at $DIR/address_of_pair.rs:+9:1: +9:2
diff --git a/tests/mir-opt/const_prop_miscompile.bar.ConstProp.diff b/tests/mir-opt/const_prop_miscompile.bar.ConstProp.diff
index def9fc6428f..a5f52d08957 100644
--- a/tests/mir-opt/const_prop_miscompile.bar.ConstProp.diff
+++ b/tests/mir-opt/const_prop_miscompile.bar.ConstProp.diff
@@ -19,8 +19,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:+1:9: +1:14
--         _1 = (const 1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
-+         _1 = const (1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
+          _1 = (const 1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
           StorageLive(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:+2:5: +4:6
           StorageLive(_3);                 // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
           _3 = &raw mut (_1.0: i32);       // scope 2 at $DIR/const_prop_miscompile.rs:+3:10: +3:22
diff --git a/tests/mir-opt/const_prop_miscompile.foo.ConstProp.diff b/tests/mir-opt/const_prop_miscompile.foo.ConstProp.diff
index b54c10a140f..42ddc2a5620 100644
--- a/tests/mir-opt/const_prop_miscompile.foo.ConstProp.diff
+++ b/tests/mir-opt/const_prop_miscompile.foo.ConstProp.diff
@@ -16,8 +16,7 @@
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/const_prop_miscompile.rs:+1:9: +1:14
--         _1 = (const 1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
-+         _1 = const (1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
+          _1 = (const 1_i32,);             // scope 0 at $DIR/const_prop_miscompile.rs:+1:17: +1:21
           StorageLive(_2);                 // scope 1 at $DIR/const_prop_miscompile.rs:+2:6: +2:14
           _2 = &mut (_1.0: i32);           // scope 1 at $DIR/const_prop_miscompile.rs:+2:6: +2:14
           (*_2) = const 5_i32;             // scope 1 at $DIR/const_prop_miscompile.rs:+2:5: +2:18