about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-09-04 22:58:51 +0000
committerbors <bors@rust-lang.org>2024-09-04 22:58:51 +0000
commit009e73825af0e59ad4fc603562e038b3dbd6593a (patch)
tree5015384a0ad20ed06a185717c3155722515a218d /compiler
parent4ac7bcbaad8d6fd7a51bdf1b696cbc3ba4c796cf (diff)
parent2e005112fdd15af33f76eb2fd839c4f7f646d3ac (diff)
downloadrust-009e73825af0e59ad4fc603562e038b3dbd6593a.tar.gz
rust-009e73825af0e59ad4fc603562e038b3dbd6593a.zip
Auto merge of #129936 - matthiaskrgr:rollup-0s8xycb, r=matthiaskrgr
Rollup of 9 pull requests

Successful merges:

 - #127692 (Suggest `impl Trait` for References to Bare Trait in Function Header)
 - #128701 (Don't Suggest Labeling `const` and `unsafe` Blocks )
 - #128934 (Non-exhaustive structs may be empty)
 - #129630 (Document the broken C ABI of `wasm32-unknown-unknown`)
 - #129863 (update comment regarding TargetOptions.features)
 - #129896 (do not attempt to prove unknowable goals)
 - #129926 (Move `SanityCheck` and `MirPass`)
 - #129928 (rustc_driver_impl: remove some old dead logic)
 - #129930 (include 1.80.1 release notes on master)

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs13
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs78
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs62
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/mod.rs4
-rw-r--r--compiler/rustc_middle/src/util/common.rs16
-rw-r--r--compiler/rustc_mir_dataflow/src/rustc_peek.rs75
-rw-r--r--compiler/rustc_mir_transform/src/abort_unwinding_calls.rs2
-rw-r--r--compiler/rustc_mir_transform/src/add_call_guards.rs2
-rw-r--r--compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs2
-rw-r--r--compiler/rustc_mir_transform/src/add_retag.rs2
-rw-r--r--compiler/rustc_mir_transform/src/add_subtyping_projections.rs2
-rw-r--r--compiler/rustc_mir_transform/src/check_alignment.rs2
-rw-r--r--compiler/rustc_mir_transform/src/check_const_item_mutation.rs4
-rw-r--r--compiler/rustc_mir_transform/src/check_packed_ref.rs4
-rw-r--r--compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs4
-rw-r--r--compiler/rustc_mir_transform/src/copy_prop.rs2
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs2
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs3
-rw-r--r--compiler/rustc_mir_transform/src/ctfe_limit.rs4
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs2
-rw-r--r--compiler/rustc_mir_transform/src/dead_store_elimination.rs2
-rw-r--r--compiler/rustc_mir_transform/src/deduplicate_blocks.rs2
-rw-r--r--compiler/rustc_mir_transform/src/deref_separator.rs2
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs4
-rw-r--r--compiler/rustc_mir_transform/src/dump_mir.rs4
-rw-r--r--compiler/rustc_mir_transform/src/early_otherwise_branch.rs2
-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/function_item_references.rs4
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs2
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs2
-rw-r--r--compiler/rustc_mir_transform/src/instsimplify.rs2
-rw-r--r--compiler/rustc_mir_transform/src/jump_threading.rs2
-rw-r--r--compiler/rustc_mir_transform/src/known_panics_lint.rs3
-rw-r--r--compiler/rustc_mir_transform/src/large_enums.rs2
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs8
-rw-r--r--compiler/rustc_mir_transform/src/lower_intrinsics.rs2
-rw-r--r--compiler/rustc_mir_transform/src/lower_slice_len.rs2
-rw-r--r--compiler/rustc_mir_transform/src/match_branches.rs2
-rw-r--r--compiler/rustc_mir_transform/src/mentioned_items.rs4
-rw-r--r--compiler/rustc_mir_transform/src/multiple_return_terminators.rs2
-rw-r--r--compiler/rustc_mir_transform/src/nrvo.rs4
-rw-r--r--compiler/rustc_mir_transform/src/pass_manager.rs104
-rw-r--r--compiler/rustc_mir_transform/src/prettify.rs4
-rw-r--r--compiler/rustc_mir_transform/src/promote_consts.rs2
-rw-r--r--compiler/rustc_mir_transform/src/ref_prop.rs2
-rw-r--r--compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs2
-rw-r--r--compiler/rustc_mir_transform/src/remove_place_mention.rs2
-rw-r--r--compiler/rustc_mir_transform/src/remove_storage_markers.rs2
-rw-r--r--compiler/rustc_mir_transform/src/remove_uninit_drops.rs4
-rw-r--r--compiler/rustc_mir_transform/src/remove_unneeded_drops.rs2
-rw-r--r--compiler/rustc_mir_transform/src/remove_zsts.rs2
-rw-r--r--compiler/rustc_mir_transform/src/reveal_all.rs2
-rw-r--r--compiler/rustc_mir_transform/src/sanity_check.rs11
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs4
-rw-r--r--compiler/rustc_mir_transform/src/simplify_branches.rs2
-rw-r--r--compiler/rustc_mir_transform/src/simplify_comparison_integral.rs4
-rw-r--r--compiler/rustc_mir_transform/src/single_use_consts.rs2
-rw-r--r--compiler/rustc_mir_transform/src/sroa.rs2
-rw-r--r--compiler/rustc_mir_transform/src/unreachable_enum_branching.rs4
-rw-r--r--compiler/rustc_mir_transform/src/unreachable_prop.rs2
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs66
-rw-r--r--compiler/rustc_passes/src/loops.rs40
-rw-r--r--compiler/rustc_pattern_analysis/src/rustc.rs8
-rw-r--r--compiler/rustc_target/src/spec/mod.rs7
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs16
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs138
-rw-r--r--compiler/rustc_type_ir/src/solve/mod.rs2
69 files changed, 400 insertions, 384 deletions
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index e49ae60e890..cb2fa6e9d74 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -61,7 +61,6 @@ use rustc_session::lint::{Lint, LintId};
 use rustc_session::output::collect_crate_types;
 use rustc_session::{config, filesearch, EarlyDiagCtxt, Session};
 use rustc_span::source_map::FileLoader;
-use rustc_span::symbol::sym;
 use rustc_span::FileName;
 use rustc_target::json::ToJson;
 use rustc_target::spec::{Target, TargetTriple};
@@ -777,16 +776,8 @@ fn print_crate_info(
                     .config
                     .iter()
                     .filter_map(|&(name, value)| {
-                        // Note that crt-static is a specially recognized cfg
-                        // directive that's printed out here as part of
-                        // rust-lang/rust#37406, but in general the
-                        // `target_feature` cfg is gated under
-                        // rust-lang/rust#29717. For now this is just
-                        // specifically allowing the crt-static cfg and that's
-                        // it, this is intended to get into Cargo and then go
-                        // through to build scripts.
-                        if (name != sym::target_feature || value != Some(sym::crt_dash_static))
-                            && !sess.is_nightly_build()
+                        // On stable, exclude unstable flags.
+                        if !sess.is_nightly_build()
                             && find_gated_cfg(|cfg_sym| cfg_sym == name).is_some()
                         {
                             return None;
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
index 7be45463f15..149bc6d2698 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
@@ -133,9 +133,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 return;
             };
             let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &impl_trait_name);
-            if sugg.is_empty() {
-                return;
-            };
             diag.multipart_suggestion(
                 format!(
                     "alternatively use a blanket implementation to implement `{of_trait_name}` for \
@@ -170,6 +167,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let parent_id = tcx.hir().get_parent_item(self_ty.hir_id).def_id;
         // FIXME: If `type_alias_impl_trait` is enabled, also look for `Trait0<Ty = Trait1>`
         //        and suggest `Trait0<Ty = impl Trait1>`.
+        // Functions are found in three different contexts.
+        // 1. Independent functions
+        // 2. Functions inside trait blocks
+        // 3. Functions inside impl blocks
         let (sig, generics, owner) = match tcx.hir_node_by_def_id(parent_id) {
             hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, generics, _), .. }) => {
                 (sig, generics, None)
@@ -180,6 +181,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 owner_id,
                 ..
             }) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))),
+            hir::Node::ImplItem(hir::ImplItem {
+                kind: hir::ImplItemKind::Fn(sig, _),
+                generics,
+                owner_id,
+                ..
+            }) => (sig, generics, Some(tcx.parent(owner_id.to_def_id()))),
             _ => return false,
         };
         let Ok(trait_name) = tcx.sess.source_map().span_to_snippet(self_ty.span) else {
@@ -187,6 +194,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         };
         let impl_sugg = vec![(self_ty.span.shrink_to_lo(), "impl ".to_string())];
         let mut is_downgradable = true;
