about summary refs log tree commit diff
path: root/compiler/rustc_mir_transform/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_mir_transform/src')
-rw-r--r--compiler/rustc_mir_transform/src/abort_unwinding_calls.rs12
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs20
-rw-r--r--compiler/rustc_mir_transform/src/coroutine/by_move_body.rs2
-rw-r--r--compiler/rustc_mir_transform/src/coverage/graph.rs177
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs100
-rw-r--r--compiler/rustc_mir_transform/src/cross_crate_inline.rs10
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs14
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_box_derefs.rs2
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drops.rs2
-rw-r--r--compiler/rustc_mir_transform/src/errors.rs6
-rw-r--r--compiler/rustc_mir_transform/src/ffi_unwind_calls.rs14
-rw-r--r--compiler/rustc_mir_transform/src/function_item_references.rs4
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs7
-rw-r--r--compiler/rustc_mir_transform/src/instsimplify.rs6
-rw-r--r--compiler/rustc_mir_transform/src/jump_threading.rs2
-rw-r--r--compiler/rustc_mir_transform/src/large_enums.rs10
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs204
-rw-r--r--compiler/rustc_mir_transform/src/match_branches.rs2
-rw-r--r--compiler/rustc_mir_transform/src/pass_manager.rs34
-rw-r--r--compiler/rustc_mir_transform/src/remove_uninit_drops.rs2
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs5
-rw-r--r--compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs2
-rw-r--r--compiler/rustc_mir_transform/src/sroa.rs2
-rw-r--r--compiler/rustc_mir_transform/src/unreachable_prop.rs2
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs9
25 files changed, 374 insertions, 276 deletions
diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
index 84c8a91b082..03f11885d58 100644
--- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
+++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
@@ -1,9 +1,9 @@
+use rustc_abi::ExternAbi;
 use rustc_ast::InlineAsmOptions;
 use rustc_middle::mir::*;
 use rustc_middle::span_bug;
 use rustc_middle::ty::{self, TyCtxt, layout};
 use rustc_target::spec::PanicStrategy;
-use rustc_target::spec::abi::Abi;
 
 /// A pass that runs which is targeted at ensuring that codegen guarantees about
 /// unwinding are upheld for compilations of panic=abort programs.
