about summary refs log tree commit diff
path: root/compiler/rustc_mir_transform/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-08-23 05:07:11 +0000
committerbors <bors@rust-lang.org>2025-08-23 05:07:11 +0000
commit8df154bffddcb6bbb543ad69aff971795c5adbc2 (patch)
treefb7a190550397be91be94378598f5154cebbdba6 /compiler/rustc_mir_transform/src
parent78b89ebb6b20cf50370335e14c5357a4388ac760 (diff)
parent418bbb283fca5e7ee5ebe30646a4dd7ae62698ea (diff)
downloadrust-8df154bffddcb6bbb543ad69aff971795c5adbc2.tar.gz
rust-8df154bffddcb6bbb543ad69aff971795c5adbc2.zip
Auto merge of #145773 - jhpratt:rollup-kocqnzv, r=jhpratt
Rollup of 28 pull requests

Successful merges:

 - rust-lang/rust#132087 (Fix overly restrictive lifetime in `core::panic::Location::file` return type)
 - rust-lang/rust#137396 (Recover `param: Ty = EXPR`)
 - rust-lang/rust#137457 (Fix host code appearing in Wasm binaries)
 - rust-lang/rust#142185 (Convert moves of references to copies in ReferencePropagation)
 - rust-lang/rust#144648 (Implementation: `#[feature(nonpoison_rwlock)]`)
 - rust-lang/rust#144897 (print raw lifetime idents with r#)
 - rust-lang/rust#145218 ([Debuginfo] improve enum value formatting in LLDB for better readability)
 - rust-lang/rust#145380 (Add codegen-llvm regression tests)
 - rust-lang/rust#145573 (Add an experimental unsafe(force_target_feature) attribute.)
 - rust-lang/rust#145597 (resolve: Remove `ScopeSet::Late`)
 - rust-lang/rust#145633 (Fix some typos in LocalKey documentation)
 - rust-lang/rust#145641 (On E0277, point at type that doesn't implement bound)
 - rust-lang/rust#145669 (rustdoc-search: GUI tests check for `//` in URL)
 - rust-lang/rust#145695 (Introduce ProjectionElem::try_map.)
 - rust-lang/rust#145710 (Fix the ABI parameter inconsistency issue in debug.rs for LoongArch64)
 - rust-lang/rust#145726 (Experiment: Reborrow trait)
 - rust-lang/rust#145731 (Make raw pointers work in type-based search)
 - rust-lang/rust#145736 (triagebot: Update style team reviewers)
 - rust-lang/rust#145738 (Uplift rustc_mir_transform::coverage::counters::union_find to rustc_data_structures.)
 - rust-lang/rust#145742 (rustdoc js: Even more typechecking improvments )
 - rust-lang/rust#145743 (doc: fix some typos in comment)
 - rust-lang/rust#145745 (tests: Ignore basic-stepping.rs on LoongArch)
 - rust-lang/rust#145747 (Refactor lint buffering to avoid requiring a giant enum)
 - rust-lang/rust#145751 (fix(lexer): Allow '-' in the frontmatter infostring continue set)
 - rust-lang/rust#145761 (Add aarch64_be-unknown-hermit target)
 - rust-lang/rust#145762 (convert strings to symbols in attr diagnostics)
 - rust-lang/rust#145763 (Ship LLVM tools for the correct target when cross-compiling)
 - rust-lang/rust#145765 (Revert suggestions for missing methods in tuples)

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler/rustc_mir_transform/src')
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters.rs1
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs3
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters/union_find.rs96
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters/union_find/tests.rs32
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs62
-rw-r--r--compiler/rustc_mir_transform/src/ref_prop.rs39
6 files changed, 52 insertions, 181 deletions
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index 5568d42ab8f..879a20e771d 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -16,7 +16,6 @@ use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
 
 mod balanced_flow;
 pub(crate) mod node_flow;
