about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs29
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/liveness.rs9
-rw-r--r--compiler/rustc_mir_transform/src/dead_store_elimination.rs2
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs8
-rw-r--r--src/test/mir-opt/simplify-locals.rs7
-rw-r--r--src/test/mir-opt/simplify_locals.expose_addr.SimplifyLocals.diff21
6 files changed, 65 insertions, 11 deletions
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index f3db359ec33..f382812f163 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -2605,9 +2605,34 @@ pub enum Rvalue<'tcx> {
 static_assert_size!(Rvalue<'_>, 40);
 
 impl<'tcx> Rvalue<'tcx> {
+    /// Returns true if rvalue can be safely removed when the result is unused.
     #[inline]
-    pub fn is_pointer_int_cast(&self) -> bool {
-        matches!(self, Rvalue::Cast(CastKind::PointerExposeAddress, _, _))
+    pub fn is_safe_to_remove(&self) -> bool {
+        match self {
+            // Pointer to int casts may be side-effects due to exposing the provenance.
+            // While the model is undecided, we should be conservative. See
+            // <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html>
+            Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false,
+
+            Rvalue::Use(_)
+            | Rvalue::Repeat(_, _)
+            | Rvalue::Ref(_, _, _)
+            | Rvalue::ThreadLocalRef(_)
+            | Rvalue::AddressOf(_, _)
+            | Rvalue::Len(_)
+            | Rvalue::Cast(
+                CastKind::Misc | CastKind::Pointer(_) | CastKind::PointerFromExposedAddress,
+                _,
+                _,
+            )
+            | Rvalue::BinaryOp(_, _)
+            | Rvalue::CheckedBinaryOp(_, _)
+            | Rvalue::NullaryOp(_, _)
+            | Rvalue::UnaryOp(_, _)
+            | Rvalue::Discriminant(_)
+            | Rvalue::Aggregate(_, _)
+            | Rvalue::ShallowInitBox(_, _) => true,
+        }
     }
 }
 
diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
index 7076fbe1bdb..9b62ee5473c 100644
--- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -244,13 +244,10 @@ impl<'a, 'tcx> Analysis<'tcx> for MaybeTransitiveLiveLocals<'a> {
         // Compute the place that we are storing to, if any
         let destination = match &statement.kind {
             StatementKind::Assign(assign) => {
-                if assign.1.is_pointer_int_cast() {
-                    // Pointer to int casts may be side-effects due to exposing the provenance.
-                    // While the model is undecided, we should be conservative. See
-                    // <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html>
-                    None
-                } else {
+                if assign.1.is_safe_to_remove() {
                     Some(assign.0)
+                } else {
+                    None
                 }
             }
             StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => {
diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
index 8becac34ed7..779f3c77815 100644
--- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs
+++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
@@ -34,7 +34,7 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
         for (statement_index, statement) in bb_data.statements.iter().enumerate().rev() {
             let loc = Location { block: bb, statement_index };
             if let StatementKind::Assign(assign) = &statement.kind {
-                if assign.1.is_pointer_int_cast() {
+                if !assign.1.is_safe_to_remove() {
                     continue;
                 }
             }
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index 72e08343925..8a78ea5c82b 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -494,8 +494,12 @@ impl<'tcx> Visitor<'tcx> for UsedLocals {
             StatementKind::StorageLive(_local) | StatementKind::StorageDead(_local) => {}
 
             StatementKind::Assign(box (ref place, ref rvalue)) => {
-                self.visit_lhs(place, location);
-                self.visit_rvalue(rvalue, location);
+                if rvalue.is_safe_to_remove() {
+                    self.visit_lhs(place, location);
+                    self.visit_rvalue(rvalue, location);
+                } else {
+                    self.super_statement(statement, location);
+                }
             }
 
             StatementKind::SetDiscriminant { ref place, variant_index: _ }
diff --git a/src/test/mir-opt/simplify-locals.rs b/src/test/mir-opt/simplify-locals.rs
index 5862cf2eb29..f6bf396cd05 100644
--- a/src/test/mir-opt/simplify-locals.rs
+++ b/src/test/mir-opt/simplify-locals.rs
@@ -62,6 +62,12 @@ fn t4() -> u32 {
     unsafe { X + 1 }
 }
 
+// EMIT_MIR simplify_locals.expose_addr.SimplifyLocals.diff
+fn expose_addr(p: *const usize) {
+    // Used pointer to address cast. Has a side effect of exposing the provenance.
+    p as usize;
+}
+
 fn main() {
     c();
     d1();
@@ -71,4 +77,5 @@ fn main() {
     t2();
     t3();
     t4();
+    expose_addr(&0);
 }
diff --git a/src/test/mir-opt/simplify_locals.expose_addr.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals.expose_addr.SimplifyLocals.diff
new file mode 100644
index 00000000000..93d77ad40aa
--- /dev/null
+++ b/src/test/mir-opt/simplify_locals.expose_addr.SimplifyLocals.diff
@@ -0,0 +1,21 @@
+- // MIR for `expose_addr` before SimplifyLocals
++ // MIR for `expose_addr` after SimplifyLocals
+  
+  fn expose_addr(_1: *const usize) -> () {
+      debug p => _1;                       // in scope 0 at $DIR/simplify-locals.rs:66:16: 66:17
+      let mut _0: ();                      // return place in scope 0 at $DIR/simplify-locals.rs:66:33: 66:33
+      let _2: usize;                       // in scope 0 at $DIR/simplify-locals.rs:68:5: 68:15
+      let mut _3: *const usize;            // in scope 0 at $DIR/simplify-locals.rs:68:5: 68:6
+  
+      bb0: {
+          StorageLive(_2);                 // scope 0 at $DIR/simplify-locals.rs:68:5: 68:15
+          StorageLive(_3);                 // scope 0 at $DIR/simplify-locals.rs:68:5: 68:6
+          _3 = _1;                         // scope 0 at $DIR/simplify-locals.rs:68:5: 68:6
+          _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/simplify-locals.rs:68:5: 68:15
+          StorageDead(_3);                 // scope 0 at $DIR/simplify-locals.rs:68:14: 68:15
+          StorageDead(_2);                 // scope 0 at $DIR/simplify-locals.rs:68:15: 68:16
+          _0 = const ();                   // scope 0 at $DIR/simplify-locals.rs:66:33: 69:2
+          return;                          // scope 0 at $DIR/simplify-locals.rs:69:2: 69:2
+      }
+  }
+