@@ -38,9 +38,9 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls {
         let body_ty = tcx.type_of(def_id).skip_binder();
         let body_abi = match body_ty.kind() {
             ty::FnDef(..) => body_ty.fn_sig(tcx).abi(),
-            ty::Closure(..) => Abi::RustCall,
-            ty::CoroutineClosure(..) => Abi::RustCall,
-            ty::Coroutine(..) => Abi::Rust,
+            ty::Closure(..) => ExternAbi::RustCall,
+            ty::CoroutineClosure(..) => ExternAbi::RustCall,
+            ty::Coroutine(..) => ExternAbi::Rust,
             ty::Error(_) => return,
             _ => span_bug!(body.span, "unexpected body ty: {:?}", body_ty),
         };
@@ -79,10 +79,10 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls {
                 }
                 TerminatorKind::Drop { .. } => {
                     tcx.sess.opts.unstable_opts.panic_in_drop == PanicStrategy::Unwind
-                        && layout::fn_can_unwind(tcx, None, Abi::Rust)
+                        && layout::fn_can_unwind(tcx, None, ExternAbi::Rust)
                 }
                 TerminatorKind::Assert { .. } | TerminatorKind::FalseUnwind { .. } => {
-                    layout::fn_can_unwind(tcx, None, Abi::Rust)
+                    layout::fn_can_unwind(tcx, None, ExternAbi::Rust)
                 }
                 TerminatorKind::InlineAsm { options, .. } => {
                     options.contains(InlineAsmOptions::MAY_UNWIND)
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 6d5665b4331..c2666caa1e8 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -54,6 +54,7 @@ mod by_move_body;
 use std::{iter, ops};
 
 pub(super) use by_move_body::coroutine_by_move_body_def_id;
+use rustc_abi::{FieldIdx, VariantIdx};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::pluralize;
 use rustc_hir as hir;
@@ -67,15 +68,14 @@ use rustc_middle::ty::{
     self, CoroutineArgs, CoroutineArgsExt, GenericArgsRef, InstanceKind, Ty, TyCtxt, TypingMode,
 };
 use rustc_middle::{bug, span_bug};
-use rustc_mir_dataflow::Analysis;
 use rustc_mir_dataflow::impls::{
     MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,
 };
 use rustc_mir_dataflow::storage::always_storage_live_locals;
+use rustc_mir_dataflow::{Analysis, Results, ResultsVisitor};
 use rustc_span::Span;
 use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::symbol::sym;
-use rustc_target::abi::{FieldIdx, VariantIdx};
 use rustc_target::spec::PanicStrategy;
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::infer::TyCtxtInferExt as _;
@@ -817,9 +817,9 @@ impl ops::Deref for CoroutineSavedLocals {
 /// computation; see `CoroutineLayout` for more.
 fn compute_storage_conflicts<'mir, 'tcx>(
     body: &'mir Body<'tcx>,
-    saved_locals: &CoroutineSavedLocals,
+    saved_locals: &'mir CoroutineSavedLocals,
     always_live_locals: BitSet<Local>,
-    mut requires_storage: rustc_mir_dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
+    mut requires_storage: Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
 ) -> BitMatrix<CoroutineSavedLocal, CoroutineSavedLocal> {
     assert_eq!(body.local_decls.len(), saved_locals.domain_size());
 
@@ -877,15 +877,13 @@ struct StorageConflictVisitor<'a, 'tcx> {
     eligible_storage_live: BitSet<Local>,
 }
 
-impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
+impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, MaybeRequiresStorage<'a, 'tcx>>
     for StorageConflictVisitor<'a, 'tcx>
 {
-    type Domain = BitSet<Local>;
-
     fn visit_statement_before_primary_effect(
         &mut self,
-        _results: &mut R,
-        state: &Self::Domain,
+        _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
+        state: &BitSet<Local>,
         _statement: &'a Statement<'tcx>,
         loc: Location,
     ) {
@@ -894,8 +892,8 @@ impl<'a, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'a, 'tcx, R>
 
     fn visit_terminator_before_primary_effect(
         &mut self,
-        _results: &mut R,
-        state: &Self::Domain,
+        _results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
+        state: &BitSet<Local>,
         _terminator: &'a Terminator<'tcx>,
         loc: Location,
     ) {
diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
index 2c622b1927e..36eb435c63a 100644
--- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
+++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
@@ -69,6 +69,7 @@
 //! in case precise captures (edition 2021 closure capture rules) caused the inner coroutine
 //! to split one field capture into two.
 
+use rustc_abi::{FieldIdx, VariantIdx};
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::unord::UnordMap;
 use rustc_hir as hir;
@@ -80,7 +81,6 @@ use rustc_middle::mir::visit::MutVisitor;
 use rustc_middle::mir::{self, dump_mir};
 use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::symbol::kw;
-use rustc_target::abi::{FieldIdx, VariantIdx};
 
 pub(crate) fn coroutine_by_move_body_def_id<'tcx>(
     tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index 168262bf01c..092bce1de2c 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -1,7 +1,7 @@
 use std::cmp::Ordering;
 use std::collections::VecDeque;
-use std::iter;
 use std::ops::{Index, IndexMut};
+use std::{iter, mem, slice};
 
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
@@ -127,10 +127,10 @@ impl CoverageGraph {
         let mut bcbs = IndexVec::<BasicCoverageBlock, _>::with_capacity(num_basic_blocks);
         let mut bb_to_bcb = IndexVec::from_elem_n(None, num_basic_blocks);
 
-        let mut add_basic_coverage_block = |basic_blocks: &mut Vec<BasicBlock>| {
+        let mut flush_chain_into_new_bcb = |current_chain: &mut Vec<BasicBlock>| {
             // Take the accumulated list of blocks, leaving the vector empty
             // to be used by subsequent BCBs.
-            let basic_blocks = std::mem::take(basic_blocks);
+            let basic_blocks = mem::take(current_chain);
 
             let bcb = bcbs.next_index();
             for &bb in basic_blocks.iter() {
@@ -141,48 +141,41 @@ impl CoverageGraph {
                 bcb_filtered_successors(mir_body[bb].terminator()).is_out_summable()
             });
             let bcb_data = BasicCoverageBlockData { basic_blocks, is_out_summable };
-            debug!("adding bcb{}: {:?}", bcb.index(), bcb_data);
+            debug!("adding {bcb:?}: {bcb_data:?}");
             bcbs.push(bcb_data);
         };
 
-        // Walk the MIR CFG using a Preorder traversal, which starts from `START_BLOCK` and follows
-        // each block terminator's `successors()`. Coverage spans must map to actual source code,
-        // so compiler generated blocks and paths can be ignored. To that end, the CFG traversal
-        // intentionally omits unwind paths.
-        // FIXME(#78544): MIR InstrumentCoverage: Improve coverage of `#[should_panic]` tests and
-        // `catch_unwind()` handlers.
+        // Traverse the MIR control-flow graph, accumulating chains of blocks
+        // that can be combined into a single node in the coverage graph.
+        // A depth-first search ensures that if two nodes can be chained
+        // together, they will be adjacent in the traversal order.
 
         // Accumulates a chain of blocks that will be combined into one BCB.
-        let mut basic_blocks = Vec::new();
+        let mut current_chain = vec![];
 
-        let filtered_successors = |bb| bcb_filtered_successors(mir_body[bb].terminator());
-        for bb in short_circuit_preorder(mir_body, filtered_successors)
+        let subgraph = CoverageRelevantSubgraph::new(&mir_body.basic_blocks);
+        for bb in graph::depth_first_search(subgraph, mir::START_BLOCK)
             .filter(|&bb| mir_body[bb].terminator().kind != TerminatorKind::Unreachable)
         {
-            // If the previous block can't be chained into `bb`, flush the accumulated
-            // blocks into a new BCB, then start building the next chain.
-            if let Some(&prev) = basic_blocks.last()
-                && (!filtered_successors(prev).is_chainable() || {
-                    // If `bb` has multiple predecessor blocks, or `prev` isn't
-                    // one of its predecessors, we can't chain and must flush.
-                    let predecessors = &mir_body.basic_blocks.predecessors()[bb];
-                    predecessors.len() > 1 || !predecessors.contains(&prev)
-                })
-            {
-                debug!(
-                    terminator_kind = ?mir_body[prev].terminator().kind,
-                    predecessors = ?&mir_body.basic_blocks.predecessors()[bb],
-                    "can't chain from {prev:?} to {bb:?}"
-                );
-                add_basic_coverage_block(&mut basic_blocks);
+            if let Some(&prev) = current_chain.last() {
+                // Adding a block to a non-empty chain is allowed if the
+                // previous block permits chaining, and the current block has
+                // `prev` as its sole predecessor.
+                let can_chain = subgraph.coverage_successors(prev).is_out_chainable()
+                    && mir_body.basic_blocks.predecessors()[bb].as_slice() == &[prev];
+                if !can_chain {
+                    // The current block can't be added to the existing chain, so
+                    // flush that chain into a new BCB, and start a new chain.
+                    flush_chain_into_new_bcb(&mut current_chain);
+                }
             }
 
-            basic_blocks.push(bb);
+            current_chain.push(bb);
         }
 
-        if !basic_blocks.is_empty() {
+        if !current_chain.is_empty() {
             debug!("flushing accumulated blocks into one last BCB");
-            add_basic_coverage_block(&mut basic_blocks);
+            flush_chain_into_new_bcb(&mut current_chain);
         }
 
         (bcbs, bb_to_bcb)
@@ -389,34 +382,28 @@ impl BasicCoverageBlockData {
 /// indicates whether that block can potentially be combined into the same BCB
 /// as its sole successor.
 #[derive(Clone, Copy, Debug)]
-enum CoverageSuccessors<'a> {
-    /// The terminator has exactly one straight-line successor, so its block can
-    /// potentially be combined into the same BCB as that successor.
-    Chainable(BasicBlock),
-    /// The block cannot be combined into the same BCB as its successor(s).
-    NotChainable(&'a [BasicBlock]),
-    /// Yield terminators are not chainable, and their execution count can also
-    /// differ from the execution count of their out-edge.
-    Yield(BasicBlock),
+struct CoverageSuccessors<'a> {
+    /// Coverage-relevant successors of the corresponding terminator.
+    /// There might be 0, 1, or multiple targets.
+    targets: &'a [BasicBlock],
+    /// `Yield` terminators are not chainable, because their sole out-edge is
+    /// only followed if/when the generator is resumed after the yield.
+    is_yield: bool,
 }
 
 impl CoverageSuccessors<'_> {
-    fn is_chainable(&self) -> bool {
-        match self {
-            Self::Chainable(_) => true,
-            Self::NotChainable(_) => false,
-            Self::Yield(_) => false,
-        }
+    /// If `false`, this terminator cannot be chained into another block when
+    /// building the coverage graph.
+    fn is_out_chainable(&self) -> bool {
+        // If a terminator is out-summable and has exactly one out-edge, then
+        // it is eligible to be chained into its successor block.
+        self.is_out_summable() && self.targets.len() == 1
     }
 
     /// Returns true if the terminator itself is assumed to have the same
     /// execution count as the sum of its out-edges (assuming no panics).
     fn is_out_summable(&self) -> bool {
-        match self {
-            Self::Chainable(_) => true,
-            Self::NotChainable(_) => true,
-            Self::Yield(_) => false,
-        }
+        !self.is_yield && !self.targets.is_empty()
     }
 }
 
@@ -425,12 +412,7 @@ impl IntoIterator for CoverageSuccessors<'_> {
     type IntoIter = impl DoubleEndedIterator<Item = Self::Item>;
 
     fn into_iter(self) -> Self::IntoIter {
-        match self {
-            Self::Chainable(bb) | Self::Yield(bb) => {
-                Some(bb).into_iter().chain((&[]).iter().copied())
-            }
-            Self::NotChainable(bbs) => None.into_iter().chain(bbs.iter().copied()),
-        }
+        self.targets.iter().copied()
     }
 }
 
@@ -440,14 +422,17 @@ impl IntoIterator for CoverageSuccessors<'_> {
 // `catch_unwind()` handlers.
 fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> CoverageSuccessors<'a> {
     use TerminatorKind::*;
-    match terminator.kind {
+    let mut is_yield = false;
+    let targets = match &terminator.kind {
         // A switch terminator can have many coverage-relevant successors.
-        // (If there is exactly one successor, we still treat it as not chainable.)
-        SwitchInt { ref targets, .. } => CoverageSuccessors::NotChainable(targets.all_targets()),
+        SwitchInt { targets, .. } => targets.all_targets(),
 
         // A yield terminator has exactly 1 successor, but should not be chained,
         // because its resume edge has a different execution count.
-        Yield { resume, .. } => CoverageSuccessors::Yield(resume),
+        Yield { resume, .. } => {
+            is_yield = true;
+            slice::from_ref(resume)
+        }
 
         // These terminators have exactly one coverage-relevant successor,
         // and can be chained into it.
@@ -455,24 +440,15 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera
         | Drop { target, .. }
         | FalseEdge { real_target: target, .. }
         | FalseUnwind { real_target: target, .. }
-        | Goto { target } => CoverageSuccessors::Chainable(target),
+        | Goto { target } => slice::from_ref(target),
 
         // A call terminator can normally be chained, except when it has no
         // successor because it is known to diverge.
-        Call { target: maybe_target, .. } => match maybe_target {
-            Some(target) => CoverageSuccessors::Chainable(target),
-            None => CoverageSuccessors::NotChainable(&[]),
-        },
+        Call { target: maybe_target, .. } => maybe_target.as_slice(),
 
         // An inline asm terminator can normally be chained, except when it
         // diverges or uses asm goto.
-        InlineAsm { ref targets, .. } => {
-            if let [target] = targets[..] {
-                CoverageSuccessors::Chainable(target)
-            } else {
-                CoverageSuccessors::NotChainable(targets)
-            }
-        }
+        InlineAsm { targets, .. } => &targets,
 
         // These terminators have no coverage-relevant successors.
         CoroutineDrop
@@ -480,8 +456,10 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera
         | TailCall { .. }
         | Unreachable
         | UnwindResume
-        | UnwindTerminate(_) => CoverageSuccessors::NotChainable(&[]),
-    }
+        | UnwindTerminate(_) => &[],
+    };
+
+    CoverageSuccessors { targets, is_yield }
 }
 
 /// Maintains separate worklists for each loop in the BasicCoverageBlock CFG, plus one for the
@@ -616,28 +594,31 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> {
     }
 }
 
-fn short_circuit_preorder<'a, 'tcx, F, Iter>(
-    body: &'a mir::Body<'tcx>,
-    filtered_successors: F,
-) -> impl Iterator<Item = BasicBlock> + Captures<'a> + Captures<'tcx>
-where
-    F: Fn(BasicBlock) -> Iter,
-    Iter: IntoIterator<Item = BasicBlock>,
-{
-    let mut visited = BitSet::new_empty(body.basic_blocks.len());
-    let mut worklist = vec![mir::START_BLOCK];
-
-    std::iter::from_fn(move || {
-        while let Some(bb) = worklist.pop() {
-            if !visited.insert(bb) {
-                continue;
-            }
-
-            worklist.extend(filtered_successors(bb));
+/// Wrapper around a [`mir::BasicBlocks`] graph that restricts each node's
+/// successors to only the ones considered "relevant" when building a coverage
+/// graph.
+#[derive(Clone, Copy)]
+struct CoverageRelevantSubgraph<'a, 'tcx> {
+    basic_blocks: &'a mir::BasicBlocks<'tcx>,
+}
+impl<'a, 'tcx> CoverageRelevantSubgraph<'a, 'tcx> {
+    fn new(basic_blocks: &'a mir::BasicBlocks<'tcx>) -> Self {
+        Self { basic_blocks }
+    }
 
-            return Some(bb);
-        }
+    fn coverage_successors(&self, bb: BasicBlock) -> CoverageSuccessors<'_> {
+        bcb_filtered_successors(self.basic_blocks[bb].terminator())
+    }
+}
+impl<'a, 'tcx> graph::DirectedGraph for CoverageRelevantSubgraph<'a, 'tcx> {
+    type Node = BasicBlock;
 
-        None
-    })
+    fn num_nodes(&self) -> usize {
+        self.basic_blocks.num_nodes()
+    }
+}
+impl<'a, 'tcx> graph::Successors for CoverageRelevantSubgraph<'a, 'tcx> {
+    fn successors(&self, bb: Self::Node) -> impl Iterator<Item = Self::Node> {
+        self.coverage_successors(bb).into_iter()
+    }
 }
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 2e4c503f3ce..e8b3d80be02 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -22,8 +22,8 @@ use rustc_middle::mir::{
 use rustc_middle::ty::TyCtxt;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::source_map::SourceMap;
-use rustc_span::{BytePos, Pos, RelativeBytePos, Span, Symbol};
-use tracing::{debug, debug_span, instrument, trace};
+use rustc_span::{BytePos, Pos, SourceFile, Span};
+use tracing::{debug, debug_span, trace};
 
 use crate::coverage::counters::{CounterIncrementSite, CoverageCounters};
 use crate::coverage::graph::CoverageGraph;
@@ -122,6 +122,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir:
 
     mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
         function_source_hash: hir_info.function_source_hash,
+        body_span: hir_info.body_span,
         num_counters: coverage_counters.num_counters(),
         mcdc_bitmap_bits: extracted_mappings.mcdc_bitmap_bits,
         expressions: coverage_counters.into_expressions(),
@@ -142,19 +143,11 @@ fn create_mappings<'tcx>(
     coverage_counters: &CoverageCounters,
 ) -> Vec<Mapping> {
     let source_map = tcx.sess.source_map();
-    let body_span = hir_info.body_span;
-
-    let source_file = source_map.lookup_source_file(body_span.lo());
-
-    use rustc_session::RemapFileNameExt;
-    use rustc_session::config::RemapPathScopeComponents;
-    let file_name = Symbol::intern(
-        &source_file.name.for_scope(tcx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(),
-    );
+    let file = source_map.lookup_source_file(hir_info.body_span.lo());
 
     let term_for_bcb =
         |bcb| coverage_counters.term_for_bcb(bcb).expect("all BCBs with spans were given counters");
-    let region_for_span = |span: Span| make_source_region(source_map, file_name, span, body_span);
+    let region_for_span = |span: Span| make_source_region(source_map, hir_info, &file, span);
 
     // Fully destructure the mappings struct to make sure we don't miss any kinds.
     let ExtractedMappings {
@@ -398,7 +391,42 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb
     data.statements.insert(0, statement);
 }
 
-/// Convert the Span into its file name, start line and column, and end line and column.
+fn ensure_non_empty_span(
+    source_map: &SourceMap,
+    hir_info: &ExtractedHirInfo,
+    span: Span,
+) -> Option<Span> {
+    if !span.is_empty() {
+        return Some(span);
+    }
+
+    let lo = span.lo();
+    let hi = span.hi();
+
+    // The span is empty, so try to expand it to cover an adjacent '{' or '}',
+    // but only within the bounds of the body span.
+    let try_next = hi < hir_info.body_span.hi();
+    let try_prev = hir_info.body_span.lo() < lo;
+    if !(try_next || try_prev) {
+        return None;
+    }
+
+    source_map
+        .span_to_source(span, |src, start, end| try {
+            // We're only checking for specific ASCII characters, so we don't
+            // have to worry about multi-byte code points.
+            if try_next && src.as_bytes()[end] == b'{' {
+                Some(span.with_hi(hi + BytePos(1)))
+            } else if try_prev && src.as_bytes()[start - 1] == b'}' {
+                Some(span.with_lo(lo - BytePos(1)))
+            } else {
+                None
+            }
+        })
+        .ok()?
+}
+
+/// Converts the span into its start line and column, and end line and column.
 ///
 /// Line numbers and column numbers are 1-based. Unlike most column numbers emitted by
 /// the compiler, these column numbers are denoted in **bytes**, because that's what
@@ -408,56 +436,29 @@ fn inject_statement(mir_body: &mut mir::Body<'_>, counter_kind: CoverageKind, bb
 /// but it's hard to rule out entirely (especially in the presence of complex macros
 /// or other expansions), and if it does happen then skipping a span or function is
 /// better than an ICE or `llvm-cov` failure that the user might have no way to avoid.
-#[instrument(level = "debug", skip(source_map))]
 fn make_source_region(
     source_map: &SourceMap,
-    file_name: Symbol,
+    hir_info: &ExtractedHirInfo,
+    file: &SourceFile,
     span: Span,
-    body_span: Span,
 ) -> Option<SourceRegion> {
+    let span = ensure_non_empty_span(source_map, hir_info, span)?;
+
     let lo = span.lo();
     let hi = span.hi();
 
-    let file = source_map.lookup_source_file(lo);
-    if !file.contains(hi) {
-        debug!(?span, ?file, ?lo, ?hi, "span crosses multiple files; skipping");
-        return None;
-    }
-
     // Column numbers need to be in bytes, so we can't use the more convenient
     // `SourceMap` methods for looking up file coordinates.
-    let rpos_and_line_and_byte_column = |pos: BytePos| -> Option<(RelativeBytePos, usize, usize)> {
+    let line_and_byte_column = |pos: BytePos| -> Option<(usize, usize)> {
         let rpos = file.relative_position(pos);
         let line_index = file.lookup_line(rpos)?;
         let line_start = file.lines()[line_index];
         // Line numbers and column numbers are 1-based, so add 1 to each.
-        Some((rpos, line_index + 1, (rpos - line_start).to_usize() + 1))
+        Some((line_index + 1, (rpos - line_start).to_usize() + 1))
     };
 
-    let (lo_rpos, mut start_line, mut start_col) = rpos_and_line_and_byte_column(lo)?;
-    let (hi_rpos, mut end_line, mut end_col) = rpos_and_line_and_byte_column(hi)?;
-
-    // If the span is empty, try to expand it horizontally by one character's
-    // worth of bytes, so that it is more visible in `llvm-cov` reports.
-    // We do this after resolving line/column numbers, so that empty spans at the
-    // end of a line get an extra column instead of wrapping to the next line.
-    if span.is_empty()
-        && body_span.contains(span)
-        && let Some(src) = &file.src
-    {
-        // Prefer to expand the end position, if it won't go outside the body span.
-        if hi < body_span.hi() {
-            let hi_rpos = hi_rpos.to_usize();
-            let nudge_bytes = src.ceil_char_boundary(hi_rpos + 1) - hi_rpos;
-            end_col += nudge_bytes;
-        } else if lo > body_span.lo() {
-            let lo_rpos = lo_rpos.to_usize();
-            let nudge_bytes = lo_rpos - src.floor_char_boundary(lo_rpos - 1);
-            // Subtract the nudge, but don't go below column 1.
-            start_col = start_col.saturating_sub(nudge_bytes).max(1);
-        }
-        // If neither nudge could be applied, stick with the empty span coordinates.
-    }
+    let (mut start_line, start_col) = line_and_byte_column(lo)?;
+    let (mut end_line, end_col) = line_and_byte_column(hi)?;
 
     // Apply an offset so that code in doctests has correct line numbers.
     // FIXME(#79417): Currently we have no way to offset doctest _columns_.
@@ -465,7 +466,6 @@ fn make_source_region(
     end_line = source_map.doctest_offset_line(&file.name, end_line);
 
     check_source_region(SourceRegion {
-        file_name,
         start_line: start_line as u32,
         start_col: start_col as u32,
         end_line: end_line as u32,
@@ -478,7 +478,7 @@ fn make_source_region(
 /// discard regions that are improperly ordered, or might be interpreted in a
 /// way that makes them improperly ordered.
 fn check_source_region(source_region: SourceRegion) -> Option<SourceRegion> {
-    let SourceRegion { file_name: _, start_line, start_col, end_line, end_col } = source_region;
+    let SourceRegion { start_line, start_col, end_line, end_col } = source_region;
 
     // Line/column coordinates are supposed to be 1-based. If we ever emit
     // coordinates of 0, `llvm-cov` might misinterpret them.
diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs
index 42cbece32d8..589be81558c 100644
--- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs
+++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs
@@ -50,6 +50,16 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
         _ => {}
     }
 
+    let sig = tcx.fn_sig(def_id).instantiate_identity();
+    for ty in sig.inputs().skip_binder().iter().chain(std::iter::once(&sig.output().skip_binder()))
+    {
+        // FIXME(f16_f128): in order to avoid crashes building `core`, always inline to skip
+        // codegen if the function is not used.
+        if ty == &tcx.types.f16 || ty == &tcx.types.f128 {
+            return true;
+        }
+    }
+
     // Don't do any inference when incremental compilation is enabled; the additional inlining that
     // inference permits also creates more work for small edits.
     if tcx.sess.opts.incremental.is_some() {
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index dd85d06540d..ab6460c490b 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -662,7 +662,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
             // Exactly one side is known, attempt some algebraic simplifications.
             (FlatSet::Elem(const_arg), _) | (_, FlatSet::Elem(const_arg)) => {
                 let layout = const_arg.layout;
-                if !matches!(layout.backend_repr, rustc_target::abi::BackendRepr::Scalar(..)) {
+                if !matches!(layout.backend_repr, rustc_abi::BackendRepr::Scalar(..)) {
                     return (FlatSet::Top, FlatSet::Top);
                 }
 
@@ -941,16 +941,12 @@ fn try_write_constant<'tcx>(
     interp_ok(())
 }
 
-impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx>>>
-    for Collector<'_, 'tcx>
-{
-    type Domain = State<FlatSet<Scalar>>;
-
+impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> {
     #[instrument(level = "trace", skip(self, results, statement))]
     fn visit_statement_before_primary_effect(
         &mut self,
         results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
-        state: &Self::Domain,
+        state: &State<FlatSet<Scalar>>,
         statement: &'mir Statement<'tcx>,
         location: Location,
     ) {
@@ -972,7 +968,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx
     fn visit_statement_after_primary_effect(
         &mut self,
         results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
-        state: &Self::Domain,
+        state: &State<FlatSet<Scalar>>,
         statement: &'mir Statement<'tcx>,
         location: Location,
     ) {
@@ -997,7 +993,7 @@ impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, Results<'tcx, ConstAnalysis<'_, 'tcx
     fn visit_terminator_before_primary_effect(
         &mut self,
         results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
-        state: &Self::Domain,
+        state: &State<FlatSet<Scalar>>,
         terminator: &'mir Terminator<'tcx>,
         location: Location,
     ) {
diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
index 57f7a9ef7f5..b909dfa1320 100644
--- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
@@ -2,13 +2,13 @@
 //!
 //! Box is not actually a pointer so it is incorrect to dereference it directly.
 
+use rustc_abi::FieldIdx;
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::visit::MutVisitor;
 use rustc_middle::mir::*;
 use rustc_middle::span_bug;
 use rustc_middle::ty::{Ty, TyCtxt};
-use rustc_target::abi::FieldIdx;
 
 /// Constructs the types used when accessing a Box's pointer
 fn build_ptr_tys<'tcx>(
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index 58e1db19438..74572100db3 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -1,5 +1,6 @@
 use std::fmt;
 
+use rustc_abi::{FieldIdx, VariantIdx};
 use rustc_index::IndexVec;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::patch::MirPatch;
@@ -14,7 +15,6 @@ use rustc_mir_dataflow::{
     Analysis, MoveDataParamEnv, ResultsCursor, on_all_children_bits, on_lookup_result_bits,
 };
 use rustc_span::Span;
-use rustc_target::abi::{FieldIdx, VariantIdx};
 use tracing::{debug, instrument};
 
 use crate::deref_separator::deref_finder;
diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs
index 8b309147c64..2d9eeddea2e 100644
--- a/compiler/rustc_mir_transform/src/errors.rs
+++ b/compiler/rustc_mir_transform/src/errors.rs
@@ -38,6 +38,12 @@ pub(crate) struct UnalignedPackedRef {
     pub span: Span,
 }
 
+#[derive(Diagnostic)]
+#[diag(mir_transform_unknown_pass_name)]
+pub(crate) struct UnknownPassName<'a> {
+    pub(crate) name: &'a str,
+}
+
 pub(crate) struct AssertLint<P> {
     pub span: Span,
     pub assert_kind: AssertKind<P>,
diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
index 99892a1296b..3d560bdf75c 100644
--- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
+++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
@@ -1,3 +1,4 @@
+use rustc_abi::ExternAbi;
 use rustc_hir::def_id::{LOCAL_CRATE, LocalDefId};
 use rustc_middle::mir::*;
 use rustc_middle::query::{LocalCrate, Providers};
@@ -5,7 +6,6 @@ use rustc_middle::ty::{self, TyCtxt, layout};
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint::builtin::FFI_UNWIND_CALLS;
 use rustc_target::spec::PanicStrategy;
-use rustc_target::spec::abi::Abi;
 use tracing::debug;
 
 use crate::errors;
@@ -26,9 +26,9 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
     let body_ty = tcx.type_of(def_id).skip_binder();
     let body_abi = match body_ty.kind() {
         ty::FnDef(..) => body_ty.fn_sig(tcx).abi(),
-        ty::Closure(..) => Abi::RustCall,
-        ty::CoroutineClosure(..) => Abi::RustCall,
-        ty::Coroutine(..) => Abi::Rust,
+        ty::Closure(..) => ExternAbi::RustCall,
+        ty::CoroutineClosure(..) => ExternAbi::RustCall,
+        ty::Coroutine(..) => ExternAbi::Rust,
         ty::Error(_) => return false,
         _ => span_bug!(body.span, "unexpected body ty: {:?}", body_ty),
     };
@@ -53,7 +53,11 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
 
         // Rust calls cannot themselves create foreign unwinds.
         // We assume this is true for intrinsics as well.
-        if let Abi::RustIntrinsic | Abi::Rust | Abi::RustCall | Abi::RustCold = sig.abi() {
+        if let ExternAbi::RustIntrinsic
+        | ExternAbi::Rust
+        | ExternAbi::RustCall
+        | ExternAbi::RustCold = sig.abi()
+        {
             continue;
         };
 
diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs
index e55aeeac6e0..2945fc6f3d5 100644
--- a/compiler/rustc_mir_transform/src/function_item_references.rs
+++ b/compiler/rustc_mir_transform/src/function_item_references.rs
@@ -1,4 +1,5 @@
 use itertools::Itertools;
+use rustc_abi::ExternAbi;
 use rustc_hir::def_id::DefId;
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
@@ -7,7 +8,6 @@ use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES;
 use rustc_span::Span;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::sym;
-use rustc_target::spec::abi::Abi;
 
 use crate::errors;
 
@@ -161,7 +161,7 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
         let fn_sig = self.tcx.fn_sig(fn_id).instantiate(self.tcx, fn_args);
         let unsafety = fn_sig.safety().prefix_str();
         let abi = match fn_sig.abi() {
-            Abi::Rust => String::from(""),
+            ExternAbi::Rust => String::from(""),
             other_abi => {
                 let mut s = String::from("extern \"");
                 s.push_str(other_abi.name());
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 404470db5c5..e95ab4ffe16 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -3,6 +3,7 @@
 use std::iter;
 use std::ops::{Range, RangeFrom};
 
+use rustc_abi::{ExternAbi, FieldIdx};
 use rustc_attr::InlineAttr;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
@@ -18,8 +19,6 @@ use rustc_middle::ty::{
 use rustc_session::config::{DebugInfo, OptLevel};
 use rustc_span::source_map::Spanned;
 use rustc_span::sym;
-use rustc_target::abi::FieldIdx;
-use rustc_target::spec::abi::Abi;
 use tracing::{debug, instrument, trace, trace_span};
 
 use crate::cost_checker::CostChecker;
@@ -254,7 +253,7 @@ impl<'tcx> Inliner<'tcx> {
             trace!(?output_type, ?destination_ty);
             return Err("failed to normalize return type");
         }
-        if callsite.fn_sig.abi() == Abi::RustCall {
+        if callsite.fn_sig.abi() == ExternAbi::RustCall {
             // FIXME: Don't inline user-written `extern "rust-call"` functions,
             // since this is generally perf-negative on rustc, and we hope that
             // LLVM will inline these functions instead.
@@ -808,7 +807,7 @@ impl<'tcx> Inliner<'tcx> {
         //     tmp2 = tuple_tmp.2
         //
         // and the vector is `[closure_ref, tmp0, tmp1, tmp2]`.
-        if callsite.fn_sig.abi() == Abi::RustCall && callee_body.spread_arg.is_none() {
+        if callsite.fn_sig.abi() == ExternAbi::RustCall && callee_body.spread_arg.is_none() {
             // FIXME(edition_2024): switch back to a normal method call.
             let mut args = <_>::into_iter(args);
             let self_ = self.create_temp_if_necessary(
diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index 8bcc91b4488..9471c1b2a9a 100644
--- a/compiler/rustc_mir_transform/src/instsimplify.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -1,5 +1,6 @@
 //! Performs various peephole optimizations.
 
+use rustc_abi::ExternAbi;
 use rustc_ast::attr;
 use rustc_hir::LangItem;
 use rustc_middle::bug;
@@ -8,7 +9,6 @@ use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, layout};
 use rustc_span::sym;
 use rustc_span::symbol::Symbol;
-use rustc_target::spec::abi::Abi;
 
 use crate::simplify::simplify_duplicate_switch_targets;
 use crate::take_array;
@@ -321,8 +321,8 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> {
         let body_ty = self.tcx.type_of(def_id).skip_binder();
         let body_abi = match body_ty.kind() {
             ty::FnDef(..) => body_ty.fn_sig(self.tcx).abi(),
-            ty::Closure(..) => Abi::RustCall,
-            ty::Coroutine(..) => Abi::Rust,
+            ty::Closure(..) => ExternAbi::RustCall,
+            ty::Coroutine(..) => ExternAbi::Rust,
             _ => bug!("unexpected body ty: {:?}", body_ty),
         };
 
diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs
index 9b9b0b705bf..3772589ac4e 100644
--- a/compiler/rustc_mir_transform/src/jump_threading.rs
+++ b/compiler/rustc_mir_transform/src/jump_threading.rs
@@ -35,6 +35,7 @@
 //! Likewise, applying the optimisation can create a lot of new MIR, so we bound the instruction
 //! cost by `MAX_COST`.
 
+use rustc_abi::{TagEncoding, Variants};
 use rustc_arena::DroplessArena;
 use rustc_const_eval::const_eval::DummyMachine;
 use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable};
@@ -50,7 +51,6 @@ use rustc_middle::ty::{self, ScalarInt, TyCtxt};
 use rustc_mir_dataflow::lattice::HasBottom;
 use rustc_mir_dataflow::value_analysis::{Map, PlaceIndex, State, TrackElem};
 use rustc_span::DUMMY_SP;
-use rustc_target::abi::{TagEncoding, Variants};
 use tracing::{debug, instrument, trace};
 
 use crate::cost_checker::CostChecker;
diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs
index 3e263aa4067..fa659a56a27 100644
--- a/compiler/rustc_mir_transform/src/large_enums.rs
+++ b/compiler/rustc_mir_transform/src/large_enums.rs
@@ -1,10 +1,10 @@
+use rustc_abi::{HasDataLayout, Size, TagEncoding, Variants};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::mir::interpret::AllocId;
 use rustc_middle::mir::*;
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, AdtDef, ParamEnv, Ty, TyCtxt};
 use rustc_session::Session;
-use rustc_target::abi::{HasDataLayout, Size, TagEncoding, Variants};
 
 /// A pass that seeks to optimize unnecessary moves of large enum types, if there is a large
 /// enough discrepancy between them.
@@ -249,8 +249,8 @@ impl EnumSizeOpt {
         macro_rules! encode_store {
             ($curr_idx: expr, $endian: expr, $bytes: expr) => {
                 let bytes = match $endian {
-                    rustc_target::abi::Endian::Little => $bytes.to_le_bytes(),
-                    rustc_target::abi::Endian::Big => $bytes.to_be_bytes(),
+                    rustc_abi::Endian::Little => $bytes.to_le_bytes(),
+                    rustc_abi::Endian::Big => $bytes.to_be_bytes(),
                 };
                 for (i, b) in bytes.into_iter().enumerate() {
                     data[$curr_idx + i] = b;
@@ -263,10 +263,10 @@ impl EnumSizeOpt {
                 target_bytes * adt_def.discriminant_for_variant(tcx, var_idx).val as usize;
             let sz = layout.size;
             match ptr_sized_int {
-                rustc_target::abi::Integer::I32 => {
+                rustc_abi::Integer::I32 => {
                     encode_store!(curr_idx, data_layout.endian, sz.bytes() as u32);
                 }
-                rustc_target::abi::Integer::I64 => {
+                rustc_abi::Integer::I64 => {
                     encode_store!(curr_idx, data_layout.endian, sz.bytes());
                 }
                 _ => unreachable!(),
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index d184328748f..d2d5facbbdc 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -9,7 +9,6 @@
 #![feature(let_chains)]
 #![feature(map_try_insert)]
 #![feature(never_type)]
-#![feature(round_char_boundary)]
 #![feature(try_blocks)]
 #![feature(yeet_expr)]
 #![warn(unreachable_pub)]
@@ -41,77 +40,158 @@ use tracing::{debug, trace};
 #[macro_use]
 mod pass_manager;
 
+use std::sync::LazyLock;
+
 use pass_manager::{self as pm, Lint, MirLint, MirPass, WithMinOptLevel};
 
-mod abort_unwinding_calls;
-mod add_call_guards;
-mod add_moves_for_packed_drops;
-mod add_retag;
-mod add_subtyping_projections;
-mod check_alignment;
-mod check_const_item_mutation;
-mod check_packed_ref;
-mod check_undefined_transmutes;
-// This pass is public to allow external drivers to perform MIR cleanup
-pub mod cleanup_post_borrowck;
-mod copy_prop;
-mod coroutine;
 mod cost_checker;
-mod coverage;
 mod cross_crate_inline;
-mod ctfe_limit;
-mod dataflow_const_prop;
-mod dead_store_elimination;
 mod deduce_param_attrs;
-mod deduplicate_blocks;
-mod deref_separator;
-mod dest_prop;
-pub mod dump_mir;
-mod early_otherwise_branch;
-mod elaborate_box_derefs;
-mod elaborate_drops;
 mod errors;
 mod ffi_unwind_calls;
-mod function_item_references;
-mod gvn;
-// Made public so that `mir_drops_elaborated_and_const_checked` can be overridden
-// by custom rustc drivers, running all the steps by themselves. See #114628.
-pub mod inline;
-mod instsimplify;
-mod jump_threading;
-mod known_panics_lint;
-mod large_enums;
 mod lint;
-mod lower_intrinsics;
-mod lower_slice_len;
-mod match_branches;
-mod mentioned_items;
-mod multiple_return_terminators;
-mod nrvo;
-mod post_drop_elaboration;
-mod prettify;
-mod promote_consts;
-mod ref_prop;
-mod remove_noop_landing_pads;
-mod remove_place_mention;
-mod remove_storage_markers;
-mod remove_uninit_drops;
-mod remove_unneeded_drops;
-mod remove_zsts;
-mod required_consts;
-mod reveal_all;
-mod sanity_check;
 mod shim;
 mod ssa;
-// This pass is public to allow external drivers to perform MIR cleanup
-pub mod simplify;
-mod simplify_branches;
-mod simplify_comparison_integral;
-mod single_use_consts;
-mod sroa;
-mod unreachable_enum_branching;
-mod unreachable_prop;
-mod validate;
+
+/// We import passes via this macro so that we can have a static list of pass names
+/// (used to verify CLI arguments). It takes a list of modules, followed by the passes
+/// declared within them.
+/// ```ignore,macro-test
+/// declare_passes! {
+///     // Declare a single pass from the module `abort_unwinding_calls`
+///     mod abort_unwinding_calls : AbortUnwindingCalls;
+///     // When passes are grouped together as an enum, declare the two constituent passes
+///     mod add_call_guards : AddCallGuards {
+///         AllCallEdges,
+///         CriticalCallEdges
+///     };
+///     // Declares multiple pass groups, each containing their own constituent passes
+///     mod simplify : SimplifyCfg {
+///         Initial,
+///         /* omitted */
+///     }, SimplifyLocals {
+///         BeforeConstProp,
+///         /* omitted */
+///     };
+/// }
+/// ```
+macro_rules! declare_passes {
+    (
+        $(
+            $vis:vis mod $mod_name:ident : $($pass_name:ident $( { $($ident:ident),* } )?),+ $(,)?;
+        )*
+    ) => {
+        $(
+            $vis mod $mod_name;
+            $(
+                // Make sure the type name is correct
+                #[allow(unused_imports)]
+                use $mod_name::$pass_name as _;
+            )+
+        )*
+
+        static PASS_NAMES: LazyLock<FxIndexSet<&str>> = LazyLock::new(|| [
+            // Fake marker pass
+            "PreCodegen",
+            $(
+                $(
+                    stringify!($pass_name),
+                    $(
+                        $(
+                            $mod_name::$pass_name::$ident.name(),
+                        )*
+                    )?
+                )+
+            )*
+        ].into_iter().collect());
+    };
+}
+
+declare_passes! {
+    mod abort_unwinding_calls : AbortUnwindingCalls;
+    mod add_call_guards : AddCallGuards { AllCallEdges, CriticalCallEdges };
+    mod add_moves_for_packed_drops : AddMovesForPackedDrops;
+    mod add_retag : AddRetag;
+    mod add_subtyping_projections : Subtyper;
+    mod check_alignment : CheckAlignment;
+    mod check_const_item_mutation : CheckConstItemMutation;
+    mod check_packed_ref : CheckPackedRef;
+    mod check_undefined_transmutes : CheckUndefinedTransmutes;
+    // This pass is public to allow external drivers to perform MIR cleanup
+    pub mod cleanup_post_borrowck : CleanupPostBorrowck;
+
+    mod copy_prop : CopyProp;
+    mod coroutine : StateTransform;
+    mod coverage : InstrumentCoverage;
+    mod ctfe_limit : CtfeLimit;
+    mod dataflow_const_prop : DataflowConstProp;
+    mod dead_store_elimination : DeadStoreElimination {
+        Initial,
+        Final
+    };
+    mod deduplicate_blocks : DeduplicateBlocks;
+    mod deref_separator : Derefer;
+    mod dest_prop : DestinationPropagation;
+    pub mod dump_mir : Marker;
+    mod early_otherwise_branch : EarlyOtherwiseBranch;
+    mod elaborate_box_derefs : ElaborateBoxDerefs;
+    mod elaborate_drops : ElaborateDrops;
+    mod function_item_references : FunctionItemReferences;
+    mod gvn : GVN;
+    // Made public so that `mir_drops_elaborated_and_const_checked` can be overridden
+    // by custom rustc drivers, running all the steps by themselves. See #114628.
+    pub mod inline : Inline;
+    mod instsimplify : InstSimplify { BeforeInline, AfterSimplifyCfg };
+    mod jump_threading : JumpThreading;
+    mod known_panics_lint : KnownPanicsLint;
+    mod large_enums : EnumSizeOpt;
+    mod lower_intrinsics : LowerIntrinsics;
+    mod lower_slice_len : LowerSliceLenCalls;
+    mod match_branches : MatchBranchSimplification;
+    mod mentioned_items : MentionedItems;
+    mod multiple_return_terminators : MultipleReturnTerminators;
+    mod nrvo : RenameReturnPlace;
+    mod post_drop_elaboration : CheckLiveDrops;
+    mod prettify : ReorderBasicBlocks, ReorderLocals;
+    mod promote_consts : PromoteTemps;
+    mod ref_prop : ReferencePropagation;
+    mod remove_noop_landing_pads : RemoveNoopLandingPads;
+    mod remove_place_mention : RemovePlaceMention;
+    mod remove_storage_markers : RemoveStorageMarkers;
+    mod remove_uninit_drops : RemoveUninitDrops;
+    mod remove_unneeded_drops : RemoveUnneededDrops;
+    mod remove_zsts : RemoveZsts;
+    mod required_consts : RequiredConstsVisitor;
+    mod reveal_all : RevealAll;
+    mod sanity_check : SanityCheck;
+    // This pass is public to allow external drivers to perform MIR cleanup
+    pub mod simplify :
+        SimplifyCfg {
+            Initial,
+            PromoteConsts,
+            RemoveFalseEdges,
+            PostAnalysis,
+            PreOptimizations,
+            Final,
+            MakeShim,
+            AfterUnreachableEnumBranching
+        },
+        SimplifyLocals {
+            BeforeConstProp,
+            AfterGVN,
+            Final
+        };
+    mod simplify_branches : SimplifyConstCondition {
+        AfterConstProp,
+        Final
+    };
+    mod simplify_comparison_integral : SimplifyComparisonIntegral;
+    mod single_use_consts : SingleUseConsts;
+    mod sroa : ScalarReplacementOfAggregates;
+    mod unreachable_enum_branching : UnreachableEnumBranching;
+    mod unreachable_prop : UnreachablePropagation;
+    mod validate : Validator;
+}
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs
index ad3126f66a6..237227f5294 100644
--- a/compiler/rustc_mir_transform/src/match_branches.rs
+++ b/compiler/rustc_mir_transform/src/match_branches.rs
@@ -1,11 +1,11 @@
 use std::iter;
 
+use rustc_abi::Integer;
 use rustc_index::IndexSlice;
 use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
 use rustc_middle::ty::{ParamEnv, ScalarInt, Ty, TyCtxt};
-use rustc_target::abi::Integer;
 use rustc_type_ir::TyKind::*;
 
 use super::simplify::simplify_cfg;
diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs
index 29f8b4f6e4d..779e7f22101 100644
--- a/compiler/rustc_mir_transform/src/pass_manager.rs
+++ b/compiler/rustc_mir_transform/src/pass_manager.rs
@@ -1,24 +1,25 @@
 use std::cell::RefCell;
 use std::collections::hash_map::Entry;
 
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_middle::mir::{self, Body, MirPhase, RuntimePhase};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
 use tracing::trace;
 
 use crate::lint::lint_body;
-use crate::validate;
+use crate::{errors, validate};
 
 thread_local! {
-    static PASS_NAMES: RefCell<FxHashMap<&'static str, &'static str>> = {
+    /// Maps MIR pass names to a snake case form to match profiling naming style
+    static PASS_TO_PROFILER_NAMES: RefCell<FxHashMap<&'static str, &'static str>> = {
         RefCell::new(FxHashMap::default())
     };
 }
 
 /// Converts a MIR pass name into a snake case form to match the profiling naming style.
 fn to_profiler_name(type_name: &'static str) -> &'static str {
-    PASS_NAMES.with(|names| match names.borrow_mut().entry(type_name) {
+    PASS_TO_PROFILER_NAMES.with(|names| match names.borrow_mut().entry(type_name) {
         Entry::Occupied(e) => *e.get(),
         Entry::Vacant(e) => {
             let snake_case: String = type_name
@@ -198,6 +199,31 @@ fn run_passes_inner<'tcx>(
     let overridden_passes = &tcx.sess.opts.unstable_opts.mir_enable_passes;
     trace!(?overridden_passes);
 
+    let named_passes: FxIndexSet<_> =
+        overridden_passes.iter().map(|(name, _)| name.as_str()).collect();
+
+    for &name in named_passes.difference(&*crate::PASS_NAMES) {
+        tcx.dcx().emit_warn(errors::UnknownPassName { name });
+    }
+
+    // Verify that no passes are missing from the `declare_passes` invocation
+    #[cfg(debug_assertions)]
+    #[allow(rustc::diagnostic_outside_of_impl)]
+    #[allow(rustc::untranslatable_diagnostic)]
+    {
+        let used_passes: FxIndexSet<_> = passes.iter().map(|p| p.name()).collect();
+
+        let undeclared = used_passes.difference(&*crate::PASS_NAMES).collect::<Vec<_>>();
+        if let Some((name, rest)) = undeclared.split_first() {
+            let mut err =
+                tcx.dcx().struct_bug(format!("pass `{name}` is not declared in `PASS_NAMES`"));
+            for name in rest {
+                err.note(format!("pass `{name}` is also not declared in `PASS_NAMES`"));
+            }
+            err.emit();
+        }
+    }
+
     let prof_arg = tcx.sess.prof.enabled().then(|| format!("{:?}", body.source.def_id()));
 
     if !body.should_skip() {
diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
index 55dd96100b0..20c34a7469e 100644
--- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
@@ -1,10 +1,10 @@
+use rustc_abi::FieldIdx;
 use rustc_index::bit_set::ChunkedBitSet;
 use rustc_middle::mir::{Body, TerminatorKind};
 use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, VariantDef};
 use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
 use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex};
 use rustc_mir_dataflow::{Analysis, MaybeReachable, move_path_children_matching};
-use rustc_target::abi::FieldIdx;
 
 /// Removes `Drop` terminators whose target is known to be uninitialized at
 /// that point.
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index e872878a751..ffa11f5b213 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -1,6 +1,7 @@
 use std::assert_matches::assert_matches;
 use std::{fmt, iter};
 
+use rustc_abi::{ExternAbi, FIRST_VARIANT, FieldIdx, VariantIdx};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
@@ -15,8 +16,6 @@ use rustc_middle::{bug, span_bug};
 use rustc_mir_dataflow::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle};
 use rustc_span::source_map::Spanned;
 use rustc_span::{DUMMY_SP, Span};
-use rustc_target::abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
-use rustc_target::spec::abi::Abi;
 use tracing::{debug, instrument};
 
 use crate::{
@@ -905,7 +904,7 @@ fn build_call_shim<'tcx>(
     let mut body =
         new_body(MirSource::from_instance(instance), blocks, local_decls, sig.inputs().len(), span);
 
-    if let Abi::RustCall = sig.abi {
+    if let ExternAbi::RustCall = sig.abi {
         body.spread_arg = Some(Local::new(sig.inputs().len()));
     }
 
diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs
index 71723f040b3..f1672272862 100644
--- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs
+++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs
@@ -1,6 +1,7 @@
 use std::iter;
 
 use itertools::Itertools;
+use rustc_abi::{FieldIdx, VariantIdx};
 use rustc_ast::Mutability;
 use rustc_const_eval::interpret;
 use rustc_hir::def_id::DefId;
@@ -18,7 +19,6 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_span::source_map::respan;
 use rustc_span::{Span, Symbol};
-use rustc_target::abi::{FieldIdx, VariantIdx};
 use rustc_target::spec::PanicStrategy;
 use tracing::debug;
 
diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs
index 2de0059bc7f..53bbb122096 100644
--- a/compiler/rustc_mir_transform/src/sroa.rs
+++ b/compiler/rustc_mir_transform/src/sroa.rs
@@ -1,3 +1,4 @@
+use rustc_abi::{FIRST_VARIANT, FieldIdx};
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
 use rustc_hir::LangItem;
 use rustc_index::IndexVec;
@@ -8,7 +9,6 @@ use rustc_middle::mir::visit::*;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_mir_dataflow::value_analysis::{excluded_locals, iter_fields};
-use rustc_target::abi::{FIRST_VARIANT, FieldIdx};
 use tracing::{debug, instrument};
 
 pub(super) struct ScalarReplacementOfAggregates;
diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs
index f3dafd13824..9cd32459c7b 100644
--- a/compiler/rustc_mir_transform/src/unreachable_prop.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs
@@ -2,13 +2,13 @@
 //! when all of their successors are unreachable. This is achieved through a
 //! post-order traversal of the blocks.
 
+use rustc_abi::Size;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_middle::bug;
 use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, TyCtxt};
-use rustc_target::abi::Size;
 
 pub(super) struct UnreachablePropagation;
 
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index 8109a9b8ba0..ae4e6ea6a74 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -1,5 +1,6 @@
 //! Validates the MIR to ensure that invariants are upheld.
 
+use rustc_abi::{ExternAbi, FIRST_VARIANT, Size};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::LangItem;
 use rustc_index::IndexVec;
@@ -15,8 +16,6 @@ use rustc_middle::ty::{
     Variance,
 };
 use rustc_middle::{bug, span_bug};
-use rustc_target::abi::{FIRST_VARIANT, Size};
-use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::traits::ObligationCtxt;
 use rustc_type_ir::Upcast;
 
@@ -60,9 +59,9 @@ impl<'tcx> crate::MirPass<'tcx> for Validator {
             let body_ty = tcx.type_of(def_id).skip_binder();
             let body_abi = match body_ty.kind() {
                 ty::FnDef(..) => body_ty.fn_sig(tcx).abi(),
-                ty::Closure(..) => Abi::RustCall,
-                ty::CoroutineClosure(..) => Abi::RustCall,
-                ty::Coroutine(..) => Abi::Rust,
+                ty::Closure(..) => ExternAbi::RustCall,
+                ty::CoroutineClosure(..) => ExternAbi::RustCall,
+                ty::Coroutine(..) => ExternAbi::Rust,
                 // No need to do MIR validation on error bodies
                 ty::Error(_) => return,
                 _ => {