-mod union_find;
 
 /// Struct containing the results of [`prepare_bcb_counters_data`].
 pub(crate) struct BcbCountersData {
diff --git a/compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs b/compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs
index 91ed54b8b59..e063f75887b 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters/node_flow.rs
@@ -7,13 +7,12 @@
 //! (Knuth & Stevenson, 1973).
 
 use rustc_data_structures::graph;
+use rustc_data_structures::union_find::UnionFind;
 use rustc_index::bit_set::DenseBitSet;
 use rustc_index::{Idx, IndexSlice, IndexVec};
 pub(crate) use rustc_middle::mir::coverage::NodeFlowData;
 use rustc_middle::mir::coverage::Op;
 
-use crate::coverage::counters::union_find::UnionFind;
-
 #[cfg(test)]
 mod tests;
 
diff --git a/compiler/rustc_mir_transform/src/coverage/counters/union_find.rs b/compiler/rustc_mir_transform/src/coverage/counters/union_find.rs
deleted file mode 100644
index a826a953fa6..00000000000
--- a/compiler/rustc_mir_transform/src/coverage/counters/union_find.rs
+++ /dev/null
@@ -1,96 +0,0 @@
-use std::cmp::Ordering;
-use std::mem;
-
-use rustc_index::{Idx, IndexVec};
-
-#[cfg(test)]
-mod tests;
-
-/// Simple implementation of a union-find data structure, i.e. a disjoint-set
-/// forest.
-#[derive(Debug)]
-pub(crate) struct UnionFind<Key: Idx> {
-    table: IndexVec<Key, UnionFindEntry<Key>>,
-}
-
-#[derive(Debug)]
-struct UnionFindEntry<Key> {
-    /// Transitively points towards the "root" of the set containing this key.
-    ///
-    /// Invariant: A root key is its own parent.
-    parent: Key,
-    /// When merging two "root" keys, their ranks determine which key becomes
-    /// the new root, to prevent the parent tree from becoming unnecessarily
-    /// tall. See [`UnionFind::unify`] for details.
-    rank: u32,
-}
-
-impl<Key: Idx> UnionFind<Key> {
-    /// Creates a new disjoint-set forest containing the keys `0..num_keys`.
-    /// Initially, every key is part of its own one-element set.
-    pub(crate) fn new(num_keys: usize) -> Self {
-        // Initially, every key is the root of its own set, so its parent is itself.
-        Self { table: IndexVec::from_fn_n(|key| UnionFindEntry { parent: key, rank: 0 }, num_keys) }
-    }
-
-    /// Returns the "root" key of the disjoint-set containing the given key.
-    /// If two keys have the same root, they belong to the same set.
-    ///
-    /// Also updates internal data structures to make subsequent `find`
-    /// operations faster.
-    pub(crate) fn find(&mut self, key: Key) -> Key {
-        // Loop until we find a key that is its own parent.
-        let mut curr = key;
-        while let parent = self.table[curr].parent
-            && curr != parent
-        {
-            // Perform "path compression" by peeking one layer ahead, and
-            // setting the current key's parent to that value.
-            // (This works even when `parent` is the root of its set, because
-            // of the invariant that a root is its own parent.)
-            let parent_parent = self.table[parent].parent;
-            self.table[curr].parent = parent_parent;
-
-            // Advance by one step and continue.
-            curr = parent;
-        }
-        curr
-    }
-
-    /// Merges the set containing `a` and the set containing `b` into one set.
-    ///
-    /// Returns the common root of both keys, after the merge.
-    pub(crate) fn unify(&mut self, a: Key, b: Key) -> Key {
-        let mut a = self.find(a);
-        let mut b = self.find(b);
-
-        // If both keys have the same root, they're already in the same set,
-        // so there's nothing more to do.
-        if a == b {
-            return a;
-        };
-
-        // Ensure that `a` has strictly greater rank, swapping if necessary.
-        // If both keys have the same rank, increment the rank of `a` so that
-        // future unifications will also prefer `a`, leading to flatter trees.
-        match Ord::cmp(&self.table[a].rank, &self.table[b].rank) {
-            Ordering::Less => mem::swap(&mut a, &mut b),
-            Ordering::Equal => self.table[a].rank += 1,
-            Ordering::Greater => {}
-        }
-
-        debug_assert!(self.table[a].rank > self.table[b].rank);
-        debug_assert_eq!(self.table[b].parent, b);
-
-        // Make `a` the parent of `b`.
-        self.table[b].parent = a;
-
-        a
-    }
-
-    /// Takes a "snapshot" of the current state of this disjoint-set forest, in
-    /// the form of a vector that directly maps each key to its current root.
-    pub(crate) fn snapshot(&mut self) -> IndexVec<Key, Key> {
-        self.table.indices().map(|key| self.find(key)).collect()
-    }
-}
diff --git a/compiler/rustc_mir_transform/src/coverage/counters/union_find/tests.rs b/compiler/rustc_mir_transform/src/coverage/counters/union_find/tests.rs
deleted file mode 100644
index 34a4e4f8e6e..00000000000
--- a/compiler/rustc_mir_transform/src/coverage/counters/union_find/tests.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-use super::UnionFind;
-
-#[test]
-fn empty() {
-    let mut sets = UnionFind::<u32>::new(10);
-
-    for i in 1..10 {
-        assert_eq!(sets.find(i), i);
-    }
-}
-
-#[test]
-fn transitive() {
-    let mut sets = UnionFind::<u32>::new(10);
-
-    sets.unify(3, 7);
-    sets.unify(4, 2);
-
-    assert_eq!(sets.find(7), sets.find(3));
-    assert_eq!(sets.find(2), sets.find(4));
-    assert_ne!(sets.find(3), sets.find(4));
-
-    sets.unify(7, 4);
-
-    assert_eq!(sets.find(7), sets.find(3));
-    assert_eq!(sets.find(2), sets.find(4));
-    assert_eq!(sets.find(3), sets.find(4));
-
-    for i in [0, 1, 5, 6, 8, 9] {
-        assert_eq!(sets.find(i), i);
-    }
-}
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 952da2cdf72..5a13394543b 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -447,26 +447,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
 
             Projection(base, elem) => {
                 let base = self.evaluated[base].as_ref()?;
-                let elem = match elem {
-                    ProjectionElem::Deref => ProjectionElem::Deref,
-                    ProjectionElem::Downcast(name, read_variant) => {
-                        ProjectionElem::Downcast(name, read_variant)
-                    }
-                    ProjectionElem::Field(f, ()) => ProjectionElem::Field(f, ty.ty),
-                    ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
-                        ProjectionElem::ConstantIndex { offset, min_length, from_end }
-                    }
-                    ProjectionElem::Subslice { from, to, from_end } => {
-                        ProjectionElem::Subslice { from, to, from_end }
-                    }
-                    ProjectionElem::OpaqueCast(()) => ProjectionElem::OpaqueCast(ty.ty),
-                    ProjectionElem::Subtype(()) => ProjectionElem::Subtype(ty.ty),
-                    ProjectionElem::UnwrapUnsafeBinder(()) => {
-                        ProjectionElem::UnwrapUnsafeBinder(ty.ty)
-                    }
-                    // This should have been replaced by a `ConstantIndex` earlier.
-                    ProjectionElem::Index(_) => return None,
-                };
+                // `Index` by constants should have been replaced by `ConstantIndex` by
+                // `simplify_place_projection`.
+                let elem = elem.try_map(|_| None, |()| ty.ty)?;
                 self.ecx.project(base, elem).discard_err()?
             }
             Address { place, kind: _, provenance: _ } => {
@@ -476,13 +459,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 let local = self.locals[place.local]?;
                 let pointer = self.evaluated[local].as_ref()?;
                 let mut mplace = self.ecx.deref_pointer(pointer).discard_err()?;
-                for proj in place.projection.iter().skip(1) {
-                    // We have no call stack to associate a local with a value, so we cannot
-                    // interpret indexing.
-                    if matches!(proj, ProjectionElem::Index(_)) {
-                        return None;
-                    }
-                    mplace = self.ecx.project(&mplace, proj).discard_err()?;
+                for elem in place.projection.iter().skip(1) {
+                    // `Index` by constants should have been replaced by `ConstantIndex` by
+                    // `simplify_place_projection`.
+                    let elem = elem.try_map(|_| None, |ty| ty)?;
+                    mplace = self.ecx.project(&mplace, elem).discard_err()?;
                 }
                 let pointer = mplace.to_ref(&self.ecx);
                 ImmTy::from_immediate(pointer, ty).into()
@@ -902,27 +883,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         proj: ProjectionElem<VnIndex, ()>,
         loc: Location,
     ) -> Option<PlaceElem<'tcx>> {
-        Some(match proj {
-            ProjectionElem::Deref => ProjectionElem::Deref,
-            ProjectionElem::Field(idx, ()) => ProjectionElem::Field(idx, ty),
-            ProjectionElem::Index(idx) => {
-                let Some(local) = self.try_as_local(idx, loc) else {
-                    return None;
-                };
+        proj.try_map(
+            |value| {
+                let local = self.try_as_local(value, loc)?;
                 self.reused_locals.insert(local);
-                ProjectionElem::Index(local)
-            }
-            ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
-                ProjectionElem::ConstantIndex { offset, min_length, from_end }
-            }
-            ProjectionElem::Subslice { from, to, from_end } => {
-                ProjectionElem::Subslice { from, to, from_end }
-            }
-            ProjectionElem::Downcast(symbol, idx) => ProjectionElem::Downcast(symbol, idx),
-            ProjectionElem::OpaqueCast(()) => ProjectionElem::OpaqueCast(ty),
-            ProjectionElem::Subtype(()) => ProjectionElem::Subtype(ty),
-            ProjectionElem::UnwrapUnsafeBinder(()) => ProjectionElem::UnwrapUnsafeBinder(ty),
-        })
+                Some(local)
+            },
+            |()| ty,
+        )
     }
 
     fn simplify_aggregate_to_copy(
diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs
index d1c2d6b508f..6f61215cee2 100644
--- a/compiler/rustc_mir_transform/src/ref_prop.rs
+++ b/compiler/rustc_mir_transform/src/ref_prop.rs
@@ -79,6 +79,7 @@ impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation {
     #[instrument(level = "trace", skip(self, tcx, body))]
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         debug!(def_id = ?body.source.def_id());
+        move_to_copy_pointers(tcx, body);
         while propagate_ssa(tcx, body) {}
     }
 
@@ -87,11 +88,43 @@ impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation {
     }
 }
 