+
+        // Check if trait object is safe for suggesting dynamic dispatch.
         let is_object_safe = match self_ty.kind {
             hir::TyKind::TraitObject(objects, ..) => {
                 objects.iter().all(|(o, _)| match o.trait_ref.path.res {
@@ -202,8 +211,15 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
             _ => false,
         };
+
+        let borrowed = matches!(
+            tcx.parent_hir_node(self_ty.hir_id),
+            hir::Node::Ty(hir::Ty { kind: hir::TyKind::Ref(..), .. })
+        );
+
+        // Suggestions for function return type.
         if let hir::FnRetTy::Return(ty) = sig.decl.output
-            && ty.hir_id == self_ty.hir_id
+            && ty.peel_refs().hir_id == self_ty.hir_id
         {
             let pre = if !is_object_safe {
                 format!("`{trait_name}` is not object safe, ")
@@ -214,14 +230,26 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 "{pre}use `impl {trait_name}` to return an opaque type, as long as you return a \
                  single underlying type",
             );
+
             diag.multipart_suggestion_verbose(msg, impl_sugg, Applicability::MachineApplicable);
+
+            // Suggest `Box<dyn Trait>` for return type
             if is_object_safe {
-                diag.multipart_suggestion_verbose(
-                    "alternatively, you can return an owned trait object",
+                // If the return type is `&Trait`, we don't want
+                // the ampersand to be displayed in the `Box<dyn Trait>`
+                // suggestion.
+                let suggestion = if borrowed {
+                    vec![(ty.span, format!("Box<dyn {trait_name}>"))]
+                } else {
                     vec![
                         (ty.span.shrink_to_lo(), "Box<dyn ".to_string()),
                         (ty.span.shrink_to_hi(), ">".to_string()),
-                    ],
+                    ]
+                };
+
+                diag.multipart_suggestion_verbose(
+                    "alternatively, you can return an owned trait object",
+                    suggestion,
                     Applicability::MachineApplicable,
                 );
             } else if is_downgradable {
@@ -230,24 +258,24 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             }
             return true;
         }
+
+        // Suggestions for function parameters.
         for ty in sig.decl.inputs {
-            if ty.hir_id != self_ty.hir_id {
+            if ty.peel_refs().hir_id != self_ty.hir_id {
                 continue;
             }
             let sugg = self.add_generic_param_suggestion(generics, self_ty.span, &trait_name);
-            if !sugg.is_empty() {
-                diag.multipart_suggestion_verbose(
-                    format!("use a new generic type parameter, constrained by `{trait_name}`"),
-                    sugg,
-                    Applicability::MachineApplicable,
-                );
-                diag.multipart_suggestion_verbose(
-                    "you can also use an opaque type, but users won't be able to specify the type \
-                     parameter when calling the `fn`, having to rely exclusively on type inference",
-                    impl_sugg,
-                    Applicability::MachineApplicable,
-                );
-            }
+            diag.multipart_suggestion_verbose(
+                format!("use a new generic type parameter, constrained by `{trait_name}`"),
+                sugg,
+                Applicability::MachineApplicable,
+            );
+            diag.multipart_suggestion_verbose(
+                "you can also use an opaque type, but users won't be able to specify the type \
+                 parameter when calling the `fn`, having to rely exclusively on type inference",
+                impl_sugg,
+                Applicability::MachineApplicable,
+            );
             if !is_object_safe {
                 diag.note(format!("`{trait_name}` it is not object safe, so it can't be `dyn`"));
                 if is_downgradable {
@@ -255,14 +283,18 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     diag.downgrade_to_delayed_bug();
                 }
             } else {
+                // No ampersand in suggestion if it's borrowed already
+                let (dyn_str, paren_dyn_str) =
+                    if borrowed { ("dyn ", "(dyn ") } else { ("&dyn ", "&(dyn ") };
+
                 let sugg = if let hir::TyKind::TraitObject([_, _, ..], _, _) = self_ty.kind {
                     // There are more than one trait bound, we need surrounding parentheses.
                     vec![
-                        (self_ty.span.shrink_to_lo(), "&(dyn ".to_string()),
+                        (self_ty.span.shrink_to_lo(), paren_dyn_str.to_string()),
                         (self_ty.span.shrink_to_hi(), ")".to_string()),
                     ]
                 } else {
-                    vec![(self_ty.span.shrink_to_lo(), "&dyn ".to_string())]
+                    vec![(self_ty.span.shrink_to_lo(), dyn_str.to_string())]
                 };
                 diag.multipart_suggestion_verbose(
                     format!(
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 7b901915037..081a23b6ff3 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -3,8 +3,6 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
 
 use std::borrow::Cow;
-use std::cell::RefCell;
-use std::collections::hash_map::Entry;
 use std::fmt::{self, Debug, Formatter};
 use std::ops::{Index, IndexMut};
 use std::{iter, mem};
@@ -26,7 +24,6 @@ use rustc_index::bit_set::BitSet;
 use rustc_index::{Idx, IndexSlice, IndexVec};
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
 use rustc_serialize::{Decodable, Encodable};
-use rustc_session::Session;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::Symbol;
 use rustc_span::{Span, DUMMY_SP};
@@ -106,65 +103,6 @@ impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> {
     }
 }
 
-thread_local! {
-    static PASS_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) {
-        Entry::Occupied(e) => *e.get(),
-        Entry::Vacant(e) => {
-            let snake_case: String = type_name
-                .chars()
-                .flat_map(|c| {
-                    if c.is_ascii_uppercase() {
-                        vec!['_', c.to_ascii_lowercase()]
-                    } else if c == '-' {
-                        vec!['_']
-                    } else {
-                        vec![c]
-                    }
-                })
-                .collect();
-            let result = &*String::leak(format!("mir_pass{}", snake_case));
-            e.insert(result);
-            result
-        }
-    })
-}
-
-/// A streamlined trait that you can implement to create a pass; the
-/// pass will be named after the type, and it will consist of a main
-/// loop that goes over each available MIR and applies `run_pass`.
-pub trait MirPass<'tcx> {
-    fn name(&self) -> &'static str {
-        // FIXME Simplify the implementation once more `str` methods get const-stable.
-        // See copypaste in `MirLint`
-        const {
-            let name = std::any::type_name::<Self>();
-            crate::util::common::c_name(name)
-        }
-    }
-
-    fn profiler_name(&self) -> &'static str {
-        to_profiler_name(self.name())
-    }
-
-    /// Returns `true` if this pass is enabled with the current combination of compiler flags.
-    fn is_enabled(&self, _sess: &Session) -> bool {
-        true
-    }
-
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>);
-
-    fn is_mir_dump_enabled(&self) -> bool {
-        true
-    }
-}
-
 impl MirPhase {
     /// Gets the index of the current MirPhase within the set of all `MirPhase`s.
     ///
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index 698104b0462..dd00db8635f 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -81,10 +81,6 @@ impl<'tcx> VariantDef {
         adt: ty::AdtDef<'_>,
     ) -> InhabitedPredicate<'tcx> {
         debug_assert!(!adt.is_union());
-        if self.is_field_list_non_exhaustive() && !self.def_id.is_local() {
-            // Non-exhaustive variants from other crates are always considered inhabited.
-            return InhabitedPredicate::True;
-        }
         InhabitedPredicate::all(
             tcx,
             self.fields.iter().map(|field| {
diff --git a/compiler/rustc_middle/src/util/common.rs b/compiler/rustc_middle/src/util/common.rs
index 2038d3f8448..223b2b3bfe4 100644
--- a/compiler/rustc_middle/src/util/common.rs
+++ b/compiler/rustc_middle/src/util/common.rs
@@ -20,19 +20,3 @@ pub fn to_readable_str(mut val: usize) -> String {
 
     groups.join("_")
 }
-
-// const wrapper for `if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }`
-pub const fn c_name(name: &'static str) -> &'static str {
-    // FIXME Simplify the implementation once more `str` methods get const-stable.
-    // and inline into call site
-    let bytes = name.as_bytes();
-    let mut i = bytes.len();
-    while i > 0 && bytes[i - 1] != b':' {
-        i = i - 1;
-    }
-    let (_, bytes) = bytes.split_at(i);
-    match std::str::from_utf8(bytes) {
-        Ok(name) => name,
-        Err(_) => name,
-    }
-}
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index 0171cc85918..8c3e6f49b16 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -1,7 +1,7 @@
 use rustc_ast::MetaItem;
 use rustc_hir::def_id::DefId;
 use rustc_index::bit_set::BitSet;
-use rustc_middle::mir::{self, Body, Local, Location, MirPass};
+use rustc_middle::mir::{self, Body, Local, Location};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::Span;
@@ -18,8 +18,6 @@ use crate::impls::{
 use crate::move_paths::{HasMoveData, LookupResult, MoveData, MovePathIndex};
 use crate::{Analysis, JoinSemiLattice, ResultsCursor};
 
-pub struct SanityCheck;
-
 fn has_rustc_mir_with(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Option<MetaItem> {
     for attr in tcx.get_attrs(def_id, sym::rustc_mir) {
         let items = attr.meta_item_list();
@@ -33,53 +31,50 @@ fn has_rustc_mir_with(tcx: TyCtxt<'_>, def_id: DefId, name: Symbol) -> Option<Me
     None
 }
 
-// FIXME: This should be a `MirLint`, but it needs to be moved back to `rustc_mir_transform` first.
-impl<'tcx> MirPass<'tcx> for SanityCheck {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let def_id = body.source.def_id();
-        if !tcx.has_attr(def_id, sym::rustc_mir) {
-            debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
-            return;
-        } else {
-            debug!("running rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
-        }
+pub fn sanity_check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
+    let def_id = body.source.def_id();
+    if !tcx.has_attr(def_id, sym::rustc_mir) {
+        debug!("skipping rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
+        return;
+    } else {
+        debug!("running rustc_peek::SanityCheck on {}", tcx.def_path_str(def_id));
+    }
 
-        let param_env = tcx.param_env(def_id);
-        let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true);
+    let param_env = tcx.param_env(def_id);
+    let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true);
 
-        if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() {
-            let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
-                .into_engine(tcx, body)
-                .iterate_to_fixpoint();
+    if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_init).is_some() {
+        let flow_inits = MaybeInitializedPlaces::new(tcx, body, &move_data)
+            .into_engine(tcx, body)
+            .iterate_to_fixpoint();
 
-            sanity_check_via_rustc_peek(tcx, flow_inits.into_results_cursor(body));
-        }
+        sanity_check_via_rustc_peek(tcx, flow_inits.into_results_cursor(body));
+    }
 
-        if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() {
-            let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data)
-                .into_engine(tcx, body)
-                .iterate_to_fixpoint();
+    if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_maybe_uninit).is_some() {
+        let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &move_data)
+            .into_engine(tcx, body)
+            .iterate_to_fixpoint();
 
-            sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body));
-        }
+        sanity_check_via_rustc_peek(tcx, flow_uninits.into_results_cursor(body));
+    }
 
-        if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
-            let flow_def_inits = DefinitelyInitializedPlaces::new(body, &move_data)
-                .into_engine(tcx, body)
-                .iterate_to_fixpoint();
+    if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_definite_init).is_some() {
+        let flow_def_inits = DefinitelyInitializedPlaces::new(body, &move_data)
+            .into_engine(tcx, body)
+            .iterate_to_fixpoint();
 
-            sanity_check_via_rustc_peek(tcx, flow_def_inits.into_results_cursor(body));
-        }
+        sanity_check_via_rustc_peek(tcx, flow_def_inits.into_results_cursor(body));
+    }
 
-        if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() {
-            let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint();
+    if has_rustc_mir_with(tcx, def_id, sym::rustc_peek_liveness).is_some() {
+        let flow_liveness = MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint();
 
-            sanity_check_via_rustc_peek(tcx, flow_liveness.into_results_cursor(body));
-        }
+        sanity_check_via_rustc_peek(tcx, flow_liveness.into_results_cursor(body));
+    }
 
-        if has_rustc_mir_with(tcx, def_id, sym::stop_after_dataflow).is_some() {
-            tcx.dcx().emit_fatal(StopAfterDataFlowEndedCompilation);
-        }
+    if has_rustc_mir_with(tcx, def_id, sym::stop_after_dataflow).is_some() {
+        tcx.dcx().emit_fatal(StopAfterDataFlowEndedCompilation);
     }
 }
 
diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
index edb6bc4fbea..e4bc6b3efe4 100644
--- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
+++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
@@ -22,7 +22,7 @@ use rustc_target::spec::PanicStrategy;
 #[derive(PartialEq)]
 pub struct AbortUnwindingCalls;
 
-impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
+impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let def_id = body.source.def_id();
         let kind = tcx.def_kind(def_id);
diff --git a/compiler/rustc_mir_transform/src/add_call_guards.rs b/compiler/rustc_mir_transform/src/add_call_guards.rs
index df5312d155c..78e850de3c7 100644
--- a/compiler/rustc_mir_transform/src/add_call_guards.rs
+++ b/compiler/rustc_mir_transform/src/add_call_guards.rs
@@ -30,7 +30,7 @@ pub use self::AddCallGuards::*;
  *
  */
 
-impl<'tcx> MirPass<'tcx> for AddCallGuards {
+impl<'tcx> crate::MirPass<'tcx> for AddCallGuards {
     fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         self.add_call_guards(body);
     }
diff --git a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
index e503119a349..4a8196aeff5 100644
--- a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
+++ b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
@@ -37,7 +37,7 @@ use crate::util;
 /// blowup.
 pub struct AddMovesForPackedDrops;
 
-impl<'tcx> MirPass<'tcx> for AddMovesForPackedDrops {
+impl<'tcx> crate::MirPass<'tcx> for AddMovesForPackedDrops {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         debug!("add_moves_for_packed_drops({:?} @ {:?})", body.source, body.span);
         add_moves_for_packed_drops(tcx, body);
diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs
index 79bc21cab14..2e12064fe73 100644
--- a/compiler/rustc_mir_transform/src/add_retag.rs
+++ b/compiler/rustc_mir_transform/src/add_retag.rs
@@ -48,7 +48,7 @@ fn may_contain_reference<'tcx>(ty: Ty<'tcx>, depth: u32, tcx: TyCtxt<'tcx>) -> b
     }
 }
 
-impl<'tcx> MirPass<'tcx> for AddRetag {
+impl<'tcx> crate::MirPass<'tcx> for AddRetag {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.opts.unstable_opts.mir_emit_retag
     }
diff --git a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
index 04204c68f7b..369f6c60084 100644
--- a/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
+++ b/compiler/rustc_mir_transform/src/add_subtyping_projections.rs
@@ -62,7 +62,7 @@ pub fn subtype_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     checker.patcher.apply(body);
 }
 
-impl<'tcx> MirPass<'tcx> for Subtyper {
+impl<'tcx> crate::MirPass<'tcx> for Subtyper {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         subtype_finder(tcx, body);
     }
diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs
index ad362f22ce1..2e072aa262a 100644
--- a/compiler/rustc_mir_transform/src/check_alignment.rs
+++ b/compiler/rustc_mir_transform/src/check_alignment.rs
@@ -9,7 +9,7 @@ use tracing::{debug, trace};
 
 pub struct CheckAlignment;
 
-impl<'tcx> MirPass<'tcx> for CheckAlignment {
+impl<'tcx> crate::MirPass<'tcx> for CheckAlignment {
     fn is_enabled(&self, sess: &Session) -> bool {
         // FIXME(#112480) MSVC and rustc disagree on minimum stack alignment on x86 Windows
         if sess.target.llvm_target == "i686-pc-windows-msvc" {
diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
index 1f615c9d8d1..fb03323e37e 100644
--- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
+++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
@@ -6,11 +6,11 @@ use rustc_session::lint::builtin::CONST_ITEM_MUTATION;
 use rustc_span::def_id::DefId;
 use rustc_span::Span;
 
-use crate::{errors, MirLint};
+use crate::errors;
 
 pub struct CheckConstItemMutation;
 
-impl<'tcx> MirLint<'tcx> for CheckConstItemMutation {
+impl<'tcx> crate::MirLint<'tcx> for CheckConstItemMutation {
     fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
         let mut checker = ConstMutationChecker { body, tcx, target_local: None };
         checker.visit_body(body);
diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs
index eb76a39be57..2f957de7e78 100644
--- a/compiler/rustc_mir_transform/src/check_packed_ref.rs
+++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs
@@ -3,11 +3,11 @@ use rustc_middle::mir::*;
 use rustc_middle::span_bug;
 use rustc_middle::ty::{self, TyCtxt};
 
-use crate::{errors, util, MirLint};
+use crate::{errors, util};
 
 pub struct CheckPackedRef;
 
-impl<'tcx> MirLint<'tcx> for CheckPackedRef {
+impl<'tcx> crate::MirLint<'tcx> for CheckPackedRef {
     fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
         let param_env = tcx.param_env(body.source.def_id());
         let source_info = SourceInfo::outermost(body.span);
diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
index 08c9f9f08e6..2f3be1e425d 100644
--- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
+++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
@@ -21,11 +21,9 @@ use rustc_middle::mir::{Body, BorrowKind, CastKind, Rvalue, StatementKind, Termi
 use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::TyCtxt;
 
-use crate::MirPass;
-
 pub struct CleanupPostBorrowck;
 
-impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck {
+impl<'tcx> crate::MirPass<'tcx> for CleanupPostBorrowck {
     fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         for basic_block in body.basic_blocks.as_mut() {
             for statement in basic_block.statements.iter_mut() {
diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs
index 5c267f85378..85d25ca2231 100644
--- a/compiler/rustc_mir_transform/src/copy_prop.rs
+++ b/compiler/rustc_mir_transform/src/copy_prop.rs
@@ -19,7 +19,7 @@ use crate::ssa::SsaLocals;
 /// We want to replace all those locals by `_a`, either copied or moved.
 pub struct CopyProp;
 
-impl<'tcx> MirPass<'tcx> for CopyProp {
+impl<'tcx> crate::MirPass<'tcx> for CopyProp {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.mir_opt_level() >= 1
     }
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 80ba1c42668..eefb748e49d 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -1535,7 +1535,7 @@ fn check_field_tys_sized<'tcx>(
     }
 }
 
-impl<'tcx> MirPass<'tcx> for StateTransform {
+impl<'tcx> crate::MirPass<'tcx> for StateTransform {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let Some(old_yield_ty) = body.yield_ty() else {
             // This only applies to coroutines
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index bba354d2936..4edba61fdec 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -28,14 +28,13 @@ use tracing::{debug, debug_span, instrument, trace};
 use crate::coverage::counters::{CounterIncrementSite, CoverageCounters};
 use crate::coverage::graph::CoverageGraph;
 use crate::coverage::mappings::ExtractedMappings;
-use crate::MirPass;
 
 /// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected
 /// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen
 /// to construct the coverage map.
 pub struct InstrumentCoverage;
 
-impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
+impl<'tcx> crate::MirPass<'tcx> for InstrumentCoverage {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.instrument_coverage()
     }
diff --git a/compiler/rustc_mir_transform/src/ctfe_limit.rs b/compiler/rustc_mir_transform/src/ctfe_limit.rs
index bf522fd5ef4..ea473b64ce5 100644
--- a/compiler/rustc_mir_transform/src/ctfe_limit.rs
+++ b/compiler/rustc_mir_transform/src/ctfe_limit.rs
@@ -8,11 +8,9 @@ use rustc_middle::mir::{
 use rustc_middle::ty::TyCtxt;
 use tracing::instrument;
 
-use crate::MirPass;
-
 pub struct CtfeLimit;
 
-impl<'tcx> MirPass<'tcx> for CtfeLimit {
+impl<'tcx> crate::MirPass<'tcx> for CtfeLimit {
     #[instrument(skip(self, _tcx, body))]
     fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let doms = body.basic_blocks.dominators();
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index b16d25c93bb..46f7408ef80 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -28,7 +28,7 @@ const PLACE_LIMIT: usize = 100;
 
 pub struct DataflowConstProp;
 
-impl<'tcx> MirPass<'tcx> for DataflowConstProp {
+impl<'tcx> crate::MirPass<'tcx> for DataflowConstProp {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.mir_opt_level() >= 3
     }
diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
index 39c8db184a5..9081a2e2e30 100644
--- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs
+++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
@@ -132,7 +132,7 @@ pub enum DeadStoreElimination {
     Final,
 }
 
-impl<'tcx> MirPass<'tcx> for DeadStoreElimination {
+impl<'tcx> crate::MirPass<'tcx> for DeadStoreElimination {
     fn name(&self) -> &'static str {
         match self {
             DeadStoreElimination::Initial => "DeadStoreElimination-initial",
diff --git a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
index b38f4a4a823..be50c1da8a4 100644
--- a/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
+++ b/compiler/rustc_mir_transform/src/deduplicate_blocks.rs
@@ -15,7 +15,7 @@ use super::simplify::simplify_cfg;
 
 pub struct DeduplicateBlocks;
 
-impl<'tcx> MirPass<'tcx> for DeduplicateBlocks {
+impl<'tcx> crate::MirPass<'tcx> for DeduplicateBlocks {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.mir_opt_level() >= 4
     }
diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs
index 0e2fccc85da..a878f777448 100644
--- a/compiler/rustc_mir_transform/src/deref_separator.rs
+++ b/compiler/rustc_mir_transform/src/deref_separator.rs
@@ -78,7 +78,7 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     checker.patcher.apply(body);
 }
 
-impl<'tcx> MirPass<'tcx> for Derefer {
+impl<'tcx> crate::MirPass<'tcx> for Derefer {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         deref_finder(tcx, body);
     }
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index a6d626d3f8f..8940a21d7fa 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -146,11 +146,9 @@ use rustc_mir_dataflow::points::{save_as_intervals, DenseLocationMap, PointIndex
 use rustc_mir_dataflow::Analysis;
 use tracing::{debug, trace};
 
-use crate::MirPass;
-
 pub struct DestinationPropagation;
 
-impl<'tcx> MirPass<'tcx> for DestinationPropagation {
+impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         // For now, only run at MIR opt level 3. Two things need to be changed before this can be
         // turned on by default:
diff --git a/compiler/rustc_mir_transform/src/dump_mir.rs b/compiler/rustc_mir_transform/src/dump_mir.rs
index 29db45f9450..06ae1b490d7 100644
--- a/compiler/rustc_mir_transform/src/dump_mir.rs
+++ b/compiler/rustc_mir_transform/src/dump_mir.rs
@@ -7,11 +7,9 @@ use rustc_middle::mir::{write_mir_pretty, Body};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{OutFileName, OutputType};
 
-use crate::MirPass;
-
 pub struct Marker(pub &'static str);
 
-impl<'tcx> MirPass<'tcx> for Marker {
+impl<'tcx> crate::MirPass<'tcx> for Marker {
     fn name(&self) -> &'static str {
         self.0
     }
diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
index 67b81efd614..1c54cd70023 100644
--- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
+++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
@@ -92,7 +92,7 @@ use super::simplify::simplify_cfg;
 /// ```
 pub struct EarlyOtherwiseBranch;
 
-impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
+impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.mir_opt_level() >= 2
     }
diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
index e5778f8a05d..5dd82f40163 100644
--- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
@@ -88,7 +88,7 @@ impl<'tcx, 'a> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'tcx, 'a> {
 
 pub struct ElaborateBoxDerefs;
 
-impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs {
+impl<'tcx> crate::MirPass<'tcx> for ElaborateBoxDerefs {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         if let Some(def_id) = tcx.lang_items().owned_box() {
             let unique_did = tcx.adt_def(def_id).non_enum_variant().fields[FieldIdx::ZERO].did;
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index d0809d9388d..f4a951ebde6 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -49,7 +49,7 @@ use crate::deref_separator::deref_finder;
 /// ```
 pub struct ElaborateDrops;
 
-impl<'tcx> MirPass<'tcx> for ElaborateDrops {
+impl<'tcx> crate::MirPass<'tcx> for ElaborateDrops {
     #[instrument(level = "trace", skip(self, tcx, body))]
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         debug!("elaborate_drops({:?} @ {:?})", body.source, body.span);
diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs
index b7873e73c18..199fd0f10ee 100644
--- a/compiler/rustc_mir_transform/src/function_item_references.rs
+++ b/compiler/rustc_mir_transform/src/function_item_references.rs
@@ -9,11 +9,11 @@ use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 
-use crate::{errors, MirLint};
+use crate::errors;
 
 pub struct FunctionItemReferences;
 
-impl<'tcx> MirLint<'tcx> for FunctionItemReferences {
+impl<'tcx> crate::MirLint<'tcx> for FunctionItemReferences {
     fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
         let mut checker = FunctionItemRefChecker { tcx, body };
         checker.visit_body(body);
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index fb9baeeb3ed..df0fcc42e59 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -111,7 +111,7 @@ use crate::ssa::{AssignedValue, SsaLocals};
 
 pub struct GVN;
 
-impl<'tcx> MirPass<'tcx> for GVN {
+impl<'tcx> crate::MirPass<'tcx> for GVN {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.mir_opt_level() >= 2
     }
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 4482801826a..6cc7e0ee1e4 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -42,7 +42,7 @@ struct CallSite<'tcx> {
     source_info: SourceInfo,
 }
 
-impl<'tcx> MirPass<'tcx> for Inline {
+impl<'tcx> crate::MirPass<'tcx> for Inline {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         // FIXME(#127234): Coverage instrumentation currently doesn't handle inlined
         // MIR correctly when Modified Condition/Decision Coverage is enabled.
diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index 3ec553d0ba0..4fbfa744e67 100644
--- a/compiler/rustc_mir_transform/src/instsimplify.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -27,7 +27,7 @@ impl InstSimplify {
     }
 }
 
-impl<'tcx> MirPass<'tcx> for InstSimplify {
+impl<'tcx> crate::MirPass<'tcx> for InstSimplify {
     fn name(&self) -> &'static str {
         self.name()
     }
diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs
index 435b6a01163..02dd56e1b4f 100644
--- a/compiler/rustc_mir_transform/src/jump_threading.rs
+++ b/compiler/rustc_mir_transform/src/jump_threading.rs
@@ -61,7 +61,7 @@ const MAX_BACKTRACK: usize = 5;
 const MAX_COST: usize = 100;
 const MAX_PLACES: usize = 100;
 
-impl<'tcx> MirPass<'tcx> for JumpThreading {
+impl<'tcx> crate::MirPass<'tcx> for JumpThreading {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.mir_opt_level() >= 2
     }
diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs
index 15d71ee2ac8..61405fb25c6 100644
--- a/compiler/rustc_mir_transform/src/known_panics_lint.rs
+++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs
@@ -25,11 +25,10 @@ use rustc_target::abi::{Abi, FieldIdx, HasDataLayout, Size, TargetDataLayout, Va
 use tracing::{debug, instrument, trace};
 
 use crate::errors::{AssertLint, AssertLintKind};
-use crate::MirLint;
 
 pub struct KnownPanicsLint;
 
-impl<'tcx> MirLint<'tcx> for KnownPanicsLint {
+impl<'tcx> crate::MirLint<'tcx> for KnownPanicsLint {
     fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
         if body.tainted_by_errors.is_some() {
             return;
diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs
index cbc3169f2f1..f02ba71ddc6 100644
--- a/compiler/rustc_mir_transform/src/large_enums.rs
+++ b/compiler/rustc_mir_transform/src/large_enums.rs
@@ -27,7 +27,7 @@ pub struct EnumSizeOpt {
     pub(crate) discrepancy: u64,
 }
 
-impl<'tcx> MirPass<'tcx> for EnumSizeOpt {
+impl<'tcx> crate::MirPass<'tcx> for EnumSizeOpt {
     fn is_enabled(&self, sess: &Session) -> bool {
         // There are some differences in behavior on wasm and ARM that are not properly
         // understood, so we conservatively treat this optimization as unsound:
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 9e460a725ee..62e73ba2c8e 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -26,13 +26,12 @@ use rustc_hir::intravisit::{self, Visitor};
 use rustc_index::IndexVec;
 use rustc_middle::mir::{
     AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstOperand, ConstQualifs, LocalDecl,
-    MirPass, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo,
+    MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo,
     Statement, StatementKind, TerminatorKind, START_BLOCK,
 };
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
 use rustc_middle::util::Providers;
 use rustc_middle::{bug, query, span_bug};
-use rustc_mir_dataflow::rustc_peek;
 use rustc_span::source_map::Spanned;
 use rustc_span::{sym, DUMMY_SP};
 use rustc_trait_selection::traits;
@@ -41,7 +40,7 @@ use tracing::{debug, trace};
 #[macro_use]
 mod pass_manager;
 
-use pass_manager::{self as pm, Lint, MirLint, WithMinOptLevel};
+use pass_manager::{self as pm, Lint, MirLint, MirPass, WithMinOptLevel};
 
 mod abort_unwinding_calls;
 mod add_call_guards;
@@ -96,6 +95,7 @@ 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
@@ -288,7 +288,7 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
             &Lint(function_item_references::FunctionItemReferences),
             // What we need to do constant evaluation.
             &simplify::SimplifyCfg::Initial,
-            &rustc_peek::SanityCheck, // Just a lint
+            &Lint(sanity_check::SanityCheck),
         ],
         None,
     );
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index a9bdff95fe5..55eec332306 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -9,7 +9,7 @@ use crate::take_array;
 
 pub struct LowerIntrinsics;
 
-impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
+impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let local_decls = &body.local_decls;
         for block in body.basic_blocks.as_mut() {
diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs
index 77a7f4f47dd..555309a7750 100644
--- a/compiler/rustc_mir_transform/src/lower_slice_len.rs
+++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs
@@ -7,7 +7,7 @@ use rustc_middle::ty::TyCtxt;
 
 pub struct LowerSliceLenCalls;
 
-impl<'tcx> MirPass<'tcx> for LowerSliceLenCalls {
+impl<'tcx> crate::MirPass<'tcx> for LowerSliceLenCalls {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.mir_opt_level() > 0
     }
diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs
index 5240f1c887c..233b39fb47a 100644
--- a/compiler/rustc_mir_transform/src/match_branches.rs
+++ b/compiler/rustc_mir_transform/src/match_branches.rs
@@ -12,7 +12,7 @@ use super::simplify::simplify_cfg;
 
 pub struct MatchBranchSimplification;
 
-impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
+impl<'tcx> crate::MirPass<'tcx> for MatchBranchSimplification {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.mir_opt_level() >= 1
     }
diff --git a/compiler/rustc_mir_transform/src/mentioned_items.rs b/compiler/rustc_mir_transform/src/mentioned_items.rs
index 32c8064ebca..41ce03caf08 100644
--- a/compiler/rustc_mir_transform/src/mentioned_items.rs
+++ b/compiler/rustc_mir_transform/src/mentioned_items.rs
@@ -1,5 +1,5 @@
 use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::{self, Location, MentionedItem, MirPass};
+use rustc_middle::mir::{self, Location, MentionedItem};
 use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::Session;
@@ -13,7 +13,7 @@ struct MentionedItemsVisitor<'a, 'tcx> {
     mentioned_items: &'a mut Vec<Spanned<MentionedItem<'tcx>>>,
 }
 
-impl<'tcx> MirPass<'tcx> for MentionedItems {
+impl<'tcx> crate::MirPass<'tcx> for MentionedItems {
     fn is_enabled(&self, _sess: &Session) -> bool {
         // If this pass is skipped the collector assume that nothing got mentioned! We could
         // potentially skip it in opt-level 0 if we are sure that opt-level will never *remove* uses
diff --git a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
index 1e87a0e01d9..1b4972d487e 100644
--- a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
+++ b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
@@ -9,7 +9,7 @@ use crate::simplify;
 
 pub struct MultipleReturnTerminators;
 
-impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators {
+impl<'tcx> crate::MirPass<'tcx> for MultipleReturnTerminators {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.mir_opt_level() >= 4
     }
diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs
index dd1875f2a78..94573a9d89b 100644
--- a/compiler/rustc_mir_transform/src/nrvo.rs
+++ b/compiler/rustc_mir_transform/src/nrvo.rs
@@ -8,8 +8,6 @@ use rustc_middle::mir::{self, BasicBlock, Local, Location};
 use rustc_middle::ty::TyCtxt;
 use tracing::{debug, trace};
 
-use crate::MirPass;
-
 /// This pass looks for MIR that always copies the same local into the return place and eliminates
 /// the copy by renaming all uses of that local to `_0`.
 ///
@@ -34,7 +32,7 @@ use crate::MirPass;
 /// [#71003]: https://github.com/rust-lang/rust/pull/71003
 pub struct RenameReturnPlace;
 
-impl<'tcx> MirPass<'tcx> for RenameReturnPlace {
+impl<'tcx> crate::MirPass<'tcx> for RenameReturnPlace {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         // unsound: #111005
         sess.mir_opt_level() > 0 && sess.opts.unstable_opts.unsound_mir_opts
diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs
index 51e27600404..28d4e1a1c91 100644
--- a/compiler/rustc_mir_transform/src/pass_manager.rs
+++ b/compiler/rustc_mir_transform/src/pass_manager.rs
@@ -1,19 +1,99 @@
+use std::cell::RefCell;
+use std::collections::hash_map::Entry;
+
+use rustc_data_structures::fx::FxHashMap;
 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, MirPass};
+use crate::validate;
+
+thread_local! {
+    static PASS_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) {
+        Entry::Occupied(e) => *e.get(),
+        Entry::Vacant(e) => {
+            let snake_case: String = type_name
+                .chars()
+                .flat_map(|c| {
+                    if c.is_ascii_uppercase() {
+                        vec!['_', c.to_ascii_lowercase()]
+                    } else if c == '-' {
+                        vec!['_']
+                    } else {
+                        vec![c]
+                    }
+                })
+                .collect();
+            let result = &*String::leak(format!("mir_pass{}", snake_case));
+            e.insert(result);
+            result
+        }
+    })
+}
+
+// const wrapper for `if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }`
+const fn c_name(name: &'static str) -> &'static str {
+    // FIXME Simplify the implementation once more `str` methods get const-stable.
+    // and inline into call site
+    let bytes = name.as_bytes();
+    let mut i = bytes.len();
+    while i > 0 && bytes[i - 1] != b':' {
+        i = i - 1;
+    }
+    let (_, bytes) = bytes.split_at(i);
+    match std::str::from_utf8(bytes) {
+        Ok(name) => name,
+        Err(_) => name,
+    }
+}
+
+/// A streamlined trait that you can implement to create a pass; the
+/// pass will be named after the type, and it will consist of a main
+/// loop that goes over each available MIR and applies `run_pass`.
+pub(super) trait MirPass<'tcx> {
+    fn name(&self) -> &'static str {
+        // FIXME Simplify the implementation once more `str` methods get const-stable.
+        // See copypaste in `MirLint`
+        const {
+            let name = std::any::type_name::<Self>();
+            c_name(name)
+        }
+    }
+
+    fn profiler_name(&self) -> &'static str {
+        to_profiler_name(self.name())
+    }
+
+    /// Returns `true` if this pass is enabled with the current combination of compiler flags.
+    fn is_enabled(&self, _sess: &Session) -> bool {
+        true
+    }
+
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>);
+
+    fn is_mir_dump_enabled(&self) -> bool {
+        true
+    }
+}
 
-/// Just like `MirPass`, except it cannot mutate `Body`.
-pub trait MirLint<'tcx> {
+/// Just like `MirPass`, except it cannot mutate `Body`, and MIR dumping is
+/// disabled (via the `Lint` adapter).
+pub(super) trait MirLint<'tcx> {
     fn name(&self) -> &'static str {
         // FIXME Simplify the implementation once more `str` methods get const-stable.
         // See copypaste in `MirPass`
         const {
             let name = std::any::type_name::<Self>();
-            rustc_middle::util::common::c_name(name)
+            c_name(name)
         }
     }
 
@@ -26,7 +106,7 @@ pub trait MirLint<'tcx> {
 
 /// An adapter for `MirLint`s that implements `MirPass`.
 #[derive(Debug, Clone)]
-pub struct Lint<T>(pub T);
+pub(super) struct Lint<T>(pub T);
 
 impl<'tcx, T> MirPass<'tcx> for Lint<T>
 where
@@ -49,7 +129,7 @@ where
     }
 }
 
-pub struct WithMinOptLevel<T>(pub u32, pub T);
+pub(super) struct WithMinOptLevel<T>(pub u32, pub T);
 
 impl<'tcx, T> MirPass<'tcx> for WithMinOptLevel<T>
 where
@@ -70,7 +150,7 @@ where
 
 /// Run the sequence of passes without validating the MIR after each pass. The MIR is still
 /// validated at the end.
-pub fn run_passes_no_validate<'tcx>(
+pub(super) fn run_passes_no_validate<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &mut Body<'tcx>,
     passes: &[&dyn MirPass<'tcx>],
@@ -80,7 +160,7 @@ pub fn run_passes_no_validate<'tcx>(
 }
 
 /// The optional `phase_change` is applied after executing all the passes, if present
-pub fn run_passes<'tcx>(
+pub(super) fn run_passes<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &mut Body<'tcx>,
     passes: &[&dyn MirPass<'tcx>],
@@ -89,7 +169,7 @@ pub fn run_passes<'tcx>(
     run_passes_inner(tcx, body, passes, phase_change, true);
 }
 
-pub fn should_run_pass<'tcx, P>(tcx: TyCtxt<'tcx>, pass: &P) -> bool
+pub(super) fn should_run_pass<'tcx, P>(tcx: TyCtxt<'tcx>, pass: &P) -> bool
 where
     P: MirPass<'tcx> + ?Sized,
 {
@@ -185,11 +265,11 @@ fn run_passes_inner<'tcx>(
     }
 }
 
-pub fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: String) {
+pub(super) fn validate_body<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, when: String) {
     validate::Validator { when, mir_phase: body.phase }.run_pass(tcx, body);
 }
 
-pub fn dump_mir_for_pass<'tcx>(
+pub(super) fn dump_mir_for_pass<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
     pass_name: &str,
@@ -205,7 +285,7 @@ pub fn dump_mir_for_pass<'tcx>(
     );
 }
 
-pub fn dump_mir_for_phase_change<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
+pub(super) fn dump_mir_for_phase_change<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
     assert_eq!(body.pass_count, 0);
     mir::dump_mir(tcx, true, body.phase.name(), &"after", body, |_, _| Ok(()))
 }
diff --git a/compiler/rustc_mir_transform/src/prettify.rs b/compiler/rustc_mir_transform/src/prettify.rs
index 14dd0c6f61e..ad71c622660 100644
--- a/compiler/rustc_mir_transform/src/prettify.rs
+++ b/compiler/rustc_mir_transform/src/prettify.rs
@@ -17,7 +17,7 @@ use rustc_session::Session;
 /// `IndexVec`, unless that successor is a back-edge (such as from a loop).
 pub struct ReorderBasicBlocks;
 
-impl<'tcx> MirPass<'tcx> for ReorderBasicBlocks {
+impl<'tcx> crate::MirPass<'tcx> for ReorderBasicBlocks {
     fn is_enabled(&self, _session: &Session) -> bool {
         false
     }
@@ -45,7 +45,7 @@ impl<'tcx> MirPass<'tcx> for ReorderBasicBlocks {
 /// (Does not reorder arguments nor the [`RETURN_PLACE`].)
 pub struct ReorderLocals;
 
-impl<'tcx> MirPass<'tcx> for ReorderLocals {
+impl<'tcx> crate::MirPass<'tcx> for ReorderLocals {
     fn is_enabled(&self, _session: &Session) -> bool {
         false
     }
diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs
index 0c940bac13c..cf0a569ffa4 100644
--- a/compiler/rustc_mir_transform/src/promote_consts.rs
+++ b/compiler/rustc_mir_transform/src/promote_consts.rs
@@ -41,7 +41,7 @@ pub struct PromoteTemps<'tcx> {
     pub promoted_fragments: Cell<IndexVec<Promoted, Body<'tcx>>>,
 }
 
-impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
+impl<'tcx> crate::MirPass<'tcx> for PromoteTemps<'tcx> {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // There's not really any point in promoting errorful MIR.
         //
diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs
index 8d0b47cb34a..4a447d24cce 100644
--- a/compiler/rustc_mir_transform/src/ref_prop.rs
+++ b/compiler/rustc_mir_transform/src/ref_prop.rs
@@ -72,7 +72,7 @@ use crate::ssa::{SsaLocals, StorageLiveLocals};
 /// so we perform all the possible instantiations without removing the `_1 = &_2` statement.
 pub struct ReferencePropagation;
 
-impl<'tcx> MirPass<'tcx> for ReferencePropagation {
+impl<'tcx> crate::MirPass<'tcx> for ReferencePropagation {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.mir_opt_level() >= 2
     }
diff --git a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
index 33c7d1695c0..ccba8d015e3 100644
--- a/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir_transform/src/remove_noop_landing_pads.rs
@@ -10,7 +10,7 @@ use tracing::debug;
 /// terrible code for these.
 pub struct RemoveNoopLandingPads;
 
-impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads {
+impl<'tcx> crate::MirPass<'tcx> for RemoveNoopLandingPads {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.panic_strategy() != PanicStrategy::Abort
     }
diff --git a/compiler/rustc_mir_transform/src/remove_place_mention.rs b/compiler/rustc_mir_transform/src/remove_place_mention.rs
index 6c0b50fafdb..5801fdedceb 100644
--- a/compiler/rustc_mir_transform/src/remove_place_mention.rs
+++ b/compiler/rustc_mir_transform/src/remove_place_mention.rs
@@ -6,7 +6,7 @@ use tracing::trace;
 
 pub struct RemovePlaceMention;
 
-impl<'tcx> MirPass<'tcx> for RemovePlaceMention {
+impl<'tcx> crate::MirPass<'tcx> for RemovePlaceMention {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         !sess.opts.unstable_opts.mir_keep_place_mention
     }
diff --git a/compiler/rustc_mir_transform/src/remove_storage_markers.rs b/compiler/rustc_mir_transform/src/remove_storage_markers.rs
index af89395dddd..329b30d3890 100644
--- a/compiler/rustc_mir_transform/src/remove_storage_markers.rs
+++ b/compiler/rustc_mir_transform/src/remove_storage_markers.rs
@@ -6,7 +6,7 @@ use tracing::trace;
 
 pub struct RemoveStorageMarkers;
 
-impl<'tcx> MirPass<'tcx> for RemoveStorageMarkers {
+impl<'tcx> crate::MirPass<'tcx> for RemoveStorageMarkers {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.mir_opt_level() > 0 && !sess.emit_lifetime_markers()
     }
diff --git a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
index fae1cb5f7d8..aafe971311d 100644
--- a/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_uninit_drops.rs
@@ -6,8 +6,6 @@ use rustc_mir_dataflow::move_paths::{LookupResult, MoveData, MovePathIndex};
 use rustc_mir_dataflow::{move_path_children_matching, Analysis, MaybeReachable};
 use rustc_target::abi::FieldIdx;
 
-use crate::MirPass;
-
 /// Removes `Drop` terminators whose target is known to be uninitialized at
 /// that point.
 ///
@@ -18,7 +16,7 @@ use crate::MirPass;
 /// [#90770]: https://github.com/rust-lang/rust/issues/90770
 pub struct RemoveUninitDrops;
 
-impl<'tcx> MirPass<'tcx> for RemoveUninitDrops {
+impl<'tcx> crate::MirPass<'tcx> for RemoveUninitDrops {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let param_env = tcx.param_env(body.source.def_id());
         let move_data =
diff --git a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
index 9adcb5a38fd..43109aae0fb 100644
--- a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
@@ -12,7 +12,7 @@ use super::simplify::simplify_cfg;
 
 pub struct RemoveUnneededDrops;
 
-impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops {
+impl<'tcx> crate::MirPass<'tcx> for RemoveUnneededDrops {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         trace!("Running RemoveUnneededDrops on {:?}", body.source);
 
diff --git a/compiler/rustc_mir_transform/src/remove_zsts.rs b/compiler/rustc_mir_transform/src/remove_zsts.rs
index 9a94cae3382..9aa46bd4fba 100644
--- a/compiler/rustc_mir_transform/src/remove_zsts.rs
+++ b/compiler/rustc_mir_transform/src/remove_zsts.rs
@@ -6,7 +6,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
 
 pub struct RemoveZsts;
 
-impl<'tcx> MirPass<'tcx> for RemoveZsts {
+impl<'tcx> crate::MirPass<'tcx> for RemoveZsts {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.mir_opt_level() > 0
     }
diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs
index 5eaa024f846..29312a99cbc 100644
--- a/compiler/rustc_mir_transform/src/reveal_all.rs
+++ b/compiler/rustc_mir_transform/src/reveal_all.rs
@@ -6,7 +6,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
 
 pub struct RevealAll;
 
-impl<'tcx> MirPass<'tcx> for RevealAll {
+impl<'tcx> crate::MirPass<'tcx> for RevealAll {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
         RevealAllVisitor { tcx, param_env }.visit_body_preserves_cfg(body);
diff --git a/compiler/rustc_mir_transform/src/sanity_check.rs b/compiler/rustc_mir_transform/src/sanity_check.rs
new file mode 100644
index 00000000000..c9445d18162
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/sanity_check.rs
@@ -0,0 +1,11 @@
+use rustc_middle::mir::Body;
+use rustc_middle::ty::TyCtxt;
+use rustc_mir_dataflow::rustc_peek::sanity_check;
+
+pub(super) struct SanityCheck;
+
+impl<'tcx> crate::MirLint<'tcx> for SanityCheck {
+    fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
+        sanity_check(tcx, body);
+    }
+}
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index d1c2c91e00f..1478b86d3c7 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -74,7 +74,7 @@ pub(crate) fn simplify_cfg(body: &mut Body<'_>) {
     body.basic_blocks_mut().raw.shrink_to_fit();
 }
 
-impl<'tcx> MirPass<'tcx> for SimplifyCfg {
+impl<'tcx> crate::MirPass<'tcx> for SimplifyCfg {
     fn name(&self) -> &'static str {
         self.name()
     }
@@ -366,7 +366,7 @@ pub enum SimplifyLocals {
     Final,
 }
 
-impl<'tcx> MirPass<'tcx> for SimplifyLocals {
+impl<'tcx> crate::MirPass<'tcx> for SimplifyLocals {
     fn name(&self) -> &'static str {
         match &self {
             SimplifyLocals::BeforeConstProp => "SimplifyLocals-before-const-prop",
diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs
index 7c8a686d007..5a014bb7346 100644
--- a/compiler/rustc_mir_transform/src/simplify_branches.rs
+++ b/compiler/rustc_mir_transform/src/simplify_branches.rs
@@ -7,7 +7,7 @@ pub enum SimplifyConstCondition {
     Final,
 }
 /// A pass that replaces a branch with a goto when its condition is known.
-impl<'tcx> MirPass<'tcx> for SimplifyConstCondition {
+impl<'tcx> crate::MirPass<'tcx> for SimplifyConstCondition {
     fn name(&self) -> &'static str {
         match self {
             SimplifyConstCondition::AfterConstProp => "SimplifyConstCondition-after-const-prop",
diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
index ac892adebec..bd30ecc59b3 100644
--- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
+++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
@@ -9,8 +9,6 @@ use rustc_middle::mir::{
 use rustc_middle::ty::{Ty, TyCtxt};
 use tracing::trace;
 
-use super::MirPass;
-
 /// Pass to convert `if` conditions on integrals into switches on the integral.
 /// For an example, it turns something like
 ///
@@ -27,7 +25,7 @@ use super::MirPass;
 /// ```
 pub struct SimplifyComparisonIntegral;
 
-impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral {
+impl<'tcx> crate::MirPass<'tcx> for SimplifyComparisonIntegral {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.mir_opt_level() > 0
     }
diff --git a/compiler/rustc_mir_transform/src/single_use_consts.rs b/compiler/rustc_mir_transform/src/single_use_consts.rs
index 35cb6872fe9..64a92872830 100644
--- a/compiler/rustc_mir_transform/src/single_use_consts.rs
+++ b/compiler/rustc_mir_transform/src/single_use_consts.rs
@@ -21,7 +21,7 @@ use rustc_middle::ty::TyCtxt;
 /// needed to do that too, including updating the debug info.
 pub struct SingleUseConsts;
 
-impl<'tcx> MirPass<'tcx> for SingleUseConsts {
+impl<'tcx> crate::MirPass<'tcx> for SingleUseConsts {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.mir_opt_level() > 0
     }
diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs
index 906e2c23f3b..3c5ccc0c99a 100644
--- a/compiler/rustc_mir_transform/src/sroa.rs
+++ b/compiler/rustc_mir_transform/src/sroa.rs
@@ -13,7 +13,7 @@ use tracing::{debug, instrument};
 
 pub struct ScalarReplacementOfAggregates;
 
-impl<'tcx> MirPass<'tcx> for ScalarReplacementOfAggregates {
+impl<'tcx> crate::MirPass<'tcx> for ScalarReplacementOfAggregates {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.mir_opt_level() >= 2
     }
diff --git a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
index 2427fbac5ee..51a322628ee 100644
--- a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
@@ -12,8 +12,6 @@ use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_target::abi::{Abi, Variants};
 use tracing::trace;
 
-use crate::MirPass;
-
 pub struct UnreachableEnumBranching;
 
 fn get_discriminant_local(terminator: &TerminatorKind<'_>) -> Option<Local> {
@@ -74,7 +72,7 @@ fn variant_discriminants<'tcx>(
     }
 }
 
-impl<'tcx> MirPass<'tcx> for UnreachableEnumBranching {
+impl<'tcx> crate::MirPass<'tcx> for UnreachableEnumBranching {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         sess.mir_opt_level() > 0
     }
diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs
index a6c3c3b189e..b8da86f1a8d 100644
--- a/compiler/rustc_mir_transform/src/unreachable_prop.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs
@@ -12,7 +12,7 @@ use rustc_target::abi::Size;
 
 pub struct UnreachablePropagation;
 
-impl MirPass<'_> for UnreachablePropagation {
+impl crate::MirPass<'_> for UnreachablePropagation {
     fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
         // Enable only under -Zmir-opt-level=2 as this can make programs less debuggable.
         sess.mir_opt_level() >= 2
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index 99e06f59dd0..69e2592e82c 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -36,7 +36,7 @@ pub struct Validator {
     pub mir_phase: MirPhase,
 }
 
-impl<'tcx> MirPass<'tcx> for Validator {
+impl<'tcx> crate::MirPass<'tcx> for Validator {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // FIXME(JakobDegen): These bodies never instantiated in codegend anyway, so it's not
         // terribly important that they pass the validator. However, I think other passes might
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index bb05eb4c256..6c9a6011144 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -304,6 +304,11 @@ where
 
         let mut candidates = vec![];
 
+        if self.solver_mode() == SolverMode::Coherence {
+            if let Ok(candidate) = self.consider_coherence_unknowable_candidate(goal) {
+                return vec![candidate];
+            }
+        }
         self.assemble_impl_candidates(goal, &mut candidates);
 
         self.assemble_builtin_impl_candidates(goal, &mut candidates);
@@ -314,11 +319,8 @@ where
 
         self.assemble_param_env_candidates(goal, &mut candidates);
 
-        match self.solver_mode() {
-            SolverMode::Normal => self.discard_impls_shadowed_by_env(goal, &mut candidates),
-            SolverMode::Coherence => {
-                self.assemble_coherence_unknowable_candidates(goal, &mut candidates)
-            }
+        if self.solver_mode() == SolverMode::Normal {
+            self.discard_impls_shadowed_by_env(goal, &mut candidates);
         }
 
         candidates
@@ -682,38 +684,34 @@ where
     /// also consider impls which may get added in a downstream or sibling crate
     /// or which an upstream impl may add in a minor release.
     ///
-    /// To do so we add an ambiguous candidate in case such an unknown impl could
-    /// apply to the current goal.
+    /// To do so we return a single ambiguous candidate in case such an unknown
+    /// impl could apply to the current goal.
     #[instrument(level = "trace", skip_all)]
-    fn assemble_coherence_unknowable_candidates<G: GoalKind<D>>(
+    fn consider_coherence_unknowable_candidate<G: GoalKind<D>>(
         &mut self,
         goal: Goal<I, G>,
-        candidates: &mut Vec<Candidate<I>>,
-    ) {
-        let cx = self.cx();
-
-        candidates.extend(self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter(
-            |ecx| {
-                let trait_ref = goal.predicate.trait_ref(cx);
-                if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? {
-                    Err(NoSolution)
-                } else {
-                    // While the trait bound itself may be unknowable, we may be able to
-                    // prove that a super trait is not implemented. For this, we recursively
-                    // prove the super trait bounds of the current goal.
-                    //
-                    // We skip the goal itself as that one would cycle.
-                    let predicate: I::Predicate = trait_ref.upcast(cx);
-                    ecx.add_goals(
-                        GoalSource::Misc,
-                        elaborate::elaborate(cx, [predicate])
-                            .skip(1)
-                            .map(|predicate| goal.with(cx, predicate)),
-                    );
-                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
-                }
-            },
-        ))
+    ) -> Result<Candidate<I>, NoSolution> {
+        self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter(|ecx| {
+            let cx = ecx.cx();
+            let trait_ref = goal.predicate.trait_ref(cx);
+            if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? {
+                Err(NoSolution)
+            } else {
+                // While the trait bound itself may be unknowable, we may be able to
+                // prove that a super trait is not implemented. For this, we recursively
+                // prove the super trait bounds of the current goal.
+                //
+                // We skip the goal itself as that one would cycle.
+                let predicate: I::Predicate = trait_ref.upcast(cx);
+                ecx.add_goals(
+                    GoalSource::Misc,
+                    elaborate::elaborate(cx, [predicate])
+                        .skip(1)
+                        .map(|predicate| goal.with(cx, predicate)),
+                );
+                ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
+            }
+        })
     }
 
     /// If there's a where-bound for the current goal, do not use any impl candidates
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index 25115c5cafd..c11562ae39e 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -19,17 +19,25 @@ use crate::errors::{
     OutsideLoopSuggestion, UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock,
 };
 
+/// The context in which a block is encountered.
 #[derive(Clone, Copy, Debug, PartialEq)]
 enum Context {
     Normal,
     Fn,
     Loop(hir::LoopSource),
     Closure(Span),
-    Coroutine { coroutine_span: Span, kind: hir::CoroutineDesugaring, source: hir::CoroutineSource },
+    Coroutine {
+        coroutine_span: Span,
+        kind: hir::CoroutineDesugaring,
+        source: hir::CoroutineSource,
+    },
     UnlabeledBlock(Span),
     UnlabeledIfBlock(Span),
     LabeledBlock,
-    Constant,
+    /// E.g. The labeled block inside `['_'; 'block: { break 'block 1 + 2; }]`.
+    AnonConst,
+    /// E.g. `const { ... }`.
+    ConstBlock,
 }
 
 #[derive(Clone)]
@@ -90,11 +98,11 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
     }
 
     fn visit_anon_const(&mut self, c: &'hir hir::AnonConst) {
-        self.with_context(Constant, |v| intravisit::walk_anon_const(v, c));
+        self.with_context(AnonConst, |v| intravisit::walk_anon_const(v, c));
     }
 
     fn visit_inline_const(&mut self, c: &'hir hir::ConstBlock) {
-        self.with_context(Constant, |v| intravisit::walk_inline_const(v, c));
+        self.with_context(ConstBlock, |v| intravisit::walk_inline_const(v, c));
     }
 
     fn visit_fn(
@@ -128,7 +136,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
                         && matches!(
                             ck_loop.cx_stack.last(),
                             Some(&Normal)
-                                | Some(&Constant)
+                                | Some(&AnonConst)
                                 | Some(&UnlabeledBlock(_))
                                 | Some(&UnlabeledIfBlock(_))
                         )
@@ -175,14 +183,18 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
             hir::ExprKind::Block(ref b, Some(_label)) => {
                 self.with_context(LabeledBlock, |v| v.visit_block(b));
             }
-            hir::ExprKind::Block(ref b, None) if matches!(self.cx_stack.last(), Some(&Fn)) => {
+            hir::ExprKind::Block(ref b, None)
+                if matches!(self.cx_stack.last(), Some(&Fn) | Some(&ConstBlock)) =>
+            {
                 self.with_context(Normal, |v| v.visit_block(b));
             }
-            hir::ExprKind::Block(ref b, None)
-                if matches!(
-                    self.cx_stack.last(),
-                    Some(&Normal) | Some(&Constant) | Some(&UnlabeledBlock(_))
-                ) =>
+            hir::ExprKind::Block(
+                ref b @ hir::Block { rules: hir::BlockCheckMode::DefaultBlock, .. },
+                None,
+            ) if matches!(
+                self.cx_stack.last(),
+                Some(&Normal) | Some(&AnonConst) | Some(&UnlabeledBlock(_))
+            ) =>
             {
                 self.with_context(UnlabeledBlock(b.span.shrink_to_lo()), |v| v.visit_block(b));
             }
@@ -353,7 +365,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
             UnlabeledIfBlock(_) if br_cx_kind == BreakContextKind::Break => {
                 self.require_break_cx(br_cx_kind, span, break_span, cx_pos - 1);
             }
-            Normal | Constant | Fn | UnlabeledBlock(_) | UnlabeledIfBlock(_) => {
+            Normal | AnonConst | Fn | UnlabeledBlock(_) | UnlabeledIfBlock(_) | ConstBlock => {
                 self.sess.dcx().emit_err(OutsideLoop {
                     spans: vec![span],
                     name: &br_cx_kind.to_string(),
@@ -365,7 +377,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
     }
 
     fn require_label_in_labeled_block(
-        &mut self,
+        &self,
         span: Span,
         label: &Destination,
         cf_type: &str,
@@ -380,7 +392,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
         false
     }
 
-    fn report_outside_loop_error(&mut self) {
+    fn report_outside_loop_error(&self) {
         for (s, block) in &self.block_breaks {
             self.sess.dcx().emit_err(OutsideLoop {
                 spans: block.spans.clone(),
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index d7885e05a2f..6c09f97bfe7 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -229,17 +229,11 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'p, 'tcx> {
                     } else {
                         let variant =
                             &adt.variant(RustcPatCtxt::variant_index_for_adt(&ctor, *adt));
-
-                        // In the cases of either a `#[non_exhaustive]` field list or a non-public
-                        // field, we skip uninhabited fields in order not to reveal the
-                        // uninhabitedness of the whole variant.
-                        let is_non_exhaustive =
-                            variant.is_field_list_non_exhaustive() && !adt.did().is_local();
                         let tys = cx.variant_sub_tys(ty, variant).map(|(field, ty)| {
                             let is_visible =
                                 adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
                             let is_uninhabited = cx.is_uninhabited(*ty);
-                            let skip = is_uninhabited && (!is_visible || is_non_exhaustive);
+                            let skip = is_uninhabited && !is_visible;
                             (ty, PrivateUninhabitedField(skip))
                         });
                         cx.dropless_arena.alloc_from_iter(tys)
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index f992ddf8417..e6b00c84254 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -2097,9 +2097,10 @@ pub struct TargetOptions {
     /// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults
     /// to "generic".
     pub cpu: StaticCow<str>,
-    /// Default target features to pass to LLVM. These features will *always* be
-    /// passed, and cannot be disabled even via `-C`. Corresponds to `llc
-    /// -mattr=$features`.
+    /// Default target features to pass to LLVM. These features overwrite
+    /// `-Ctarget-cpu` but can be overwritten with `-Ctarget-features`.
+    /// Corresponds to `llc -mattr=$features`.
+    /// Note that these are LLVM feature names, not Rust feature names!
     pub features: StaticCow<str>,
     /// Direct or use GOT indirect to reference external data symbols
     pub direct_access_external_data: Option<bool>,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 5c663e0bf4b..45e157b1080 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -5023,24 +5023,32 @@ impl<'v> Visitor<'v> for AwaitsVisitor {
     }
 }
 
+/// Suggest a new type parameter name for diagnostic purposes.
+///
+/// `name` is the preferred name you'd like to suggest if it's not in use already.
 pub trait NextTypeParamName {
     fn next_type_param_name(&self, name: Option<&str>) -> String;
 }
 
 impl NextTypeParamName for &[hir::GenericParam<'_>] {
     fn next_type_param_name(&self, name: Option<&str>) -> String {
-        // This is the list of possible parameter names that we might suggest.
+        // Type names are usually single letters in uppercase. So convert the first letter of input string to uppercase.
         let name = name.and_then(|n| n.chars().next()).map(|c| c.to_uppercase().to_string());
         let name = name.as_deref();
+
+        // This is the list of possible parameter names that we might suggest.
         let possible_names = [name.unwrap_or("T"), "T", "U", "V", "X", "Y", "Z", "A", "B", "C"];
-        let used_names = self
+
+        // Filter out used names based on `filter_fn`.
+        let used_names: Vec<Symbol> = self
             .iter()
-            .filter_map(|p| match p.name {
+            .filter_map(|param| match param.name {
                 hir::ParamName::Plain(ident) => Some(ident.name),
                 _ => None,
             })
-            .collect::<Vec<_>>();
+            .collect();
 
+        // Find a name from `possible_names` that is not in `used_names`.
         possible_names
             .iter()
             .find(|n| !used_names.contains(&Symbol::intern(n)))
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 8558520897b..8b55f84bccc 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -29,6 +29,7 @@ use crate::infer::outlives::env::OutlivesEnvironment;
 use crate::infer::InferOk;
 use crate::solve::inspect::{InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
 use crate::solve::{deeply_normalize_for_diagnostics, inspect};
+use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::select::IntercrateAmbiguityCause;
 use crate::traits::{
     util, FulfillmentErrorCode, NormalizeExt, Obligation, ObligationCause, PredicateObligation,
@@ -624,14 +625,13 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
         // at ambiguous goals, as for others the coherence unknowable candidate
         // was irrelevant.
         match goal.result() {
-            Ok(Certainty::Maybe(_)) => {}
             Ok(Certainty::Yes) | Err(NoSolution) => return,
+            Ok(Certainty::Maybe(_)) => {}
         }
 
-        let Goal { param_env, predicate } = goal.goal();
-
         // For bound predicates we simply call `infcx.enter_forall`
         // and then prove the resulting predicate as a nested goal.
+        let Goal { param_env, predicate } = goal.goal();
         let trait_ref = match predicate.kind().no_bound_vars() {
             Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr))) => tr.trait_ref,
             Some(ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)))
@@ -645,7 +645,11 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
             _ => return,
         };
 
-        // Add ambiguity causes for reservation impls.
+        if trait_ref.references_error() {
+            return;
+        }
+
+        let mut candidates = goal.candidates();
         for cand in goal.candidates() {
             if let inspect::ProbeKind::TraitCandidate {
                 source: CandidateSource::Impl(def_id),
@@ -664,78 +668,68 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> {
             }
         }
 
-        // Add ambiguity causes for unknowable goals.
-        let mut ambiguity_cause = None;
-        for cand in goal.candidates() {
-            if let inspect::ProbeKind::TraitCandidate {
-                source: CandidateSource::CoherenceUnknowable,
-                result: Ok(_),
-            } = cand.kind()
-            {
-                let lazily_normalize_ty = |mut ty: Ty<'tcx>| {
-                    if matches!(ty.kind(), ty::Alias(..)) {
-                        let ocx = ObligationCtxt::new(infcx);
-                        ty = ocx
-                            .structurally_normalize(&ObligationCause::dummy(), param_env, ty)
-                            .map_err(|_| ())?;
-                        if !ocx.select_where_possible().is_empty() {
-                            return Err(());
-                        }
-                    }
-                    Ok(ty)
-                };
+        // We also look for unknowable candidates. In case a goal is unknowable, there's
+        // always exactly 1 candidate.
+        let Some(cand) = candidates.pop() else {
+            return;
+        };
 
-                infcx.probe(|_| {
-                    match trait_ref_is_knowable(infcx, trait_ref, lazily_normalize_ty) {
-                        Err(()) => {}
-                        Ok(Ok(())) => warn!("expected an unknowable trait ref: {trait_ref:?}"),
-                        Ok(Err(conflict)) => {
-                            if !trait_ref.references_error() {
-                                // Normalize the trait ref for diagnostics, ignoring any errors if this fails.
-                                let trait_ref =
-                                    deeply_normalize_for_diagnostics(infcx, param_env, trait_ref);
-
-                                let self_ty = trait_ref.self_ty();
-                                let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty);
-                                ambiguity_cause = Some(match conflict {
-                                    Conflict::Upstream => {
-                                        IntercrateAmbiguityCause::UpstreamCrateUpdate {
-                                            trait_ref,
-                                            self_ty,
-                                        }
-                                    }
-                                    Conflict::Downstream => {
-                                        IntercrateAmbiguityCause::DownstreamCrate {
-                                            trait_ref,
-                                            self_ty,
-                                        }
-                                    }
-                                });
-                            }
-                        }
-                    }
-                })
-            } else {
-                match cand.result() {
-                    // We only add an ambiguity cause if the goal would otherwise
-                    // result in an error.
-                    //
-                    // FIXME: While this matches the behavior of the
-                    // old solver, it is not the only way in which the unknowable
-                    // candidates *weaken* coherence, they can also force otherwise
-                    // successful normalization to be ambiguous.
-                    Ok(Certainty::Maybe(_) | Certainty::Yes) => {
-                        ambiguity_cause = None;
-                        break;
-                    }
-                    Err(NoSolution) => continue,
+        let inspect::ProbeKind::TraitCandidate {
+            source: CandidateSource::CoherenceUnknowable,
+            result: Ok(_),
+        } = cand.kind()
+        else {
+            return;
+        };
+
+        let lazily_normalize_ty = |mut ty: Ty<'tcx>| {
+            if matches!(ty.kind(), ty::Alias(..)) {
+                let ocx = ObligationCtxt::new(infcx);
+                ty = ocx
+                    .structurally_normalize(&ObligationCause::dummy(), param_env, ty)
+                    .map_err(|_| ())?;
+                if !ocx.select_where_possible().is_empty() {
+                    return Err(());
                 }
             }
-        }
+            Ok(ty)
+        };
 
-        if let Some(ambiguity_cause) = ambiguity_cause {
-            self.causes.insert(ambiguity_cause);
-        }
+        infcx.probe(|_| {
+            let conflict = match trait_ref_is_knowable(infcx, trait_ref, lazily_normalize_ty) {
+                Err(()) => return,
+                Ok(Ok(())) => {
+                    warn!("expected an unknowable trait ref: {trait_ref:?}");
+                    return;
+                }
+                Ok(Err(conflict)) => conflict,
+            };
+
+            // It is only relevant that a goal is unknowable if it would have otherwise
+            // failed.
+            let non_intercrate_infcx = infcx.fork_with_intercrate(false);
+            if non_intercrate_infcx.predicate_may_hold(&Obligation::new(
+                infcx.tcx,
+                ObligationCause::dummy(),
+                param_env,
+                predicate,
+            )) {
+                return;
+            }
+
+            // Normalize the trait ref for diagnostics, ignoring any errors if this fails.
+            let trait_ref = deeply_normalize_for_diagnostics(infcx, param_env, trait_ref);
+            let self_ty = trait_ref.self_ty();
+            let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty);
+            self.causes.insert(match conflict {
+                Conflict::Upstream => {
+                    IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_ref, self_ty }
+                }
+                Conflict::Downstream => {
+                    IntercrateAmbiguityCause::DownstreamCrate { trait_ref, self_ty }
+                }
+            });
+        });
     }
 }
 
diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs
index 96c939a898b..96998d2ec9f 100644
--- a/compiler/rustc_type_ir/src/solve/mod.rs
+++ b/compiler/rustc_type_ir/src/solve/mod.rs
@@ -58,7 +58,7 @@ pub enum Reveal {
     All,
 }
 
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 pub enum SolverMode {
     /// Ordinary trait solving, using everywhere except for coherence.
     Normal,