diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index f1e712d814a10..6606be2f9f42f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -315,7 +315,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
             let mut failed = false;
 
             let elaborated_args = std::iter::zip(*args, &generics.params).map(|(arg, param)| {
-                if let Some(ty::Dynamic(obj, _, ty::DynKind::Dyn)) = arg.as_type().map(Ty::kind) {
+                if let Some(ty::Dynamic(obj, _, ty::Dyn)) = arg.as_type().map(Ty::kind) {
                     let default = tcx.object_lifetime_default(param.def_id);
 
                     let re_static = tcx.lifetimes.re_static;
@@ -339,7 +339,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
 
                     has_dyn = true;
 
-                    Ty::new_dynamic(tcx, obj, implied_region, ty::DynKind::Dyn).into()
+                    Ty::new_dynamic(tcx, obj, implied_region, ty::Dyn).into()
                 } else {
                     arg
                 }
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index 298bdc557abb4..4d44e340ae149 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -394,7 +394,7 @@ fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>)
     let level = match item.map(|i| &i.kind) {
         // These were a warning before #92959 and need to continue being that to avoid breaking
         // stable user code (#94508).
-        Some(ast::ItemKind::MacCall(_)) => Level::Warning(None),
+        Some(ast::ItemKind::MacCall(_)) => Level::Warning,
         _ => Level::Error,
     };
     let mut err = DiagnosticBuilder::<()>::new(dcx, level, msg);
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index deffb10c7590c..a912ef9e7558e 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -417,7 +417,7 @@ fn report_inline_asm(
     }
     let level = match level {
         llvm::DiagnosticLevel::Error => Level::Error,
-        llvm::DiagnosticLevel::Warning => Level::Warning(None),
+        llvm::DiagnosticLevel::Warning => Level::Warning,
         llvm::DiagnosticLevel::Note | llvm::DiagnosticLevel::Remark => Level::Note,
     };
     cgcx.diag_emitter.inline_asm_error(cookie as u32, msg, level, source);
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 6c066e61a583a..8e835039970b0 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -1847,14 +1847,9 @@ impl SharedEmitterMain {
                     dcx.emit_diagnostic(d);
                 }
                 Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => {
-                    let err_level = match level {
-                        Level::Error => Level::Error,
-                        Level::Warning(_) => Level::Warning(None),
-                        Level::Note => Level::Note,
-                        _ => bug!("Invalid inline asm diagnostic level"),
-                    };
+                    assert!(matches!(level, Level::Error | Level::Warning | Level::Note));
                     let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string();
-                    let mut err = DiagnosticBuilder::<()>::new(sess.dcx(), err_level, msg);
+                    let mut err = DiagnosticBuilder::<()>::new(sess.dcx(), level, msg);
 
                     // If the cookie is 0 then we don't have span information.
                     if cookie != 0 {
diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
index 5c0e210f1472b..97f2efa7874d1 100644
--- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
+++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
@@ -87,7 +87,7 @@ fn source_string(file: Lrc<SourceFile>, line: &Line) -> String {
 fn annotation_type_for_level(level: Level) -> AnnotationType {
     match level {
         Level::Bug | Level::DelayedBug | Level::Fatal | Level::Error => AnnotationType::Error,
-        Level::Warning(_) => AnnotationType::Warning,
+        Level::ForceWarning(_) | Level::Warning => AnnotationType::Warning,
         Level::Note | Level::OnceNote => AnnotationType::Note,
         Level::Help | Level::OnceHelp => AnnotationType::Help,
         // FIXME(#59346): Not sure how to map this level
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 701c1c02ab0ef..d8d6922a1bcda 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -152,7 +152,6 @@ pub enum DiagnosticId {
         name: String,
         /// Indicates whether this lint should show up in cargo's future breakage report.
         has_future_breakage: bool,
-        is_force_warn: bool,
     },
 }
 
@@ -248,7 +247,8 @@ impl Diagnostic {
                 true
             }
 
-            Level::Warning(_)
+            Level::ForceWarning(_)
+            | Level::Warning
             | Level::Note
             | Level::OnceNote
             | Level::Help
@@ -262,7 +262,7 @@ impl Diagnostic {
         &mut self,
         unstable_to_stable: &FxIndexMap<LintExpectationId, LintExpectationId>,
     ) {
-        if let Level::Expect(expectation_id) | Level::Warning(Some(expectation_id)) =
+        if let Level::Expect(expectation_id) | Level::ForceWarning(Some(expectation_id)) =
             &mut self.level
         {
             if expectation_id.is_stable() {
@@ -292,8 +292,11 @@ impl Diagnostic {
     }
 
     pub(crate) fn is_force_warn(&self) -> bool {
-        match self.code {
-            Some(DiagnosticId::Lint { is_force_warn, .. }) => is_force_warn,
+        match self.level {
+            Level::ForceWarning(_) => {
+                assert!(self.is_lint);
+                true
+            }
             _ => false,
         }
     }
@@ -472,7 +475,7 @@ impl Diagnostic {
     /// Add a warning attached to this diagnostic.
     #[rustc_lint_diagnostics]
     pub fn warn(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self {
-        self.sub(Level::Warning(None), msg, MultiSpan::new());
+        self.sub(Level::Warning, msg, MultiSpan::new());
         self
     }
 
@@ -484,7 +487,7 @@ impl Diagnostic {
         sp: S,
         msg: impl Into<SubdiagnosticMessage>,
     ) -> &mut Self {
-        self.sub(Level::Warning(None), msg, sp.into());
+        self.sub(Level::Warning, msg, sp.into());
         self
     }
 
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index 52fcb50e9fb96..87bf9c234564b 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -198,7 +198,7 @@ impl Emitter for JsonEmitter {
             .into_iter()
             .map(|mut diag| {
                 if diag.level == crate::Level::Allow {
-                    diag.level = crate::Level::Warning(None);
+                    diag.level = crate::Level::Warning;
                 }
                 FutureBreakageItem {
                     diagnostic: EmitTyped::Diagnostic(Diagnostic::from_errors_diagnostic(
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 1f5ad56a42a29..8fb539fc3582f 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -420,6 +420,7 @@ pub struct DiagCtxt {
 /// as well as inconsistent state observation.
 struct DiagCtxtInner {
     flags: DiagCtxtFlags,
+
     /// The number of lint errors that have been emitted.
     lint_err_count: usize,
     /// The number of errors that have been emitted, including duplicates.
@@ -427,8 +428,13 @@ struct DiagCtxtInner {
     /// This is not necessarily the count that's reported to the user once
     /// compilation ends.
     err_count: usize,
-    warn_count: usize,
     deduplicated_err_count: usize,
+    /// The warning count, used for a recap upon finishing
+    deduplicated_warn_count: usize,
+    /// Has this diagnostic context printed any diagnostics? (I.e. has
+    /// `self.emitter.emit_diagnostic()` been called?
+    has_printed: bool,
+
     emitter: Box<DynEmitter>,
     span_delayed_bugs: Vec<DelayedDiagnostic>,
     good_path_delayed_bugs: Vec<DelayedDiagnostic>,
@@ -455,9 +461,6 @@ struct DiagCtxtInner {
     /// When `.abort_if_errors()` is called, these are also emitted.
     stashed_diagnostics: FxIndexMap<(Span, StashKey), Diagnostic>,
 
-    /// The warning count, used for a recap upon finishing
-    deduplicated_warn_count: usize,
-
     future_breakage_diagnostics: Vec<Diagnostic>,
 
     /// The [`Self::unstable_expect_diagnostics`] should be empty when this struct is
@@ -513,7 +516,7 @@ fn default_track_diagnostic(diag: Diagnostic, f: &mut dyn FnMut(Diagnostic)) {
     (*f)(diag)
 }
 
-pub static TRACK_DIAGNOSTICS: AtomicRef<fn(Diagnostic, &mut dyn FnMut(Diagnostic))> =
+pub static TRACK_DIAGNOSTIC: AtomicRef<fn(Diagnostic, &mut dyn FnMut(Diagnostic))> =
     AtomicRef::new(&(default_track_diagnostic as _));
 
 #[derive(Copy, Clone, Default)]
@@ -547,8 +550,7 @@ impl Drop for DiagCtxtInner {
         // instead of "require some error happened". Sadly that isn't ideal, as
         // lints can be `#[allow]`'d, potentially leading to this triggering.
         // Also, "good path" should be replaced with a better naming.
-        let has_any_message = self.err_count > 0 || self.lint_err_count > 0 || self.warn_count > 0;
-        if !has_any_message && !self.suppressed_expected_diag && !std::thread::panicking() {
+        if !self.has_printed && !self.suppressed_expected_diag && !std::thread::panicking() {
             let bugs = std::mem::replace(&mut self.good_path_delayed_bugs, Vec::new());
             self.flush_delayed(
                 bugs,
@@ -594,9 +596,9 @@ impl DiagCtxt {
                 flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
                 lint_err_count: 0,
                 err_count: 0,
-                warn_count: 0,
                 deduplicated_err_count: 0,
                 deduplicated_warn_count: 0,
+                has_printed: false,
                 emitter,
                 span_delayed_bugs: Vec::new(),
                 good_path_delayed_bugs: Vec::new(),
@@ -647,10 +649,11 @@ impl DiagCtxt {
     /// the overall count of emitted error diagnostics.
     pub fn reset_err_count(&self) {
         let mut inner = self.inner.borrow_mut();
+        inner.lint_err_count = 0;
         inner.err_count = 0;
-        inner.warn_count = 0;
         inner.deduplicated_err_count = 0;
         inner.deduplicated_warn_count = 0;
+        inner.has_printed = false;
 
         // actually free the underlying memory (which `clear` would not do)
         inner.span_delayed_bugs = Default::default();
@@ -669,16 +672,11 @@ impl DiagCtxt {
         let key = (span.with_parent(None), key);
 
         if diag.is_error() {
-            if diag.level == Error && diag.is_lint {
+            if diag.is_lint {
                 inner.lint_err_count += 1;
             } else {
                 inner.err_count += 1;
             }
-        } else {
-            // Warnings are only automatically flushed if they're forced.
-            if diag.is_force_warn() {
-                inner.warn_count += 1;
-            }
         }
 
         // FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic
@@ -693,15 +691,11 @@ impl DiagCtxt {
         let key = (span.with_parent(None), key);
         let diag = inner.stashed_diagnostics.remove(&key)?;
         if diag.is_error() {
-            if diag.level == Error && diag.is_lint {
+            if diag.is_lint {
                 inner.lint_err_count -= 1;
             } else {
                 inner.err_count -= 1;
             }
-        } else {
-            if diag.is_force_warn() {
-                inner.warn_count -= 1;
-            }
         }
         Some(DiagnosticBuilder::new_diagnostic(self, diag))
     }
@@ -738,7 +732,7 @@ impl DiagCtxt {
     #[rustc_lint_diagnostics]
     #[track_caller]
     pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
-        DiagnosticBuilder::new(self, Warning(None), msg)
+        DiagnosticBuilder::new(self, Warning, msg)
     }
 
     /// Construct a builder at the `Allow` level with the `msg`.
@@ -1005,7 +999,7 @@ impl DiagCtxt {
             (0, 0) => return,
             (0, _) => inner
                 .emitter
-                .emit_diagnostic(&Diagnostic::new(Warning(None), DiagnosticMessage::Str(warnings))),
+                .emit_diagnostic(&Diagnostic::new(Warning, DiagnosticMessage::Str(warnings))),
             (_, 0) => {
                 inner.emit_diagnostic(Diagnostic::new(Fatal, errors));
             }
@@ -1094,7 +1088,7 @@ impl DiagCtxt {
         &'a self,
         warning: impl IntoDiagnostic<'a, ()>,
     ) -> DiagnosticBuilder<'a, ()> {
-        warning.into_diagnostic(self, Warning(None))
+        warning.into_diagnostic(self, Warning)
     }
 
     #[track_caller]
@@ -1241,21 +1235,17 @@ impl DiagCtxtInner {
         for diag in diags {
             // Decrement the count tracking the stash; emitting will increment it.
             if diag.is_error() {
-                if diag.level == Error && diag.is_lint {
+                if diag.is_lint {
                     self.lint_err_count -= 1;
                 } else {
                     self.err_count -= 1;
                 }
             } else {
-                if diag.is_force_warn() {
-                    self.warn_count -= 1;
-                } else {
-                    // Unless they're forced, don't flush stashed warnings when
-                    // there are errors, to avoid causing warning overload. The
-                    // stash would've been stolen already if it were important.
-                    if has_errors {
-                        continue;
-                    }
+                // Unless they're forced, don't flush stashed warnings when
+                // there are errors, to avoid causing warning overload. The
+                // stash would've been stolen already if it were important.
+                if !diag.is_force_warn() && has_errors {
+                    continue;
                 }
             }
             let reported_this = self.emit_diagnostic(diag);
@@ -1304,23 +1294,20 @@ impl DiagCtxtInner {
             self.fulfilled_expectations.insert(expectation_id.normalize());
         }
 
-        if matches!(diagnostic.level, Warning(_))
-            && !self.flags.can_emit_warnings
-            && !diagnostic.is_force_warn()
-        {
+        if diagnostic.level == Warning && !self.flags.can_emit_warnings {
             if diagnostic.has_future_breakage() {
-                (*TRACK_DIAGNOSTICS)(diagnostic, &mut |_| {});
+                (*TRACK_DIAGNOSTIC)(diagnostic, &mut |_| {});
             }
             return None;
         }
 
         if matches!(diagnostic.level, Expect(_) | Allow) {
-            (*TRACK_DIAGNOSTICS)(diagnostic, &mut |_| {});
+            (*TRACK_DIAGNOSTIC)(diagnostic, &mut |_| {});
             return None;
         }
 
         let mut guaranteed = None;
-        (*TRACK_DIAGNOSTICS)(diagnostic, &mut |mut diagnostic| {
+        (*TRACK_DIAGNOSTIC)(diagnostic, &mut |mut diagnostic| {
             if let Some(ref code) = diagnostic.code {
                 self.emitted_diagnostic_codes.insert(code.clone());
             }
@@ -1359,12 +1346,13 @@ impl DiagCtxtInner {
                 self.emitter.emit_diagnostic(&diagnostic);
                 if diagnostic.is_error() {
                     self.deduplicated_err_count += 1;
-                } else if let Warning(_) = diagnostic.level {
+                } else if matches!(diagnostic.level, ForceWarning(_) | Warning) {
                     self.deduplicated_warn_count += 1;
                 }
+                self.has_printed = true;
             }
             if diagnostic.is_error() {
-                if diagnostic.level == Error && diagnostic.is_lint {
+                if diagnostic.is_lint {
                     self.bump_lint_err_count();
                 } else {
                     self.bump_err_count();
@@ -1374,8 +1362,6 @@ impl DiagCtxtInner {
                 {
                     guaranteed = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
                 }
-            } else {
-                self.bump_warn_count();
             }
         });
 
@@ -1471,10 +1457,6 @@ impl DiagCtxtInner {
         self.panic_if_treat_err_as_bug();
     }
 
-    fn bump_warn_count(&mut self) {
-        self.warn_count += 1;
-    }
-
     fn panic_if_treat_err_as_bug(&self) {
         if self.treat_err_as_bug() {
             match (
@@ -1562,14 +1544,17 @@ pub enum Level {
     /// Its `EmissionGuarantee` is `ErrorGuaranteed`.
     Error,
 
-    /// A warning about the code being compiled. Does not prevent compilation from finishing.
+    /// A `force-warn` lint warning about the code being compiled. Does not prevent compilation
+    /// from finishing.
     ///
-    /// This [`LintExpectationId`] is used for expected lint diagnostics, which should
-    /// also emit a warning due to the `force-warn` flag. In all other cases this should
-    /// be `None`.
+    /// The [`LintExpectationId`] is used for expected lint diagnostics. In all other cases this
+    /// should be `None`.
+    ForceWarning(Option<LintExpectationId>),
+
+    /// A warning about the code being compiled. Does not prevent compilation from finishing.
     ///
     /// Its `EmissionGuarantee` is `()`.
-    Warning(Option<LintExpectationId>),
+    Warning,
 
     /// A message giving additional context. Rare, because notes are more commonly attached to other
     /// diagnostics such as errors.
@@ -1622,7 +1607,7 @@ impl Level {
             Bug | DelayedBug | Fatal | Error => {
                 spec.set_fg(Some(Color::Red)).set_intense(true);
             }
-            Warning(_) => {
+            ForceWarning(_) | Warning => {
                 spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
             }
             Note | OnceNote => {
@@ -1641,7 +1626,7 @@ impl Level {
         match self {
             Bug | DelayedBug => "error: internal compiler error",
             Fatal | Error => "error",
-            Warning(_) => "warning",
+            ForceWarning(_) | Warning => "warning",
             Note | OnceNote => "note",
             Help | OnceHelp => "help",
             FailureNote => "failure-note",
@@ -1655,7 +1640,7 @@ impl Level {
 
     pub fn get_expectation_id(&self) -> Option<LintExpectationId> {
         match self {
-            Expect(id) | Warning(Some(id)) => Some(*id),
+            Expect(id) | ForceWarning(Some(id)) => Some(*id),
             _ => None,
         }
     }
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index 0053f5503186b..6392894fea2aa 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -380,7 +380,7 @@ impl ToInternal<rustc_errors::Level> for Level {
     fn to_internal(self) -> rustc_errors::Level {
         match self {
             Level::Error => rustc_errors::Level::Error,
-            Level::Warning => rustc_errors::Level::Warning(None),
+            Level::Warning => rustc_errors::Level::Warning,
             Level::Note => rustc_errors::Level::Note,
             Level::Help => rustc_errors::Level::Help,
             _ => unreachable!("unknown proc_macro::Level variant: {:?}", self),
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 082658a3a3b06..58ac9668da5e9 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2405,6 +2405,39 @@ impl<'hir> Ty<'hir> {
         my_visitor.visit_ty(self);
         my_visitor.0
     }
+
+    /// Whether `ty` is a type with `_` placeholders that can be inferred. Used in diagnostics only to
+    /// use inference to provide suggestions for the appropriate type if possible.
+    pub fn is_suggestable_infer_ty(&self) -> bool {
+        fn are_suggestable_generic_args(generic_args: &[GenericArg<'_>]) -> bool {
+            generic_args.iter().any(|arg| match arg {
+                GenericArg::Type(ty) => ty.is_suggestable_infer_ty(),
+                GenericArg::Infer(_) => true,
+                _ => false,
+            })
+        }
+        debug!(?self);
+        match &self.kind {
+            TyKind::Infer => true,
+            TyKind::Slice(ty) => ty.is_suggestable_infer_ty(),
+            TyKind::Array(ty, length) => {
+                ty.is_suggestable_infer_ty() || matches!(length, ArrayLen::Infer(_, _))
+            }
+            TyKind::Tup(tys) => tys.iter().any(Self::is_suggestable_infer_ty),
+            TyKind::Ptr(mut_ty) | TyKind::Ref(_, mut_ty) => mut_ty.ty.is_suggestable_infer_ty(),
+            TyKind::OpaqueDef(_, generic_args, _) => are_suggestable_generic_args(generic_args),
+            TyKind::Path(QPath::TypeRelative(ty, segment)) => {
+                ty.is_suggestable_infer_ty() || are_suggestable_generic_args(segment.args().args)
+            }
+            TyKind::Path(QPath::Resolved(ty_opt, Path { segments, .. })) => {
+                ty_opt.is_some_and(Self::is_suggestable_infer_ty)
+                    || segments
+                        .iter()
+                        .any(|segment| are_suggestable_generic_args(segment.args().args))
+            }
+            _ => false,
+        }
+    }
 }
 
 /// Not represented directly in the AST; referred to by name through a `ty_path`.
@@ -2735,7 +2768,7 @@ pub enum FnRetTy<'hir> {
     Return(&'hir Ty<'hir>),
 }
 
-impl FnRetTy<'_> {
+impl<'hir> FnRetTy<'hir> {
     #[inline]
     pub fn span(&self) -> Span {
         match *self {
@@ -2743,6 +2776,15 @@ impl FnRetTy<'_> {
             Self::Return(ref ty) => ty.span,
         }
     }
+
+    pub fn get_infer_ret_ty(&self) -> Option<&'hir Ty<'hir>> {
+        if let Self::Return(ty) = self {
+            if ty.is_suggestable_infer_ty() {
+                return Some(*ty);
+            }
+        }
+        None
+    }
 }
 
 /// Represents `for<...>` binder before a closure
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 0a13949a68821..c9f89a0c3ef32 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -642,7 +642,7 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
             tcx.ensure().generics_of(def_id);
             tcx.ensure().type_of(def_id);
             tcx.ensure().predicates_of(def_id);
-            if !is_suggestable_infer_ty(ty) {
+            if !ty.is_suggestable_infer_ty() {
                 let mut visitor = HirPlaceholderCollector::default();
                 visitor.visit_item(it);
                 placeholder_type_error(tcx, None, visitor.0, false, None, it.kind.descr());
@@ -674,7 +674,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
         hir::TraitItemKind::Const(ty, body_id) => {
             tcx.ensure().type_of(def_id);
             if !tcx.dcx().has_stashed_diagnostic(ty.span, StashKey::ItemNoType)
-                && !(is_suggestable_infer_ty(ty) && body_id.is_some())
+                && !(ty.is_suggestable_infer_ty() && body_id.is_some())
             {
                 // Account for `const C: _;`.
                 let mut visitor = HirPlaceholderCollector::default();
@@ -726,7 +726,7 @@ fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
         }
         hir::ImplItemKind::Const(ty, _) => {
             // Account for `const T: _ = ..;`
-            if !is_suggestable_infer_ty(ty) {
+            if !ty.is_suggestable_infer_ty() {
                 let mut visitor = HirPlaceholderCollector::default();
                 visitor.visit_impl_item(impl_item);
                 placeholder_type_error(tcx, None, visitor.0, false, None, "associated constant");
@@ -1054,48 +1054,6 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
     }
 }
 
-fn are_suggestable_generic_args(generic_args: &[hir::GenericArg<'_>]) -> bool {
-    generic_args.iter().any(|arg| match arg {
-        hir::GenericArg::Type(ty) => is_suggestable_infer_ty(ty),
-        hir::GenericArg::Infer(_) => true,
-        _ => false,
-    })
-}
-
-/// Whether `ty` is a type with `_` placeholders that can be inferred. Used in diagnostics only to
-/// use inference to provide suggestions for the appropriate type if possible.
-fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool {
-    debug!(?ty);
-    use hir::TyKind::*;
-    match &ty.kind {
-        Infer => true,
-        Slice(ty) => is_suggestable_infer_ty(ty),
-        Array(ty, length) => {
-            is_suggestable_infer_ty(ty) || matches!(length, hir::ArrayLen::Infer(_, _))
-        }
-        Tup(tys) => tys.iter().any(is_suggestable_infer_ty),
-        Ptr(mut_ty) | Ref(_, mut_ty) => is_suggestable_infer_ty(mut_ty.ty),
-        OpaqueDef(_, generic_args, _) => are_suggestable_generic_args(generic_args),
-        Path(hir::QPath::TypeRelative(ty, segment)) => {
-            is_suggestable_infer_ty(ty) || are_suggestable_generic_args(segment.args().args)
-        }
-        Path(hir::QPath::Resolved(ty_opt, hir::Path { segments, .. })) => {
-            ty_opt.is_some_and(is_suggestable_infer_ty)
-                || segments.iter().any(|segment| are_suggestable_generic_args(segment.args().args))
-        }
-        _ => false,
-    }
-}
-
-pub fn get_infer_ret_ty<'hir>(output: &'hir hir::FnRetTy<'hir>) -> Option<&'hir hir::Ty<'hir>> {
-    if let hir::FnRetTy::Return(ty) = output {
-        if is_suggestable_infer_ty(ty) {
-            return Some(*ty);
-        }
-    }
-    None
-}
-
 #[instrument(level = "debug", skip(tcx))]
 fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<'_>> {
     use rustc_hir::Node::*;
@@ -1188,7 +1146,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
 ) -> ty::PolyFnSig<'tcx> {
     let hir_id = tcx.local_def_id_to_hir_id(def_id);
 
-    match get_infer_ret_ty(&sig.decl.output) {
+    match sig.decl.output.get_infer_ret_ty() {
         Some(ty) => {
             let fn_sig = tcx.typeck(def_id).liberated_fn_sigs()[hir_id];
             // Typeck doesn't expect erased regions to be returned from `type_of`.
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 55720e6d2aa4f..3ceea3dc7ae3f 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -9,8 +9,8 @@ use rustc_middle::ty::{self, ImplTraitInTraitData, IsSuggestable, Ty, TyCtxt, Ty
 use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
 
+use super::bad_placeholder;
 use super::ItemCtxt;
-use super::{bad_placeholder, is_suggestable_infer_ty};
 pub use opaque::test_opaque_hidden_types;
 
 mod opaque;
@@ -368,7 +368,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
             }
             TraitItemKind::Const(ty, body_id) => body_id
                 .and_then(|body_id| {
-                    is_suggestable_infer_ty(ty).then(|| {
+                    ty.is_suggestable_infer_ty().then(|| {
                         infer_placeholder_type(
                             tcx,
                             def_id,
@@ -392,7 +392,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
                 Ty::new_fn_def(tcx, def_id.to_def_id(), args)
             }
             ImplItemKind::Const(ty, body_id) => {
-                if is_suggestable_infer_ty(ty) {
+                if ty.is_suggestable_infer_ty() {
                     infer_placeholder_type(
                         tcx,
                         def_id,
@@ -416,7 +416,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
 
         Node::Item(item) => match item.kind {
             ItemKind::Static(ty, .., body_id) => {
-                if is_suggestable_infer_ty(ty) {
+                if ty.is_suggestable_infer_ty() {
                     infer_placeholder_type(
                         tcx,
                         def_id,
@@ -430,7 +430,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
                 }
             }
             ItemKind::Const(ty, _, body_id) => {
-                if is_suggestable_infer_ty(ty) {
+                if ty.is_suggestable_infer_ty() {
                     infer_placeholder_type(tcx, def_id, body_id, ty.span, item.ident, "constant")
                 } else {
                     icx.to_ty(ty)
@@ -603,6 +603,8 @@ fn infer_placeholder_type<'a>(
             }
 
             err.emit();
+            // diagnostic stashing loses the information of whether something is a hard error.
+            Ty::new_error_with_message(tcx, span, "ItemNoType is a hard error")
         }
         None => {
             let mut diag = bad_placeholder(tcx, vec![span], kind);
@@ -623,15 +625,9 @@ fn infer_placeholder_type<'a>(
                 }
             }
 
-            diag.emit();
+            Ty::new_error(tcx, diag.emit())
         }
     }
-
-    // Typeck doesn't expect erased regions to be returned from `type_of`.
-    tcx.fold_regions(ty, |r, _| match *r {
-        ty::ReErased => tcx.lifetimes.re_static,
-        _ => r,
-    })
 }
 
 fn check_feature_inherent_assoc_ty(tcx: TyCtxt<'_>, span: Span) {
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
index da7279967dac1..1f7ca48234a24 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
@@ -134,6 +134,21 @@ impl TaitConstraintLocator<'_> {
             debug!("no constraint: no typeck results");
             return;
         }
+
+        if let Some(hir_sig) = self.tcx.hir_node_by_def_id(item_def_id).fn_decl() {
+            if hir_sig.output.get_infer_ret_ty().is_some() {
+                let guar = self.tcx.dcx().span_delayed_bug(
+                    hir_sig.output.span(),
+                    "inferring return types and opaque types do not mix well",
+                );
+                self.found = Some(ty::OpaqueHiddenType {
+                    span: DUMMY_SP,
+                    ty: Ty::new_error(self.tcx, guar),
+                });
+                return;
+            }
+        }
+
         // Calling `mir_borrowck` can lead to cycle errors through
         // const-checking, avoid calling it if we don't have to.
         // ```rust
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 6dd4c8654f234..36dd06d944c4e 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -181,7 +181,7 @@ fn typeck_with_fallback<'tcx>(
     let mut fcx = FnCtxt::new(&inh, param_env, def_id);
 
     if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
-        let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() {
+        let fn_sig = if decl.output.get_infer_ret_ty().is_some() {
             fcx.astconv().ty_of_fn(id, header.unsafety, header.abi, decl, None, None)
         } else {
             tcx.fn_sig(def_id).instantiate_identity()
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index b81cc6edaf2f5..875e94fcd9f16 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -2348,11 +2348,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             GenericKind::Param(ref p) => format!("the parameter type `{p}`"),
             GenericKind::Placeholder(ref p) => format!("the placeholder type `{p:?}`"),
             GenericKind::Alias(ref p) => match p.kind(self.tcx) {
-                ty::AliasKind::Projection | ty::AliasKind::Inherent => {
+                ty::Projection | ty::Inherent => {
                     format!("the associated type `{p}`")
                 }
-                ty::AliasKind::Weak => format!("the type alias `{p}`"),
-                ty::AliasKind::Opaque => format!("the opaque type `{p}`"),
+                ty::Weak => format!("the type alias `{p}`"),
+                ty::Opaque => format!("the opaque type `{p}`"),
             },
         };
 
diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs
index 6634b192811d6..4b254fc7df518 100644
--- a/compiler/rustc_infer/src/infer/relate/combine.rs
+++ b/compiler/rustc_infer/src/infer/relate/combine.rs
@@ -510,7 +510,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
                 ));
             } else {
                 match a_ty.kind() {
-                    &ty::Alias(ty::AliasKind::Projection, data) => {
+                    &ty::Alias(ty::Projection, data) => {
                         // FIXME: This does not handle subtyping correctly, we could
                         // instead create a new inference variable for `a_ty`, emitting
                         // `Projection(a_ty, a_infer)` and `a_infer <: b_ty`.
@@ -522,10 +522,9 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
                         ))
                     }
                     // The old solver only accepts projection predicates for associated types.
-                    ty::Alias(
-                        ty::AliasKind::Inherent | ty::AliasKind::Weak | ty::AliasKind::Opaque,
-                        _,
-                    ) => return Err(TypeError::CyclicTy(a_ty)),
+                    ty::Alias(ty::Inherent | ty::Weak | ty::Opaque, _) => {
+                        return Err(TypeError::CyclicTy(a_ty));
+                    }
                     _ => bug!("generalizated `{a_ty:?} to infer, not an alias"),
                 }
             }
diff --git a/compiler/rustc_interface/src/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs
index 7458be2c86da7..8c7e49b51f9b2 100644
--- a/compiler/rustc_interface/src/callbacks.rs
+++ b/compiler/rustc_interface/src/callbacks.rs
@@ -9,7 +9,7 @@
 //! The functions in this file should fall back to the default set in their
 //! origin crate when the `TyCtxt` is not present in TLS.
 
-use rustc_errors::{Diagnostic, TRACK_DIAGNOSTICS};
+use rustc_errors::{Diagnostic, TRACK_DIAGNOSTIC};
 use rustc_middle::dep_graph::{DepNodeExt, TaskDepsRef};
 use rustc_middle::ty::tls;
 use rustc_query_system::dep_graph::dep_node::default_dep_kind_debug;
@@ -103,5 +103,5 @@ pub fn setup_callbacks() {
         .swap(&(dep_kind_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
     rustc_query_system::dep_graph::dep_node::DEP_NODE_DEBUG
         .swap(&(dep_node_debug as fn(_, &mut fmt::Formatter<'_>) -> _));
-    TRACK_DIAGNOSTICS.swap(&(track_diagnostic as _));
+    TRACK_DIAGNOSTIC.swap(&(track_diagnostic as _));
 }
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 6dade43a18357..a86fe2db2b2d5 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -29,7 +29,6 @@ use rustc_span::{Span, Symbol};
 use rustc_target::abi::{Abi, Size, WrappingRange};
 use rustc_target::abi::{Integer, TagEncoding, Variants};
 use rustc_target::spec::abi::Abi as SpecAbi;
-use rustc_type_ir::DynKind;
 
 use std::iter;
 use std::ops::ControlFlow;
@@ -675,7 +674,7 @@ fn lint_wide_pointer<'tcx>(
         }
         match ty.kind() {
             ty::RawPtr(TypeAndMut { mutbl: _, ty }) => (!ty.is_sized(cx.tcx, cx.param_env))
-                .then(|| (refs, matches!(ty.kind(), ty::Dynamic(_, _, DynKind::Dyn)))),
+                .then(|| (refs, matches!(ty.kind(), ty::Dynamic(_, _, ty::Dyn)))),
             _ => None,
         }
     };
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index cf3f526400d46..76eb6bfaef721 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -787,7 +787,9 @@ LLVMRustOptimize(
     for (auto PluginPath: Plugins) {
       auto Plugin = PassPlugin::Load(PluginPath.str());
       if (!Plugin) {
-        LLVMRustSetLastError(("Failed to load pass plugin" + PluginPath.str()).c_str());
+        auto Err = Plugin.takeError();
+        auto ErrMsg = llvm::toString(std::move(Err));
+        LLVMRustSetLastError(ErrMsg.c_str());
         return LLVMRustResult::Failure;
       }
       Plugin->registerPassBuilderCallbacks(PB);
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 212e831e10614..c5e4dfaf19ee3 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -312,8 +312,9 @@ pub fn struct_lint_level(
                 // create a `DiagnosticBuilder` and continue as we would for warnings.
                 rustc_errors::Level::Expect(expect_id)
             }
-            Level::ForceWarn(Some(expect_id)) => rustc_errors::Level::Warning(Some(expect_id)),
-            Level::Warn | Level::ForceWarn(None) => rustc_errors::Level::Warning(None),
+            Level::ForceWarn(Some(expect_id)) => rustc_errors::Level::ForceWarning(Some(expect_id)),
+            Level::ForceWarn(None) => rustc_errors::Level::ForceWarning(None),
+            Level::Warn => rustc_errors::Level::Warning,
             Level::Deny | Level::Forbid => rustc_errors::Level::Error,
         };
         let mut err = DiagnosticBuilder::new(sess.dcx(), err_level, "");
@@ -350,22 +351,19 @@ pub fn struct_lint_level(
         // suppressed the lint due to macros.
         err.primary_message(msg);
 
+        let name = lint.name_lower();
+        err.code(DiagnosticId::Lint { name, has_future_breakage });
+
         // Lint diagnostics that are covered by the expect level will not be emitted outside
         // the compiler. It is therefore not necessary to add any information for the user.
         // This will therefore directly call the decorate function which will in turn emit
         // the `Diagnostic`.
         if let Level::Expect(_) = level {
-            let name = lint.name_lower();
-            err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn: false });
             decorate(&mut err);
             err.emit();
             return;
         }
 
-        let name = lint.name_lower();
-        let is_force_warn = matches!(level, Level::ForceWarn(_));
-        err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn });
-
         if let Some(future_incompatible) = future_incompatible {
             let explanation = match future_incompatible.reason {
                 FutureIncompatibilityReason::FutureReleaseErrorDontReportInDeps
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 38bf39bff908d..8cf5fc8013f1d 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1225,7 +1225,7 @@ impl<'tcx> AliasTy<'tcx> {
 
     /// Whether this alias type is an opaque.
     pub fn is_opaque(self, tcx: TyCtxt<'tcx>) -> bool {
-        matches!(self.opt_kind(tcx), Some(ty::AliasKind::Opaque))
+        matches!(self.opt_kind(tcx), Some(ty::Opaque))
     }
 
     /// FIXME: rename `AliasTy` to `AliasTerm` and always handle
@@ -2745,7 +2745,7 @@ impl<'tcx> Ty<'tcx> {
             // Extern types have metadata = ().
             | ty::Foreign(..)
             // `dyn*` has no metadata
-            | ty::Dynamic(_, _, DynKind::DynStar)
+            | ty::Dynamic(_, _, ty::DynStar)
             // If returned by `struct_tail_without_normalization` this is a unit struct
             // without any fields, or not a struct, and therefore is Sized.
             | ty::Adt(..)
@@ -2754,7 +2754,7 @@ impl<'tcx> Ty<'tcx> {
             | ty::Tuple(..) => (tcx.types.unit, false),
 
             ty::Str | ty::Slice(_) => (tcx.types.usize, false),
-            ty::Dynamic(_, _, DynKind::Dyn) => {
+            ty::Dynamic(_, _, ty::Dyn) => {
                 let dyn_metadata = tcx.require_lang_item(LangItem::DynMetadata, None);
                 (tcx.type_of(dyn_metadata).instantiate(tcx, &[tail.into()]), false)
             },
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 619e7d392681f..f6c5e4a5cd6e2 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -432,7 +432,13 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
         }
 
         let scrut_ty = scrut.ty;
-        let report = analyze_match(&cx, &tarms, scrut_ty);
+        let report = match analyze_match(&cx, &tarms, scrut_ty) {
+            Ok(report) => report,
+            Err(err) => {
+                self.error = Err(err);
+                return;
+            }
+        };
 
         match source {
             // Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }`
@@ -546,7 +552,7 @@ impl<'p, 'tcx> MatchVisitor<'p, 'tcx> {
         let cx = self.new_cx(refutability, None, scrut, pat.span);
         let pat = self.lower_pattern(&cx, pat)?;
         let arms = [MatchArm { pat, arm_data: self.lint_level, has_guard: false }];
-        let report = analyze_match(&cx, &arms, pat.ty().inner());
+        let report = analyze_match(&cx, &arms, pat.ty().inner())?;
         Ok((cx, report))
     }
 
diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs
index 8ea8dd61ab4be..b52643adcc959 100644
--- a/compiler/rustc_pattern_analysis/src/lib.rs
+++ b/compiler/rustc_pattern_analysis/src/lib.rs
@@ -24,6 +24,8 @@ use std::fmt;
 use rustc_index::Idx;
 #[cfg(feature = "rustc")]
 use rustc_middle::ty::Ty;
+#[cfg(feature = "rustc")]
+use rustc_span::ErrorGuaranteed;
 
 use crate::constructor::{Constructor, ConstructorSet};
 #[cfg(feature = "rustc")]
@@ -52,6 +54,8 @@ impl<'a, T: ?Sized> Captures<'a> for T {}
 pub trait TypeCx: Sized + fmt::Debug {
     /// The type of a pattern.
     type Ty: Copy + Clone + fmt::Debug; // FIXME: remove Copy
+    /// Errors that can abort analysis.
+    type Error: fmt::Debug;
     /// The index of an enum variant.
     type VariantIdx: Clone + Idx;
     /// A string literal
@@ -73,7 +77,7 @@ pub trait TypeCx: Sized + fmt::Debug {
     /// The set of all the constructors for `ty`.
     ///
     /// This must follow the invariants of `ConstructorSet`
-    fn ctors_for_ty(&self, ty: Self::Ty) -> ConstructorSet<Self>;
+    fn ctors_for_ty(&self, ty: Self::Ty) -> Result<ConstructorSet<Self>, Self::Error>;
 
     /// Best-effort `Debug` implementation.
     fn debug_pat(f: &mut fmt::Formatter<'_>, pat: &DeconstructedPat<'_, Self>) -> fmt::Result;
@@ -109,25 +113,25 @@ pub fn analyze_match<'p, 'tcx>(
     tycx: &RustcMatchCheckCtxt<'p, 'tcx>,
     arms: &[rustc::MatchArm<'p, 'tcx>],
     scrut_ty: Ty<'tcx>,
-) -> rustc::UsefulnessReport<'p, 'tcx> {
+) -> Result<rustc::UsefulnessReport<'p, 'tcx>, ErrorGuaranteed> {
     // Arena to store the extra wildcards we construct during analysis.
     let wildcard_arena = tycx.pattern_arena;
     let scrut_ty = tycx.reveal_opaque_ty(scrut_ty);
     let scrut_validity = ValidityConstraint::from_bool(tycx.known_valid_scrutinee);
     let cx = MatchCtxt { tycx, wildcard_arena };
 
-    let report = compute_match_usefulness(cx, arms, scrut_ty, scrut_validity);
+    let report = compute_match_usefulness(cx, arms, scrut_ty, scrut_validity)?;
 
     let pat_column = PatternColumn::new(arms);
 
     // Lint on ranges that overlap on their endpoints, which is likely a mistake.
-    lint_overlapping_range_endpoints(cx, &pat_column);
+    lint_overlapping_range_endpoints(cx, &pat_column)?;
 
     // Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting
     // `if let`s. Only run if the match is exhaustive otherwise the error is redundant.
     if tycx.refutable && report.non_exhaustiveness_witnesses.is_empty() {
-        lint_nonexhaustive_missing_variants(cx, arms, &pat_column, scrut_ty)
+        lint_nonexhaustive_missing_variants(cx, arms, &pat_column, scrut_ty)?;
     }
 
-    report
+    Ok(report)
 }
diff --git a/compiler/rustc_pattern_analysis/src/lints.rs b/compiler/rustc_pattern_analysis/src/lints.rs
index f1237ecf83c68..08a1a6bcbc4be 100644
--- a/compiler/rustc_pattern_analysis/src/lints.rs
+++ b/compiler/rustc_pattern_analysis/src/lints.rs
@@ -4,7 +4,7 @@ use rustc_data_structures::captures::Captures;
 use rustc_middle::ty;
 use rustc_session::lint;
 use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
-use rustc_span::Span;
+use rustc_span::{ErrorGuaranteed, Span};
 
 use crate::constructor::{IntRange, MaybeInfiniteInt};
 use crate::errors::{
@@ -52,9 +52,13 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> {
     }
 
     /// Do constructor splitting on the constructors of the column.
-    fn analyze_ctors(&self, pcx: &PlaceCtxt<'_, 'p, 'tcx>) -> SplitConstructorSet<'p, 'tcx> {
+    fn analyze_ctors(
+        &self,
+        pcx: &PlaceCtxt<'_, 'p, 'tcx>,
+    ) -> Result<SplitConstructorSet<'p, 'tcx>, ErrorGuaranteed> {
         let column_ctors = self.patterns.iter().map(|p| p.ctor());
-        pcx.ctors_for_ty().split(pcx, column_ctors)
+        let ctors_for_ty = &pcx.ctors_for_ty()?;
+        Ok(ctors_for_ty.split(pcx, column_ctors))
     }
 
     fn iter(&self) -> impl Iterator<Item = &'p DeconstructedPat<'p, 'tcx>> + Captures<'_> {
@@ -110,18 +114,18 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> {
 fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
     cx: MatchCtxt<'a, 'p, 'tcx>,
     column: &PatternColumn<'p, 'tcx>,
-) -> Vec<WitnessPat<'p, 'tcx>> {
+) -> Result<Vec<WitnessPat<'p, 'tcx>>, ErrorGuaranteed> {
     let Some(ty) = column.head_ty() else {
-        return Vec::new();
+        return Ok(Vec::new());
     };
     let pcx = &PlaceCtxt::new_dummy(cx, ty);
 
-    let set = column.analyze_ctors(pcx);
+    let set = column.analyze_ctors(pcx)?;
     if set.present.is_empty() {
         // We can't consistently handle the case where no constructors are present (since this would
         // require digging deep through any type in case there's a non_exhaustive enum somewhere),
         // so for consistency we refuse to handle the top-level case, where we could handle it.
-        return vec![];
+        return Ok(Vec::new());
     }
 
     let mut witnesses = Vec::new();
@@ -141,7 +145,7 @@ fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
         let wild_pat = WitnessPat::wild_from_ctor(pcx, ctor);
         for (i, col_i) in specialized_columns.iter().enumerate() {
             // Compute witnesses for each column.
-            let wits_for_col_i = collect_nonexhaustive_missing_variants(cx, col_i);
+            let wits_for_col_i = collect_nonexhaustive_missing_variants(cx, col_i)?;
             // For each witness, we build a new pattern in the shape of `ctor(_, _, wit, _, _)`,
             // adding enough wildcards to match `arity`.
             for wit in wits_for_col_i {
@@ -151,7 +155,7 @@ fn collect_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
             }
         }
     }
-    witnesses
+    Ok(witnesses)
 }
 
 pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
@@ -159,13 +163,13 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
     arms: &[MatchArm<'p, 'tcx>],
     pat_column: &PatternColumn<'p, 'tcx>,
     scrut_ty: RevealedTy<'tcx>,
-) {
+) -> Result<(), ErrorGuaranteed> {
     let rcx: &RustcMatchCheckCtxt<'_, '_> = cx.tycx;
     if !matches!(
         rcx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, rcx.match_lint_level).0,
         rustc_session::lint::Level::Allow
     ) {
-        let witnesses = collect_nonexhaustive_missing_variants(cx, pat_column);
+        let witnesses = collect_nonexhaustive_missing_variants(cx, pat_column)?;
         if !witnesses.is_empty() {
             // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
             // is not exhaustive enough.
@@ -204,6 +208,7 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
             }
         }
     }
+    Ok(())
 }
 
 /// Traverse the patterns to warn the user about ranges that overlap on their endpoints.
@@ -211,14 +216,14 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
 pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
     cx: MatchCtxt<'a, 'p, 'tcx>,
     column: &PatternColumn<'p, 'tcx>,
-) {
+) -> Result<(), ErrorGuaranteed> {
     let Some(ty) = column.head_ty() else {
-        return;
+        return Ok(());
     };
     let pcx = &PlaceCtxt::new_dummy(cx, ty);
     let rcx: &RustcMatchCheckCtxt<'_, '_> = cx.tycx;
 
-    let set = column.analyze_ctors(pcx);
+    let set = column.analyze_ctors(pcx)?;
 
     if matches!(ty.kind(), ty::Char | ty::Int(_) | ty::Uint(_)) {
         let emit_lint = |overlap: &IntRange, this_span: Span, overlapped_spans: &[Span]| {
@@ -275,8 +280,9 @@ pub(crate) fn lint_overlapping_range_endpoints<'a, 'p, 'tcx>(
         // Recurse into the fields.
         for ctor in set.present {
             for col in column.specialize(pcx, &ctor) {
-                lint_overlapping_range_endpoints(cx, &col);
+                lint_overlapping_range_endpoints(cx, &col)?;
             }
         }
     }
+    Ok(())
 }
diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs
index b6f67b7c56fc2..a8d1bece61367 100644
--- a/compiler/rustc_pattern_analysis/src/rustc.rs
+++ b/compiler/rustc_pattern_analysis/src/rustc.rs
@@ -12,7 +12,9 @@ use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::{self, Const};
 use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange, PatRangeBoundary};
 use rustc_middle::ty::layout::IntegerExt;
+use rustc_middle::ty::TypeVisitableExt;
 use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, VariantDef};
+use rustc_span::ErrorGuaranteed;
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{FieldIdx, Integer, VariantIdx, FIRST_VARIANT};
 use smallvec::SmallVec;
@@ -302,7 +304,10 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
     ///
     /// See [`crate::constructor`] for considerations of emptiness.
     #[instrument(level = "debug", skip(self), ret)]
-    pub fn ctors_for_ty(&self, ty: RevealedTy<'tcx>) -> ConstructorSet<'p, 'tcx> {
+    pub fn ctors_for_ty(
+        &self,
+        ty: RevealedTy<'tcx>,
+    ) -> Result<ConstructorSet<'p, 'tcx>, ErrorGuaranteed> {
         let cx = self;
         let make_uint_range = |start, end| {
             IntRange::from_range(
@@ -311,9 +316,11 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
                 RangeEnd::Included,
             )
         };
+        // Abort on type error.
+        ty.error_reported()?;
         // This determines the set of all possible constructors for the type `ty`. For numbers,
         // arrays and slices we use ranges and variable-length slices when appropriate.
-        match ty.kind() {
+        Ok(match ty.kind() {
             ty::Bool => ConstructorSet::Bool,
             ty::Char => {
                 // The valid Unicode Scalar Value ranges.
@@ -423,7 +430,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
             ty::CoroutineWitness(_, _) | ty::Bound(_, _) | ty::Placeholder(_) | ty::Infer(_) => {
                 bug!("Encountered unexpected type in `ConstructorSet::for_ty`: {ty:?}")
             }
-        }
+        })
     }
 
     pub(crate) fn lower_pat_range_bdy(
@@ -944,6 +951,7 @@ impl<'p, 'tcx> RustcMatchCheckCtxt<'p, 'tcx> {
 
 impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
     type Ty = RevealedTy<'tcx>;
+    type Error = ErrorGuaranteed;
     type VariantIdx = VariantIdx;
     type StrLit = Const<'tcx>;
     type ArmData = HirId;
@@ -963,7 +971,10 @@ impl<'p, 'tcx> TypeCx for RustcMatchCheckCtxt<'p, 'tcx> {
     ) -> &[Self::Ty] {
         self.ctor_sub_tys(ctor, ty)
     }
-    fn ctors_for_ty(&self, ty: Self::Ty) -> crate::constructor::ConstructorSet<Self> {
+    fn ctors_for_ty(
+        &self,
+        ty: Self::Ty,
+    ) -> Result<crate::constructor::ConstructorSet<Self>, Self::Error> {
         self.ctors_for_ty(ty)
     }
 
diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs
index 16bf709881b6b..d227bca502205 100644
--- a/compiler/rustc_pattern_analysis/src/usefulness.rs
+++ b/compiler/rustc_pattern_analysis/src/usefulness.rs
@@ -753,7 +753,7 @@ impl<'a, 'p, Cx: TypeCx> PlaceCtxt<'a, 'p, Cx> {
     pub(crate) fn ctor_sub_tys(&self, ctor: &Constructor<Cx>) -> &[Cx::Ty] {
         self.mcx.tycx.ctor_sub_tys(ctor, self.ty)
     }
-    pub(crate) fn ctors_for_ty(&self) -> ConstructorSet<Cx> {
+    pub(crate) fn ctors_for_ty(&self) -> Result<ConstructorSet<Cx>, Cx::Error> {
         self.mcx.tycx.ctors_for_ty(self.ty)
     }
 }
@@ -1341,14 +1341,14 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
     mcx: MatchCtxt<'a, 'p, Cx>,
     matrix: &mut Matrix<'p, Cx>,
     is_top_level: bool,
-) -> WitnessMatrix<Cx> {
+) -> Result<WitnessMatrix<Cx>, Cx::Error> {
     debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count()));
 
     if !matrix.wildcard_row_is_relevant && matrix.rows().all(|r| !r.pats.relevant) {
         // Here we know that nothing will contribute further to exhaustiveness or usefulness. This
         // is purely an optimization: skipping this check doesn't affect correctness. See the top of
         // the file for details.
-        return WitnessMatrix::empty();
+        return Ok(WitnessMatrix::empty());
     }
 
     let Some(ty) = matrix.head_ty() else {
@@ -1360,16 +1360,16 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
             // When there's an unguarded row, the match is exhaustive and any subsequent row is not
             // useful.
             if !row.is_under_guard {
-                return WitnessMatrix::empty();
+                return Ok(WitnessMatrix::empty());
             }
         }
         // No (unguarded) rows, so the match is not exhaustive. We return a new witness unless
         // irrelevant.
         return if matrix.wildcard_row_is_relevant {
-            WitnessMatrix::unit_witness()
+            Ok(WitnessMatrix::unit_witness())
         } else {
             // We choose to not report anything here; see at the top for details.
-            WitnessMatrix::empty()
+            Ok(WitnessMatrix::empty())
         };
     };
 
@@ -1383,7 +1383,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
 
     // Analyze the constructors present in this column.
     let ctors = matrix.heads().map(|p| p.ctor());
-    let ctors_for_ty = pcx.ctors_for_ty();
+    let ctors_for_ty = pcx.ctors_for_ty()?;
     let is_integers = matches!(ctors_for_ty, ConstructorSet::Integers { .. }); // For diagnostics.
     let split_set = ctors_for_ty.split(pcx, ctors);
     let all_missing = split_set.present.is_empty();
@@ -1422,7 +1422,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
         let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor, ctor_is_relevant);
         let mut witnesses = ensure_sufficient_stack(|| {
             compute_exhaustiveness_and_usefulness(mcx, &mut spec_matrix, false)
-        });
+        })?;
 
         // Transform witnesses for `spec_matrix` into witnesses for `matrix`.
         witnesses.apply_constructor(pcx, &missing_ctors, &ctor, report_individual_missing_ctors);
@@ -1443,7 +1443,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
         }
     }
 
-    ret
+    Ok(ret)
 }
 
 /// Indicates whether or not a given arm is useful.
@@ -1474,9 +1474,10 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
     arms: &[MatchArm<'p, Cx>],
     scrut_ty: Cx::Ty,
     scrut_validity: ValidityConstraint,
-) -> UsefulnessReport<'p, Cx> {
+) -> Result<UsefulnessReport<'p, Cx>, Cx::Error> {
     let mut matrix = Matrix::new(arms, scrut_ty, scrut_validity);
-    let non_exhaustiveness_witnesses = compute_exhaustiveness_and_usefulness(cx, &mut matrix, true);
+    let non_exhaustiveness_witnesses =
+        compute_exhaustiveness_and_usefulness(cx, &mut matrix, true)?;
 
     let non_exhaustiveness_witnesses: Vec<_> = non_exhaustiveness_witnesses.single_column();
     let arm_usefulness: Vec<_> = arms
@@ -1493,5 +1494,5 @@ pub fn compute_match_usefulness<'p, Cx: TypeCx>(
             (arm, usefulness)
         })
         .collect();
-    UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses }
+    Ok(UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses })
 }
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index 3b1f957c89099..0e43a35ce7389 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -20,7 +20,7 @@
 //    separate step to be able to collapse the adjacent spans that rustfix
 //    will remove
 //
-//  - `check_crate` finally emits the diagnostics based on the data generated
+//  - `check_unused` finally emits the diagnostics based on the data generated
 //    in the last step
 
 use crate::imports::ImportKind;
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 439fa18b7fadc..598178c3c2a59 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -143,11 +143,7 @@ pub fn feature_warn_issue(
     // Decorate this as a future-incompatibility lint as in rustc_middle::lint::struct_lint_level
     let lint = UNSTABLE_SYNTAX_PRE_EXPANSION;
     let future_incompatible = lint.future_incompatible.as_ref().unwrap();
-    err.code(DiagnosticId::Lint {
-        name: lint.name_lower(),
-        has_future_breakage: false,
-        is_force_warn: false,
-    });
+    err.code(DiagnosticId::Lint { name: lint.name_lower(), has_future_breakage: false });
     err.warn(lint.desc);
     err.note(format!("for more information, see {}", future_incompatible.reference));
 
diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs
index 17162d0de25c2..5689e8f3b3d94 100644
--- a/compiler/rustc_smir/src/rustc_internal/internal.rs
+++ b/compiler/rustc_smir/src/rustc_internal/internal.rs
@@ -17,7 +17,7 @@ use stable_mir::ty::{
     GenericArgKind, GenericArgs, IndexedVal, IntTy, Movability, Region, RigidTy, Span, TermKind,
     TraitRef, Ty, UintTy, VariantDef, VariantIdx,
 };
-use stable_mir::{CrateItem, DefId};
+use stable_mir::{CrateItem, CrateNum, DefId};
 
 use super::RustcInternal;
 
@@ -28,6 +28,13 @@ impl<'tcx> RustcInternal<'tcx> for CrateItem {
     }
 }
 
+impl<'tcx> RustcInternal<'tcx> for CrateNum {
+    type T = rustc_span::def_id::CrateNum;
+    fn internal(&self, _tables: &mut Tables<'tcx>) -> Self::T {
+        rustc_span::def_id::CrateNum::from_usize(*self)
+    }
+}
+
 impl<'tcx> RustcInternal<'tcx> for DefId {
     type T = rustc_span::def_id::DefId;
     fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
index f84c466cc440d..fffc454804d29 100644
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -25,8 +25,9 @@ use stable_mir::ty::{
     AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, GenericArgs,
     LineInfo, PolyFnSig, RigidTy, Span, Ty, TyKind, VariantDef,
 };
-use stable_mir::{Crate, CrateItem, DefId, Error, Filename, ItemKind, Symbol};
+use stable_mir::{Crate, CrateItem, CrateNum, DefId, Error, Filename, ItemKind, Symbol};
 use std::cell::RefCell;
+use std::iter;
 
 use crate::rustc_internal::{internal, RustcInternal};
 use crate::rustc_smir::builder::BodyBuilder;
@@ -67,10 +68,15 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
     }
 
     fn all_trait_decls(&self) -> stable_mir::TraitDecls {
+        let mut tables = self.0.borrow_mut();
+        tables.tcx.all_traits().map(|trait_def_id| tables.trait_def(trait_def_id)).collect()
+    }
+
+    fn trait_decls(&self, crate_num: CrateNum) -> stable_mir::TraitDecls {
         let mut tables = self.0.borrow_mut();
         tables
             .tcx
-            .traits(LOCAL_CRATE)
+            .traits(crate_num.internal(&mut *tables))
             .iter()
             .map(|trait_def_id| tables.trait_def(*trait_def_id))
             .collect()
@@ -84,10 +90,20 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
     }
 
     fn all_trait_impls(&self) -> stable_mir::ImplTraitDecls {
+        let mut tables = self.0.borrow_mut();
+        let tcx = tables.tcx;
+        iter::once(LOCAL_CRATE)
+            .chain(tables.tcx.crates(()).iter().copied())
+            .flat_map(|cnum| tcx.trait_impls_in_crate(cnum).iter())
+            .map(|impl_def_id| tables.impl_def(*impl_def_id))
+            .collect()
+    }
+
+    fn trait_impls(&self, crate_num: CrateNum) -> stable_mir::ImplTraitDecls {
         let mut tables = self.0.borrow_mut();
         tables
             .tcx
-            .trait_impls_in_crate(LOCAL_CRATE)
+            .trait_impls_in_crate(crate_num.internal(&mut *tables))
             .iter()
             .map(|impl_def_id| tables.impl_def(*impl_def_id))
             .collect()
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index f0f1d798d44b4..c0ecbfb991413 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -12,12 +12,11 @@ use crate::rustc_smir::{alloc, Stable, Tables};
 impl<'tcx> Stable<'tcx> for ty::AliasKind {
     type T = stable_mir::ty::AliasKind;
     fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        use rustc_middle::ty::AliasKind::*;
         match self {
-            Projection => stable_mir::ty::AliasKind::Projection,
-            Inherent => stable_mir::ty::AliasKind::Inherent,
-            Opaque => stable_mir::ty::AliasKind::Opaque,
-            Weak => stable_mir::ty::AliasKind::Weak,
+            ty::Projection => stable_mir::ty::AliasKind::Projection,
+            ty::Inherent => stable_mir::ty::AliasKind::Inherent,
+            ty::Opaque => stable_mir::ty::AliasKind::Opaque,
+            ty::Weak => stable_mir::ty::AliasKind::Weak,
         }
     }
 }
@@ -34,10 +33,9 @@ impl<'tcx> Stable<'tcx> for ty::DynKind {
     type T = stable_mir::ty::DynKind;
 
     fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
-        use rustc_middle::ty::DynKind;
         match self {
-            DynKind::Dyn => stable_mir::ty::DynKind::Dyn,
-            DynKind::DynStar => stable_mir::ty::DynKind::DynStar,
+            ty::Dyn => stable_mir::ty::DynKind::Dyn,
+            ty::DynStar => stable_mir::ty::DynKind::DynStar,
         }
     }
 }
diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
index 626569fb40fc0..c05c996175042 100644
--- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs
+++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
@@ -2,15 +2,29 @@
 //! Doing this via a separate goal is called "deferred alias relation" and part
 //! of our more general approach to "lazy normalization".
 //!
-//! This goal, e.g. `A alias-relate B`, may be satisfied by one of three branches:
-//! * normalizes-to: If `A` is a projection, we can prove the equivalent
-//!   projection predicate with B as the right-hand side of the projection.
-//!   This goal is computed in both directions, if both are aliases.
-//! * subst-relate: Equate `A` and `B` by their substs, if they're both
-//!   aliases with the same def-id.
-//! * bidirectional-normalizes-to: If `A` and `B` are both projections, and both
-//!   may apply, then we can compute the "intersection" of both normalizes-to by
-//!   performing them together. This is used specifically to resolve ambiguities.
+//! This is done by first normalizing both sides of the goal, ending up in
+//! either a concrete type, rigid projection, opaque, or an infer variable.
+//! These are related further according to the rules below:
+//!
+//! (1.) If we end up with a rigid projection and a rigid projection, then we
+//! relate those projections structurally.
+//!
+//! (2.) If we end up with a rigid projection and an alias, then the opaque will
+//! have its hidden type defined to be that rigid projection.
+//!
+//! (3.) If we end up with an opaque and an opaque, then we assemble two
+//! candidates, one defining the LHS to be the hidden type of the RHS, and vice
+//! versa.
+//!
+//! (4.) If we end up with an infer var and an opaque or rigid projection, then
+//! we assign the alias to the infer var.
+//!
+//! (5.) If we end up with an opaque and a rigid (non-projection) type, then we
+//! define the hidden type of the opaque to be the rigid type.
+//!
+//! (6.) Otherwise, if we end with two rigid (non-projection) or infer types,
+//! relate them structurally.
+
 use super::{EvalCtxt, GoalSource};
 use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::traits::query::NoSolution;
@@ -50,6 +64,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
                     self.relate(param_env, lhs, variance, rhs)?;
                     self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
                 } else if alias.is_opaque(tcx) {
+                    // FIXME: This doesn't account for variance.
                     self.define_opaque(param_env, alias, rhs)
                 } else {
                     Err(NoSolution)
@@ -60,6 +75,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
                     self.relate(param_env, lhs, variance, rhs)?;
                     self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
                 } else if alias.is_opaque(tcx) {
+                    // FIXME: This doesn't account for variance.
                     self.define_opaque(param_env, alias, lhs)
                 } else {
                     Err(NoSolution)
@@ -72,6 +88,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
         }
     }
 
+    // FIXME: This needs a name that reflects that it's okay to bottom-out with an inference var.
     /// Normalize the `term` to equate it later. This does not define opaque types.
     #[instrument(level = "debug", skip(self, param_env), ret)]
     fn try_normalize_term(
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 2f3111a2414d5..7c8f885a1f24c 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -22,6 +22,7 @@ use rustc_middle::traits::solve::{
     CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, IsNormalizesToHack,
     QueryResult, Response,
 };
+use rustc_middle::traits::Reveal;
 use rustc_middle::ty::{self, OpaqueTypeKey, Ty, TyCtxt, UniverseIndex};
 use rustc_middle::ty::{
     CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
@@ -316,19 +317,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
             return Some(ty);
         };
 
-        // We do no always define opaque types eagerly to allow non-defining uses in the defining scope.
-        if let (DefineOpaqueTypes::No, ty::AliasKind::Opaque) = (define_opaque_types, kind) {
-            if let Some(def_id) = alias.def_id.as_local() {
-                if self
-                    .unify_existing_opaque_tys(
-                        param_env,
-                        OpaqueTypeKey { def_id, args: alias.args },
-                        self.next_ty_infer(),
-                    )
-                    .is_empty()
-                {
-                    return Some(ty);
-                }
+        // We do no always define opaque types eagerly to allow non-defining uses
+        // in the defining scope. However, if we can unify this opaque to an existing
+        // opaque, then we should attempt to eagerly reveal the opaque, and we fall
+        // through.
+        if let DefineOpaqueTypes::No = define_opaque_types
+            && let Reveal::UserFacing = param_env.reveal()
+            && let ty::Opaque = kind
+            && let Some(def_id) = alias.def_id.as_local()
+            && self.can_define_opaque_ty(def_id)
+        {
+            if self
+                .unify_existing_opaque_tys(
+                    param_env,
+                    OpaqueTypeKey { def_id, args: alias.args },
+                    self.next_ty_infer(),
+                )
+                .is_empty()
+            {
+                return Some(ty);
             }
         }
 
diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs
index f52e506059bd1..fb83dae571423 100644
--- a/compiler/stable_mir/src/compiler_interface.rs
+++ b/compiler/stable_mir/src/compiler_interface.rs
@@ -16,8 +16,8 @@ use crate::ty::{
     TraitDef, Ty, TyKind, VariantDef,
 };
 use crate::{
-    mir, Crate, CrateItem, CrateItems, DefId, Error, Filename, ImplTraitDecls, ItemKind, Symbol,
-    TraitDecls,
+    mir, Crate, CrateItem, CrateItems, CrateNum, DefId, Error, Filename, ImplTraitDecls, ItemKind,
+    Symbol, TraitDecls,
 };
 
 /// This trait defines the interface between stable_mir and the Rust compiler.
@@ -32,8 +32,10 @@ pub trait Context {
     /// Check whether the body of a function is available.
     fn has_body(&self, item: DefId) -> bool;
     fn all_trait_decls(&self) -> TraitDecls;
+    fn trait_decls(&self, crate_num: CrateNum) -> TraitDecls;
     fn trait_decl(&self, trait_def: &TraitDef) -> TraitDecl;
     fn all_trait_impls(&self) -> ImplTraitDecls;
+    fn trait_impls(&self, crate_num: CrateNum) -> ImplTraitDecls;
     fn trait_impl(&self, trait_impl: &ImplDef) -> ImplTrait;
     fn generics_of(&self, def_id: DefId) -> Generics;
     fn predicates_of(&self, def_id: DefId) -> GenericPredicates;
diff --git a/compiler/stable_mir/src/lib.rs b/compiler/stable_mir/src/lib.rs
index 9194f1e6bdb5e..de5dfcdf207f7 100644
--- a/compiler/stable_mir/src/lib.rs
+++ b/compiler/stable_mir/src/lib.rs
@@ -31,7 +31,7 @@ pub use crate::error::*;
 use crate::mir::pretty::function_name;
 use crate::mir::Body;
 use crate::mir::Mutability;
-use crate::ty::{ImplDef, ImplTrait, IndexedVal, Span, TraitDecl, TraitDef, Ty};
+use crate::ty::{ImplDef, IndexedVal, Span, TraitDef, Ty};
 
 pub mod abi;
 #[macro_use]
@@ -86,6 +86,18 @@ pub struct Crate {
     pub is_local: bool,
 }
 
+impl Crate {
+    /// The list of traits declared in this crate.
+    pub fn trait_decls(&self) -> TraitDecls {
+        with(|cx| cx.trait_decls(self.id))
+    }
+
+    /// The list of trait implementations in this crate.
+    pub fn trait_impls(&self) -> ImplTraitDecls {
+        with(|cx| cx.trait_impls(self.id))
+    }
+}
+
 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
 pub enum ItemKind {
     Fn,
@@ -169,18 +181,10 @@ pub fn all_trait_decls() -> TraitDecls {
     with(|cx| cx.all_trait_decls())
 }
 
-pub fn trait_decl(trait_def: &TraitDef) -> TraitDecl {
-    with(|cx| cx.trait_decl(trait_def))
-}
-
 pub fn all_trait_impls() -> ImplTraitDecls {
     with(|cx| cx.all_trait_impls())
 }
 
-pub fn trait_impl(trait_impl: &ImplDef) -> ImplTrait {
-    with(|cx| cx.trait_impl(trait_impl))
-}
-
 /// A type that provides internal information but that can still be used for debug purpose.
 #[derive(Clone, PartialEq, Eq, Hash)]
 pub struct Opaque(String);
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index 9e6ecbe8315b5..eba2ac57012b9 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -714,9 +714,16 @@ crate_def! {
 }
 
 crate_def! {
+    /// A trait's definition.
     pub TraitDef;
 }
 
+impl TraitDef {
+    pub fn declaration(trait_def: &TraitDef) -> TraitDecl {
+        with(|cx| cx.trait_decl(trait_def))
+    }
+}
+
 crate_def! {
     pub GenericDef;
 }
@@ -726,9 +733,17 @@ crate_def! {
 }
 
 crate_def! {
+    /// A trait impl definition.
     pub ImplDef;
 }
 
+impl ImplDef {
+    /// Retrieve information about this implementation.
+    pub fn trait_impl(&self) -> ImplTrait {
+        with(|cx| cx.trait_impl(self))
+    }
+}
+
 crate_def! {
     pub RegionDef;
 }
diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs
index 1ef876a3163c9..4b5862d98a3ab 100644
--- a/library/core/src/net/ip_addr.rs
+++ b/library/core/src/net/ip_addr.rs
@@ -771,7 +771,11 @@ impl Ipv4Addr {
             || self.is_loopback()
             || self.is_link_local()
             // addresses reserved for future protocols (`192.0.0.0/24`)
-            ||(self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0)
+            // .9 and .10 are documented as globally reachable so they're excluded
+            || (
+                self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0
+                && self.octets()[3] != 9 && self.octets()[3] != 10
+            )
             || self.is_documentation()
             || self.is_benchmarking()
             || self.is_reserved()
@@ -1515,8 +1519,12 @@ impl Ipv6Addr {
                     // AS112-v6 (`2001:4:112::/48`)
                     || matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
                     // ORCHIDv2 (`2001:20::/28`)
-                    || matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x2F)
+                    // Drone Remote ID Protocol Entity Tags (DETs) Prefix (`2001:30::/28`)`
+                    || matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x3F)
                 ))
+            // 6to4 (`2002::/16`) – it's not explicitly documented as globally reachable,
+            // IANA says N/A.
+            || matches!(self.segments(), [0x2002, _, _, _, _, _, _, _])
             || self.is_documentation()
             || self.is_unique_local()
             || self.is_unicast_link_local())
diff --git a/library/core/tests/net/ip_addr.rs b/library/core/tests/net/ip_addr.rs
index 7530fc084874d..7f7802c221a61 100644
--- a/library/core/tests/net/ip_addr.rs
+++ b/library/core/tests/net/ip_addr.rs
@@ -461,6 +461,10 @@ fn ipv4_properties() {
     check!("198.18.54.2", benchmarking);
     check!("198.19.255.255", benchmarking);
     check!("192.0.0.0");
+    check!("192.0.0.8");
+    check!("192.0.0.9", global);
+    check!("192.0.0.10", global);
+    check!("192.0.0.11");
     check!("192.0.0.255");
     check!("192.0.0.100");
     check!("240.0.0.0", reserved);
@@ -480,6 +484,10 @@ fn ipv6_properties() {
     }
 
     macro_rules! check {
+        ($s:expr, &[$($octet:expr),*]) => {
+            check!($s, &[$($octet),*], 0);
+        };
+
         ($s:expr, &[$($octet:expr),*], $mask:expr) => {
             assert_eq!($s, ip!($s).to_string());
             let octets = &[$($octet),*];
@@ -656,8 +664,8 @@ fn ipv6_properties() {
         &[0x20, 1, 0, 0x20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         global | unicast_global
     );
-
-    check!("2001:30::", &[0x20, 1, 0, 0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
+    check!("2001:30::", &[0x20, 1, 0, 0x30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global);
+    check!("2001:40::", &[0x20, 1, 0, 0x40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
 
     check!(
         "2001:200::",
@@ -665,6 +673,8 @@ fn ipv6_properties() {
         global | unicast_global
     );
 
+    check!("2002::", &[0x20, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_global);
+
     check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local);
 
     check!(
diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs
index 0c001d7c258c0..184c406e326cf 100644
--- a/library/std/src/sync/mutex.rs
+++ b/library/std/src/sync/mutex.rs
@@ -383,8 +383,6 @@ impl<T: ?Sized> Mutex<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(mutex_unpoison)]
-    ///
     /// use std::sync::{Arc, Mutex};
     /// use std::thread;
     ///
@@ -406,7 +404,7 @@ impl<T: ?Sized> Mutex<T> {
     /// assert_eq!(*x, 1);
     /// ```
     #[inline]
-    #[unstable(feature = "mutex_unpoison", issue = "96469")]
+    #[stable(feature = "mutex_unpoison", since = "CURRENT_RUSTC_VERSION")]
     pub fn clear_poison(&self) {
         self.poison.clear();
     }
diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs
index 5d8967bfbe686..23d3dd0707a34 100644
--- a/library/std/src/sync/rwlock.rs
+++ b/library/std/src/sync/rwlock.rs
@@ -387,8 +387,6 @@ impl<T: ?Sized> RwLock<T> {
     /// # Examples
     ///
     /// ```
-    /// #![feature(mutex_unpoison)]
-    ///
     /// use std::sync::{Arc, RwLock};
     /// use std::thread;
     ///
@@ -410,7 +408,7 @@ impl<T: ?Sized> RwLock<T> {
     /// assert_eq!(*guard, 1);
     /// ```
     #[inline]
-    #[unstable(feature = "mutex_unpoison", issue = "96469")]
+    #[stable(feature = "mutex_unpoison", since = "CURRENT_RUSTC_VERSION")]
     pub fn clear_poison(&self) {
         self.poison.clear();
     }
diff --git a/src/doc/style-guide/src/README.md b/src/doc/style-guide/src/README.md
index 9a59d80556e0f..dce50ebf29c46 100644
--- a/src/doc/style-guide/src/README.md
+++ b/src/doc/style-guide/src/README.md
@@ -112,6 +112,90 @@ fn bar() {}
 fn baz() {}
 ```
 
+### Sorting
+
+In various cases, the default Rust style specifies to sort things. If not
+otherwise specified, such sorting should be "version sorting", which ensures
+that (for instance) `x8` comes before `x16` even though the character `1` comes
+before the character `8`. (If not otherwise specified, version-sorting is
+lexicographical.)
+
+For the purposes of the Rust style, to compare two strings for version-sorting:
+
+- Process both strings from beginning to end as two sequences of maximal-length
+  chunks, where each chunk consists either of a sequence of characters other
+  than ASCII digits, or a sequence of ASCII digits (a numeric chunk), and
+  compare corresponding chunks from the strings.
+- To compare two numeric chunks, compare them by numeric value, ignoring
+  leading zeroes. If the two chunks have equal numeric value, but different
+  numbers of leading digits, and this is the first time this has happened for
+  these strings, treat the chunks as equal (moving on to the next chunk) but
+  remember which string had more leading zeroes.
+- To compare two chunks if both are not numeric, compare them by Unicode
+  character lexicographically, except that `_` (underscore) sorts immediately
+  after ` ` (space) but before any other character. (This treats underscore as
+  a word separator, as commonly used in identifiers.)
+  - If the use of version sorting specifies further modifiers, such as sorting
+    non-lowercase before lowercase, apply those modifiers to the lexicographic
+    sort in this step.
+- If the comparison reaches the end of the string and considers each pair of
+  chunks equal:
+  - If one of the numeric comparisons noted the earliest point at which one
+    string had more leading zeroes than the other, sort the string with more
+    leading zeroes first.
+  - Otherwise, the strings are equal.
+
+Note that there exist various algorithms called "version sorting", which
+generally try to solve the same problem, but which differ in various ways (such
+as in their handling of numbers with leading zeroes). This algorithm
+does not purport to precisely match the behavior of any particular other
+algorithm, only to produce a simple and satisfying result for Rust formatting.
+In particular, this algorithm aims to produce a satisfying result for a set of
+symbols that have the same number of leading zeroes, and an acceptable and
+easily understandable result for a set of symbols that has varying numbers of
+leading zeroes.
+
+As an example, version-sorting will sort the following strings in the order
+given:
+- `_ZYWX`
+- `u_zzz`
+- `u8`
+- `u16`
+- `u32`
+- `u64`
+- `u128`
+- `u256`
+- `ua`
+- `usize`
+- `uz`
+- `v000`
+- `v00`
+- `v0`
+- `v0s`
+- `v00t`
+- `v0u`
+- `v001`
+- `v01`
+- `v1`
+- `v009`
+- `v09`
+- `v9`
+- `v010`
+- `v10`
+- `w005s09t`
+- `w5s009t`
+- `x64`
+- `x86`
+- `x86_32`
+- `x86_64`
+- `x86_128`
+- `x87`
+- `Z_YWX`
+- `ZY_WX`
+- `ZYW_X`
+- `ZYWX`
+- `ZYWX_`
+
 ### [Module-level items](items.md)
 
 ### [Statements](statements.md)
diff --git a/src/doc/style-guide/src/cargo.md b/src/doc/style-guide/src/cargo.md
index d3b67ae45825d..d47d04642280f 100644
--- a/src/doc/style-guide/src/cargo.md
+++ b/src/doc/style-guide/src/cargo.md
@@ -8,11 +8,11 @@ Put a blank line between the last key-value pair in a section and the header of
 the next section. Do not place a blank line between section headers and the
 key-value pairs in that section, or between key-value pairs in a section.
 
-Sort key names alphabetically within each section, with the exception of the
+Version-sort key names within each section, with the exception of the
 `[package]` section. Put the `[package]` section at the top of the file; put
 the `name` and `version` keys in that order at the top of that section,
-followed by the remaining keys other than `description` in alphabetical order,
-followed by the `description` at the end of that section.
+followed by the remaining keys other than `description` in order, followed by
+the `description` at the end of that section.
 
 Don't use quotes around any standard key names; use bare keys. Only use quoted
 keys for non-standard keys whose names require them, and avoid introducing such
diff --git a/src/doc/style-guide/src/editions.md b/src/doc/style-guide/src/editions.md
index 5c67a185b8ffa..19e62c4867c99 100644
--- a/src/doc/style-guide/src/editions.md
+++ b/src/doc/style-guide/src/editions.md
@@ -37,6 +37,8 @@ history of the style guide. Notable changes in the Rust 2024 style edition
 include:
 
 - Miscellaneous `rustfmt` bugfixes.
+- Use version-sort (sort `x8`, `x16`, `x32`, `x64`, `x128` in that order).
+- Change "ASCIIbetical" sort to Unicode-aware "non-lowercase before lowercase".
 
 ## Rust 2015/2018/2021 style edition
 
diff --git a/src/doc/style-guide/src/items.md b/src/doc/style-guide/src/items.md
index b215de6ad28a2..0066a4bacb956 100644
--- a/src/doc/style-guide/src/items.md
+++ b/src/doc/style-guide/src/items.md
@@ -9,8 +9,8 @@ an item appears at module level or within another item.
 alphabetically.
 
 `use` statements, and module *declarations* (`mod foo;`, not `mod { ... }`)
-must come before other items. Put imports before module declarations. Sort each
-alphabetically, except that `self` and `super` must come before any other
+must come before other items. Put imports before module declarations.
+Version-sort each, except that `self` and `super` must come before any other
 names.
 
 Don't automatically move module declarations annotated with `#[macro_use]`,
@@ -467,8 +467,10 @@ foo::{
 A *group* of imports is a set of imports on the same or sequential lines. One or
 more blank lines or other items (e.g., a function) separate groups of imports.
 
-Within a group of imports, imports must be sorted ASCIIbetically (uppercase
-before lowercase). Groups of imports must not be merged or re-ordered.
+Within a group of imports, imports must be version-sorted, except that
+non-lowercase characters (characters that can start an `UpperCamelCase`
+identifier) must be sorted before lowercase characters. Groups of imports must
+not be merged or re-ordered.
 
 E.g., input:
 
@@ -495,10 +497,15 @@ re-ordering.
 
 ### Ordering list import
 
-Names in a list import must be sorted ASCIIbetically, but with `self` and
-`super` first, and groups and glob imports last. This applies recursively. For
-example, `a::*` comes before `b::a` but `a::b` comes before `a::*`. E.g.,
-`use foo::bar::{a, b::c, b::d, b::d::{x, y, z}, b::{self, r, s}};`.
+Names in a list import must be version-sorted, except that:
+- `self` and `super` always come first if present,
+- non-lowercase characters (characters that can start an `UpperCamelCase`
+  identifier) must be sorted before lowercase characters, and
+- groups and glob imports always come last if present.
+
+This applies recursively. For example, `a::*` comes before `b::a` but `a::b`
+comes before `a::*`. E.g., `use foo::bar::{a, b::c, b::d, b::d::{x, y, z},
+b::{self, r, s}};`.
 
 ### Normalisation
 
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 819d2018a1595..bf3284df5967a 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -455,7 +455,7 @@ pub fn report_msg<'tcx>(
     let sess = machine.tcx.sess;
     let level = match diag_level {
         DiagLevel::Error => Level::Error,
-        DiagLevel::Warning => Level::Warning(None),
+        DiagLevel::Warning => Level::Warning,
         DiagLevel::Note => Level::Note,
     };
     let mut err = DiagnosticBuilder::<()>::new(sess.dcx(), level, title);
diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs
index 2663f16b8e8d8..f4fb5073dfdcd 100644
--- a/src/tools/rustfmt/src/parse/session.rs
+++ b/src/tools/rustfmt/src/parse/session.rs
@@ -446,7 +446,7 @@ mod tests {
                 Some(ignore_list),
             );
             let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
-            let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(span));
+            let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span));
             emitter.emit_diagnostic(&non_fatal_diagnostic);
             assert_eq!(num_emitted_errors.load(Ordering::Acquire), 0);
             assert_eq!(can_reset_errors.load(Ordering::Acquire), true);
@@ -470,7 +470,7 @@ mod tests {
                 None,
             );
             let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
-            let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(span));
+            let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span));
             emitter.emit_diagnostic(&non_fatal_diagnostic);
             assert_eq!(num_emitted_errors.load(Ordering::Acquire), 1);
             assert_eq!(can_reset_errors.load(Ordering::Acquire), false);
@@ -507,8 +507,8 @@ mod tests {
             );
             let bar_span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1)));
             let foo_span = MultiSpan::from_span(mk_sp(BytePos(21), BytePos(22)));
-            let bar_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(bar_span));
-            let foo_diagnostic = build_diagnostic(DiagnosticLevel::Warning(None), Some(foo_span));
+            let bar_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(bar_span));
+            let foo_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(foo_span));
             let fatal_diagnostic = build_diagnostic(DiagnosticLevel::Fatal, None);
             emitter.emit_diagnostic(&bar_diagnostic);
             emitter.emit_diagnostic(&foo_diagnostic);
diff --git a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs
new file mode 100644
index 0000000000000..fb1197e4ecc40
--- /dev/null
+++ b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs
@@ -0,0 +1,125 @@
+// run-pass
+//! Test that users are able to retrieve information about trait declarations and implementations.
+
+// ignore-stage1
+// ignore-cross-compile
+// ignore-remote
+// ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
+// edition: 2021
+
+#![feature(rustc_private)]
+#![feature(assert_matches)]
+#![feature(control_flow_enum)]
+
+extern crate rustc_middle;
+#[macro_use]
+extern crate rustc_smir;
+extern crate rustc_driver;
+extern crate rustc_interface;
+extern crate stable_mir;
+
+use rustc_middle::ty::TyCtxt;
+use rustc_smir::rustc_internal;
+use stable_mir::CrateDef;
+use std::collections::HashSet;
+use std::io::Write;
+use std::ops::ControlFlow;
+
+const CRATE_NAME: &str = "trait_test";
+
+/// This function uses the Stable MIR APIs to get information about the test crate.
+fn test_traits() -> ControlFlow<()> {
+    let local_crate = stable_mir::local_crate();
+    let local_traits = local_crate.trait_decls();
+    assert_eq!(local_traits.len(), 1, "Expected `Max` trait, but found {:?}", local_traits);
+    assert_eq!(&local_traits[0].name(), "Max");
+
+    let local_impls = local_crate.trait_impls();
+    let impl_names = local_impls.iter().map(|trait_impl| trait_impl.name()).collect::<HashSet<_>>();
+    assert_impl(&impl_names, "<Positive as Max>");
+    assert_impl(&impl_names, "<Positive as std::marker::Copy>");
+    assert_impl(&impl_names, "<Positive as std::clone::Clone>");
+    assert_impl(&impl_names, "<Positive as std::fmt::Debug>");
+    assert_impl(&impl_names, "<Positive as std::cmp::PartialEq>");
+    assert_impl(&impl_names, "<Positive as std::cmp::Eq>");
+    assert_impl(&impl_names, "<Positive as std::convert::TryFrom<u64>>");
+    assert_impl(&impl_names, "<u64 as Max>");
+    assert_impl(&impl_names, "<impl std::convert::From<Positive> for u64>");
+
+    let all_traits = stable_mir::all_trait_decls();
+    assert!(all_traits.len() > local_traits.len());
+    assert!(
+        local_traits.iter().all(|t| all_traits.contains(t)),
+        "Local: {local_traits:#?}, All: {all_traits:#?}"
+    );
+
+    let all_impls = stable_mir::all_trait_impls();
+    assert!(all_impls.len() > local_impls.len());
+    assert!(
+        local_impls.iter().all(|t| all_impls.contains(t)),
+        "Local: {local_impls:#?}, All: {all_impls:#?}"
+    );
+    ControlFlow::Continue(())
+}
+
+fn assert_impl(impl_names: &HashSet<String>, target: &str) {
+    assert!(
+        impl_names.contains(target),
+        "Failed to find `{target}`. Implementations available: {impl_names:?}",
+    );
+}
+
+/// This test will generate and analyze a dummy crate using the stable mir.
+/// For that, it will first write the dummy crate into a file.
+/// Then it will create a `StableMir` using custom arguments and then
+/// it will run the compiler.
+fn main() {
+    let path = "trait_queries.rs";
+    generate_input(&path).unwrap();
+    let args = vec![
+        "rustc".to_string(),
+        "--crate-type=lib".to_string(),
+        "--crate-name".to_string(),
+        CRATE_NAME.to_string(),
+        path.to_string(),
+    ];
+    run!(args, test_traits()).unwrap();
+}
+
+fn generate_input(path: &str) -> std::io::Result<()> {
+    let mut file = std::fs::File::create(path)?;
+    write!(
+        file,
+        r#"
+        use std::convert::TryFrom;
+
+        #[derive(Copy, Clone, Debug, PartialEq, Eq)]
+        pub struct Positive(u64);
+
+        impl TryFrom<u64> for Positive {{
+            type Error = ();
+            fn try_from(val: u64) -> Result<Positive, Self::Error> {{
+                if val > 0 {{ Ok(Positive(val)) }} else {{ Err(()) }}
+            }}
+        }}
+
+        impl From<Positive> for u64 {{
+            fn from(val: Positive) -> u64 {{ val.0 }}
+        }}
+
+        pub trait Max {{
+            fn is_max(&self) -> bool;
+        }}
+
+        impl Max for u64 {{
+            fn is_max(&self) -> bool {{ *self == u64::MAX }}
+        }}
+
+        impl Max for Positive {{
+            fn is_max(&self) -> bool {{ self.0.is_max() }}
+        }}
+
+    "#
+    )?;
+    Ok(())
+}
diff --git a/tests/ui/pattern/usefulness/issue-119493-type-error-ice.rs b/tests/ui/pattern/usefulness/issue-119493-type-error-ice.rs
new file mode 100644
index 0000000000000..6cf459eb82e13
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-119493-type-error-ice.rs
@@ -0,0 +1,13 @@
+fn main() {}
+
+fn foo() {
+    #[derive(Copy, Clone)]
+    struct Foo(NonExistent);
+    //~^ ERROR cannot find type
+    //~| ERROR cannot find type
+
+    type U = impl Copy;
+    //~^ ERROR `impl Trait` in type aliases is unstable
+    let foo: U = Foo(());
+    let Foo(()) = foo;
+}
diff --git a/tests/ui/pattern/usefulness/issue-119493-type-error-ice.stderr b/tests/ui/pattern/usefulness/issue-119493-type-error-ice.stderr
new file mode 100644
index 0000000000000..6d74feb7a9f3f
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-119493-type-error-ice.stderr
@@ -0,0 +1,30 @@
+error[E0412]: cannot find type `NonExistent` in this scope
+  --> $DIR/issue-119493-type-error-ice.rs:5:16
+   |
+LL |     struct Foo(NonExistent);
+   |                ^^^^^^^^^^^ not found in this scope
+
+error[E0412]: cannot find type `NonExistent` in this scope
+  --> $DIR/issue-119493-type-error-ice.rs:5:16
+   |
+LL |     struct Foo(NonExistent);
+   |                ^^^^^^^^^^^ not found in this scope
+   |
+help: you might be missing a type parameter
+   |
+LL |     struct Foo<NonExistent>(NonExistent);
+   |               +++++++++++++
+
+error[E0658]: `impl Trait` in type aliases is unstable
+  --> $DIR/issue-119493-type-error-ice.rs:9:14
+   |
+LL |     type U = impl Copy;
+   |              ^^^^^^^^^
+   |
+   = note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
+   = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0412, E0658.
+For more information about an error, try `rustc --explain E0412`.
diff --git a/tests/ui/pattern/usefulness/issue-119778-type-error-ice.rs b/tests/ui/pattern/usefulness/issue-119778-type-error-ice.rs
new file mode 100644
index 0000000000000..47333385bc161
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-119778-type-error-ice.rs
@@ -0,0 +1,13 @@
+fn main() {}
+
+fn foo() {
+    #[derive(Copy, Clone)]
+    struct Foo([u8; S]);
+    //~^ ERROR cannot find value `S`
+    //~| ERROR cannot find value `S`
+
+    type U = impl Copy;
+    //~^ ERROR `impl Trait` in type aliases is unstable
+    let foo: U = Foo(());
+    let Foo(()) = foo;
+}
diff --git a/tests/ui/pattern/usefulness/issue-119778-type-error-ice.stderr b/tests/ui/pattern/usefulness/issue-119778-type-error-ice.stderr
new file mode 100644
index 0000000000000..93ef05decd26f
--- /dev/null
+++ b/tests/ui/pattern/usefulness/issue-119778-type-error-ice.stderr
@@ -0,0 +1,35 @@
+error[E0425]: cannot find value `S` in this scope
+  --> $DIR/issue-119778-type-error-ice.rs:5:21
+   |
+LL |     struct Foo([u8; S]);
+   |                     ^ not found in this scope
+   |
+help: you might be missing a const parameter
+   |
+LL |     struct Foo<const S: /* Type */>([u8; S]);
+   |               +++++++++++++++++++++
+
+error[E0425]: cannot find value `S` in this scope
+  --> $DIR/issue-119778-type-error-ice.rs:5:21
+   |
+LL |     struct Foo([u8; S]);
+   |                     ^ not found in this scope
+   |
+help: you might be missing a const parameter
+   |
+LL |     struct Foo<const S: /* Type */>([u8; S]);
+   |               +++++++++++++++++++++
+
+error[E0658]: `impl Trait` in type aliases is unstable
+  --> $DIR/issue-119778-type-error-ice.rs:9:14
+   |
+LL |     type U = impl Copy;
+   |              ^^^^^^^^^
+   |
+   = note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
+   = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0425, E0658.
+For more information about an error, try `rustc --explain E0425`.
diff --git a/tests/ui/type-alias-impl-trait/issue-77179.rs b/tests/ui/type-alias-impl-trait/issue-77179.rs
index 6e2ce76632fdc..093aeb4b27911 100644
--- a/tests/ui/type-alias-impl-trait/issue-77179.rs
+++ b/tests/ui/type-alias-impl-trait/issue-77179.rs
@@ -6,9 +6,7 @@ type Pointer<T> = impl std::ops::Deref<Target = T>;
 
 fn test() -> Pointer<_> {
     //~^ ERROR: the placeholder `_` is not allowed within types
-    //~| ERROR: non-defining opaque type use in defining scope
     Box::new(1)
-    //~^ ERROR expected generic type parameter, found `i32`
 }
 
 fn main() {
diff --git a/tests/ui/type-alias-impl-trait/issue-77179.stderr b/tests/ui/type-alias-impl-trait/issue-77179.stderr
index c5b7c4178e473..68dd6570d00c0 100644
--- a/tests/ui/type-alias-impl-trait/issue-77179.stderr
+++ b/tests/ui/type-alias-impl-trait/issue-77179.stderr
@@ -7,28 +7,6 @@ LL | fn test() -> Pointer<_> {
    |              |       not allowed in type signatures
    |              help: replace with the correct return type: `Pointer<i32>`
 
-error[E0792]: non-defining opaque type use in defining scope
-  --> $DIR/issue-77179.rs:7:14
-   |
-LL | fn test() -> Pointer<_> {
-   |              ^^^^^^^^^^ argument `i32` is not a generic parameter
-   |
-note: for this opaque type
-  --> $DIR/issue-77179.rs:5:19
-   |
-LL | type Pointer<T> = impl std::ops::Deref<Target = T>;
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0792]: expected generic type parameter, found `i32`
-  --> $DIR/issue-77179.rs:10:5
-   |
-LL | type Pointer<T> = impl std::ops::Deref<Target = T>;
-   |              - this generic parameter must be used with a generic type parameter
-...
-LL |     Box::new(1)
-   |     ^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0121, E0792.
-For more information about an error, try `rustc --explain E0121`.
+For more information about this error, try `rustc --explain E0121`.
diff --git a/triagebot.toml b/triagebot.toml
index 5406500cec302..aac3a830a7875 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -744,6 +744,12 @@ style-team = [
     "@yaahc",
 ]
 
+project-const-traits = [
+    "@compiler-errors",
+    "@fee1-dead",
+    "@fmease",
+    "@oli-obk",
+]
 project-stable-mir = [
     "@celinval",
     "@oli-obk",