+/// The SSA analysis done by [`SsaLocals`] treats [`Operand::Move`] as a read, even though in
+/// general [`Operand::Move`] represents pass-by-pointer where the callee can overwrite the
+/// pointee (Miri always considers the place deinitialized). CopyProp has a similar trick to
+/// turn [`Operand::Move`] into [`Operand::Copy`] when required for an optimization, but in this
+/// pass we just turn all moves of pointers into copies because pointers should be by-value anyway.
+fn move_to_copy_pointers<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+    let mut visitor = MoveToCopyVisitor { tcx, local_decls: &body.local_decls };
+    for (bb, data) in body.basic_blocks.as_mut_preserves_cfg().iter_enumerated_mut() {
+        visitor.visit_basic_block_data(bb, data);
+    }
+
+    struct MoveToCopyVisitor<'a, 'tcx> {
+        tcx: TyCtxt<'tcx>,
+        local_decls: &'a IndexVec<Local, LocalDecl<'tcx>>,
+    }
+
+    impl<'a, 'tcx> MutVisitor<'tcx> for MoveToCopyVisitor<'a, 'tcx> {
+        fn tcx(&self) -> TyCtxt<'tcx> {
+            self.tcx
+        }
+
+        fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) {
+            if let Operand::Move(place) = *operand {
+                if place.ty(self.local_decls, self.tcx).ty.is_any_ptr() {
+                    *operand = Operand::Copy(place);
+                }
+            }
+            self.super_operand(operand, loc);
+        }
+    }
+}
+
 fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
     let typing_env = body.typing_env(tcx);
     let ssa = SsaLocals::new(tcx, body, typing_env);
 
-    let mut replacer = compute_replacement(tcx, body, &ssa);
+    let mut replacer = compute_replacement(tcx, body, ssa);
     debug!(?replacer.targets);
     debug!(?replacer.allowed_replacements);
     debug!(?replacer.storage_to_remove);
@@ -119,7 +152,7 @@ enum Value<'tcx> {
 fn compute_replacement<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
-    ssa: &SsaLocals,
+    ssa: SsaLocals,
 ) -> Replacer<'tcx> {
     let always_live_locals = always_storage_live_locals(body);
 
@@ -138,7 +171,7 @@ fn compute_replacement<'tcx>(
     // reborrowed references.
     let mut storage_to_remove = DenseBitSet::new_empty(body.local_decls.len());
 
-    let fully_replaceable_locals = fully_replaceable_locals(ssa);
+    let fully_replaceable_locals = fully_replaceable_locals(&ssa);
 
     // Returns true iff we can use `place` as a pointee.
     //