diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 942aae3d53600..73d1d891bb989 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -323,9 +323,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     )
                 }
                 ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
-                ExprKind::Err => {
-                    hir::ExprKind::Err(self.dcx().span_delayed_bug(e.span, "lowered ExprKind::Err"))
-                }
+                ExprKind::Err => hir::ExprKind::Err(self.dcx().has_errors().unwrap()),
                 ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),
 
                 ExprKind::Paren(_) | ExprKind::ForLoop { .. } => {
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 933372fae4eb4..87ed47648c813 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1068,7 +1068,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     fn lower_block_expr_opt(&mut self, span: Span, block: Option<&Block>) -> hir::Expr<'hir> {
         match block {
             Some(block) => self.lower_block_expr(block),
-            None => self.expr_err(span, self.dcx().span_delayed_bug(span, "no block")),
+            None => self.expr_err(span, self.dcx().has_errors().unwrap()),
         }
     }
 
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 480072ce705aa..6b5fc01424085 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1285,9 +1285,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
         let kind = match &t.kind {
             TyKind::Infer => hir::TyKind::Infer,
-            TyKind::Err => {
-                hir::TyKind::Err(self.dcx().span_delayed_bug(t.span, "TyKind::Err lowered"))
-            }
+            TyKind::Err => hir::TyKind::Err(self.dcx().has_errors().unwrap()),
             // Lower the anonymous structs or unions in a nested lowering context.
             //
             // ```
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 5ce6a71c4bdd5..b5c70538c52d3 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -117,18 +117,14 @@ struct CfgChecker<'a, 'tcx> {
 impl<'a, 'tcx> CfgChecker<'a, 'tcx> {
     #[track_caller]
     fn fail(&self, location: Location, msg: impl AsRef<str>) {
-        let span = self.body.source_info(location).span;
-        // We use `span_delayed_bug` as we might see broken MIR when other errors have already
-        // occurred.
-        self.tcx.dcx().span_delayed_bug(
-            span,
-            format!(
-                "broken MIR in {:?} ({}) at {:?}:\n{}",
-                self.body.source.instance,
-                self.when,
-                location,
-                msg.as_ref()
-            ),
+        // We might see broken MIR when other errors have already occurred.
+        assert!(
+            self.tcx.dcx().has_errors().is_some(),
+            "broken MIR in {:?} ({}) at {:?}:\n{}",
+            self.body.source.instance,
+            self.when,
+            location,
+            msg.as_ref(),
         );
     }
 
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index b738ecb54ffc1..d876f28040da1 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -1315,6 +1315,9 @@ impl DiagCtxtInner {
             self.future_breakage_diagnostics.push(diagnostic.clone());
         }
 
+        // Note that because this comes before the `match` below,
+        // `-Zeagerly-emit-delayed-bugs` continues to work even after we've
+        // issued an error and stopped recording new delayed bugs.
         if diagnostic.level == DelayedBug && self.flags.eagerly_emit_delayed_bugs {
             diagnostic.level = Error;
         }
@@ -1326,18 +1329,20 @@ impl DiagCtxtInner {
                 diagnostic.level = Bug;
             }
             DelayedBug => {
-                // FIXME(eddyb) this should check for `has_errors` and stop pushing
-                // once *any* errors were emitted (and truncate `delayed_bugs`
-                // when an error is first emitted, also), but maybe there's a case
-                // in which that's not sound? otherwise this is really inefficient.
-                let backtrace = std::backtrace::Backtrace::capture();
-                // This `unchecked_error_guaranteed` is valid. It is where the
-                // `ErrorGuaranteed` for delayed bugs originates.
-                #[allow(deprecated)]
-                let guar = ErrorGuaranteed::unchecked_error_guaranteed();
-                self.delayed_bugs
-                    .push((DelayedDiagnostic::with_backtrace(diagnostic, backtrace), guar));
-                return Some(guar);
+                // If we have already emitted at least one error, we don't need
+                // to record the delayed bug, because it'll never be used.
+                return if let Some(guar) = self.has_errors_or_lint_errors() {
+                    Some(guar)
+                } else {
+                    let backtrace = std::backtrace::Backtrace::capture();
+                    // This `unchecked_error_guaranteed` is valid. It is where the
+                    // `ErrorGuaranteed` for delayed bugs originates.
+                    #[allow(deprecated)]
+                    let guar = ErrorGuaranteed::unchecked_error_guaranteed();
+                    self.delayed_bugs
+                        .push((DelayedDiagnostic::with_backtrace(diagnostic, backtrace), guar));
+                    Some(guar)
+                };
             }
             Warning if !self.flags.can_emit_warnings => {
                 if diagnostic.has_future_breakage() {
@@ -1403,6 +1408,16 @@ impl DiagCtxtInner {
             }
 
             if is_error {
+                // If we have any delayed bugs recorded, we can discard them
+                // because they won't be used. (This should only occur if there
+                // have been no errors previously emitted, because we don't add
+                // new delayed bugs once the first error is emitted.)
+                if !self.delayed_bugs.is_empty() {
+                    assert_eq!(self.lint_err_guars.len() + self.err_guars.len(), 0);
+                    self.delayed_bugs.clear();
+                    self.delayed_bugs.shrink_to_fit();
+                }
+
                 // This `unchecked_error_guaranteed` is valid. It is where the
                 // `ErrorGuaranteed` for errors and lint errors originates.
                 #[allow(deprecated)]
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index eec86c36aedae..be4b6399e12da 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -34,10 +34,10 @@ pub(super) fn failed_to_match_macro<'cx>(
     if try_success_result.is_ok() {
         // Nonterminal parser recovery might turn failed matches into successful ones,
         // but for that it must have emitted an error already
-        tracker
-            .cx
-            .dcx()
-            .span_delayed_bug(sp, "Macro matching returned a success on the second try");
+        assert!(
+            tracker.cx.dcx().has_errors().is_some(),
+            "Macro matching returned a success on the second try"
+        );
     }
 
     if let Some(result) = tracker.result {
diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs
index a6ac8ecd950ea..cee7c84adb2e9 100644
--- a/compiler/rustc_hir_analysis/src/astconv/lint.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs
@@ -243,7 +243,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 tcx.node_span_lint(BARE_TRAIT_OBJECTS, self_ty.hir_id, self_ty.span, msg, |lint| {
                     if self_ty.span.can_be_used_for_suggestions() {
                         lint.multipart_suggestion_verbose(
-                            "use `dyn`",
+                            "if this is an object-safe trait, use `dyn`",
                             sugg,
                             Applicability::MachineApplicable,
                         );
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index a001044c3e52d..98a27c5ed2093 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -758,8 +758,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             // since we should have emitten an error for them earlier, and they will
             // not be well-formed!
             if polarity == ty::ImplPolarity::Negative {
-                self.tcx().dcx().span_delayed_bug(
-                    binding.span,
+                assert!(
+                    self.tcx().dcx().has_errors().is_some(),
                     "negative trait bounds should not have bindings",
                 );
                 continue;
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 7f674a1e7e45f..e7506cee60e7c 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1865,13 +1865,13 @@ fn check_variances_for_type_defn<'tcx>(
         let hir_param = &hir_generics.params[index];
 
         if ty_param.def_id != hir_param.def_id.into() {
-            // valid programs always have lifetimes before types in the generic parameter list
+            // Valid programs always have lifetimes before types in the generic parameter list.
             // ty_generics are normalized to be in this required order, and variances are built
             // from ty generics, not from hir generics. but we need hir generics to get
-            // a span out
+            // a span out.
             //
-            // if they aren't in the same order, then the user has written invalid code, and already
-            // got an error about it (or I'm wrong about this)
+            // If they aren't in the same order, then the user has written invalid code, and already
+            // got an error about it (or I'm wrong about this).
             tcx.dcx().span_delayed_bug(
                 hir_param.span,
                 "hir generics and ty generics in different order",
diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
index 688760a391269..53a5ada410560 100644
--- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
@@ -85,7 +85,7 @@ pub(super) fn check_item(
 
         (_, _, Unsafety::Unsafe, Negative) => {
             // Reported in AST validation
-            tcx.dcx().span_delayed_bug(tcx.def_span(def_id), "unsafe negative impl");
+            assert!(tcx.dcx().has_errors().is_some(), "unsafe negative impl");
             Ok(())
         }
         (_, _, Unsafety::Normal, Negative)
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index f21de1609cb7f..9a8f287ec14f7 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -139,10 +139,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             | ty::Never
             | ty::Dynamic(_, _, ty::DynStar)
             | ty::Error(_) => {
-                let reported = self
+                let guar = self
                     .dcx()
                     .span_delayed_bug(span, format!("`{t:?}` should be sized but is not?"));
-                return Err(reported);
+                return Err(guar);
             }
         })
     }
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index d84bce09ecb1e..b83a0f893f5f8 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -221,8 +221,8 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
             if base_ty.is_none() {
                 // When encountering `return [0][0]` outside of a `fn` body we can encounter a base
                 // that isn't in the type table. We assume more relevant errors have already been
-                // emitted, so we delay an ICE if none have. (#64638)
-                self.tcx().dcx().span_delayed_bug(e.span, format!("bad base: `{base:?}`"));
+                // emitted. (#64638)
+                assert!(self.tcx().dcx().has_errors().is_some(), "bad base: `{base:?}`");
             }
             if let Some(base_ty) = base_ty
                 && let ty::Ref(_, base_ty_inner, _) = *base_ty.kind()
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index 6137506d4a994..c39d0425f7e25 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -802,14 +802,12 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
         }
 
         // Errors in earlier passes can yield error variables without
-        // resolution errors here; delay ICE in favor of those errors.
-        self.tcx().dcx().span_delayed_bug(
-            self.var_infos[node_idx].origin.span(),
-            format!(
-                "collect_error_for_expanding_node() could not find \
-                 error for var {node_idx:?} in universe {node_universe:?}, lower_bounds={lower_bounds:#?}, \
-                 upper_bounds={upper_bounds:#?}"
-            ),
+        // resolution errors here; ICE if no errors have been emitted yet.
+        assert!(
+            self.tcx().dcx().has_errors().is_some(),
+            "collect_error_for_expanding_node() could not find error for var {node_idx:?} in \
+            universe {node_universe:?}, lower_bounds={lower_bounds:#?}, \
+            upper_bounds={upper_bounds:#?}",
         );
     }
 
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index 7208f17fb340f..c0a99e5cc4177 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -300,9 +300,9 @@ where
                     self.components_must_outlive(origin, subcomponents, region, category);
                 }
                 Component::UnresolvedInferenceVariable(v) => {
-                    // ignore this, we presume it will yield an error
-                    // later, since if a type variable is not resolved by
-                    // this point it never will be
+                    // Ignore this, we presume it will yield an error later,
+                    // since if a type variable is not resolved by this point
+                    // it never will be.
                     self.tcx.dcx().span_delayed_bug(
                         origin.span(),
                         format!("unresolved inference variable in outlives: {v:?}"),
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index 24b351988bf69..3ef37bf3466f1 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -172,13 +172,13 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
                 self.bound_from_components(components, visited)
             }
             Component::UnresolvedInferenceVariable(v) => {
-                // ignore this, we presume it will yield an error
-                // later, since if a type variable is not resolved by
-                // this point it never will be
+                // Ignore this, we presume it will yield an error later, since
+                // if a type variable is not resolved by this point it never
+                // will be.
                 self.tcx
                     .dcx()
                     .delayed_bug(format!("unresolved inference variable in outlives: {v:?}"));
-                // add a bound that never holds
+                // Add a bound that never holds.
                 VerifyBound::AnyBound(vec![])
             }
         }
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 5ae080d470235..0862204d88e2d 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -431,14 +431,13 @@ pub fn check_ast_node_inner<'a, T: EarlyLintPass>(
     // If not, that means that we somehow buffered a lint for a node id
     // that was not lint-checked (perhaps it doesn't exist?). This is a bug.
     for (id, lints) in cx.context.buffered.map {
-        for early_lint in lints {
-            sess.dcx().span_delayed_bug(
-                early_lint.span,
-                format!(
-                    "failed to process buffered lint here (dummy = {})",
-                    id == ast::DUMMY_NODE_ID
-                ),
+        if !lints.is_empty() {
+            assert!(
+                sess.dcx().has_errors().is_some(),
+                "failed to process buffered lint here (dummy = {})",
+                id == ast::DUMMY_NODE_ID
             );
+            break;
         }
     }
 }
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 6ffa0819f3571..2a6f473cd32f3 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -207,6 +207,11 @@ pub fn explain_lint_level_source(
     err: &mut Diagnostic,
 ) {
     let name = lint.name_lower();
+    if let Level::Allow = level {
+        // Do not point at `#[allow(compat_lint)]` as the reason for a compatibility lint
+        // triggering. (#121009)
+        return;
+    }
     match src {
         LintLevelSource::Default => {
             err.note_once(format!("`#[{}({})]` on by default", level.as_str(), name));
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 23771073745ff..5e4d899f51768 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -35,6 +35,16 @@ impl<'tcx> IntoKind for Const<'tcx> {
     }
 }
 
+impl<'tcx> rustc_type_ir::visit::Flags for Const<'tcx> {
+    fn flags(&self) -> TypeFlags {
+        self.0.flags
+    }
+
+    fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex {
+        self.0.outer_exclusive_binder
+    }
+}
+
 impl<'tcx> ConstTy<TyCtxt<'tcx>> for Const<'tcx> {
     fn ty(self) -> Ty<'tcx> {
         self.ty()
@@ -63,11 +73,13 @@ impl<'tcx> Const<'tcx> {
         self.0.kind
     }
 
+    // FIXME(compiler-errors): Think about removing this.
     #[inline]
     pub fn flags(self) -> TypeFlags {
         self.0.flags
     }
 
+    // FIXME(compiler-errors): Think about removing this.
     #[inline]
     pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex {
         self.0.outer_exclusive_binder
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index bd86c1c284e6e..61e449b8b565f 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -28,7 +28,7 @@ use crate::ty::{
     self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Const, ConstData, GenericParamDefKind,
     ImplPolarity, List, ParamConst, ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate,
     PredicateKind, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid,
-    Visibility,
+    TypeVisitable, Visibility,
 };
 use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
 use rustc_ast::{self as ast, attr};
@@ -87,7 +87,9 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     type GenericArg = ty::GenericArg<'tcx>;
     type Term = ty::Term<'tcx>;
 
-    type Binder<T> = Binder<'tcx, T>;
+    type Binder<T: TypeVisitable<TyCtxt<'tcx>>> = Binder<'tcx, T>;
+    type BoundVars = &'tcx List<ty::BoundVariableKind>;
+    type BoundVar = ty::BoundVariableKind;
     type CanonicalVars = CanonicalVarInfos<'tcx>;
 
     type Ty = Ty<'tcx>;
@@ -151,6 +153,11 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
     ) -> Self::Const {
         Const::new_bound(self, debruijn, var, ty)
     }
+
+    fn expect_error_or_delayed_bug() {
+        let has_errors = ty::tls::with(|tcx| tcx.dcx().has_errors_or_lint_errors_or_delayed_bugs());
+        assert!(has_errors.is_some());
+    }
 }
 
 type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>;
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 2d6c6cfbcd144..15bddb2a64fb8 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -504,6 +504,16 @@ impl<'tcx> IntoKind for Ty<'tcx> {
     }
 }
 
+impl<'tcx> rustc_type_ir::visit::Flags for Ty<'tcx> {
+    fn flags(&self) -> TypeFlags {
+        self.0.flags
+    }
+
+    fn outer_exclusive_binder(&self) -> DebruijnIndex {
+        self.0.outer_exclusive_binder
+    }
+}
+
 impl EarlyParamRegion {
     /// Does this early bound region have a name? Early bound regions normally
     /// always have names except when using anonymous lifetimes (`'_`).
diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs
index 200811940ed76..b63f9c6dfa01a 100644
--- a/compiler/rustc_middle/src/ty/predicate.rs
+++ b/compiler/rustc_middle/src/ty/predicate.rs
@@ -29,6 +29,16 @@ pub struct Predicate<'tcx>(
     pub(super) Interned<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>,
 );
 
+impl<'tcx> rustc_type_ir::visit::Flags for Predicate<'tcx> {
+    fn flags(&self) -> TypeFlags {
+        self.0.flags
+    }
+
+    fn outer_exclusive_binder(&self) -> ty::DebruijnIndex {
+        self.0.outer_exclusive_binder
+    }
+}
+
 impl<'tcx> Predicate<'tcx> {
     /// Gets the inner `ty::Binder<'tcx, PredicateKind<'tcx>>`.
     #[inline]
@@ -36,11 +46,13 @@ impl<'tcx> Predicate<'tcx> {
         self.0.internee
     }
 
+    // FIXME(compiler-errors): Think about removing this.
     #[inline(always)]
     pub fn flags(self) -> TypeFlags {
         self.0.flags
     }
 
+    // FIXME(compiler-errors): Think about removing this.
     #[inline(always)]
     pub fn outer_exclusive_binder(self) -> DebruijnIndex {
         self.0.outer_exclusive_binder
diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs
index 1191d7fca32a4..b206727f0514e 100644
--- a/compiler/rustc_middle/src/ty/region.rs
+++ b/compiler/rustc_middle/src/ty/region.rs
@@ -26,6 +26,19 @@ impl<'tcx> rustc_type_ir::IntoKind for Region<'tcx> {
     }
 }
 
+impl<'tcx> rustc_type_ir::visit::Flags for Region<'tcx> {
+    fn flags(&self) -> TypeFlags {
+        self.type_flags()
+    }
+
+    fn outer_exclusive_binder(&self) -> ty::DebruijnIndex {
+        match **self {
+            ty::ReBound(debruijn, _) => debruijn.shifted_in(1),
+            _ => ty::INNERMOST,
+        }
+    }
+}
+
 impl<'tcx> Region<'tcx> {
     #[inline]
     pub fn new_early_param(
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index a3d5f1f195510..ae6544b9dbea0 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -942,6 +942,16 @@ where
     }
 }
 
+impl<'tcx, T> rustc_type_ir::BoundVars<TyCtxt<'tcx>> for ty::Binder<'tcx, T> {
+    fn bound_vars(&self) -> &'tcx List<ty::BoundVariableKind> {
+        self.bound_vars
+    }
+
+    fn has_no_bound_vars(&self) -> bool {
+        self.bound_vars.is_empty()
+    }
+}
+
 impl<'tcx, T> Binder<'tcx, T> {
     /// Skips the binder and returns the "bound" value. This is a
     /// risky thing to do because it's easy to get confused about
@@ -1808,6 +1818,7 @@ impl<'tcx> Ty<'tcx> {
         self.0.0
     }
 
+    // FIXME(compiler-errors): Think about removing this.
     #[inline(always)]
     pub fn flags(self) -> TypeFlags {
         self.0.0.flags
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index c674a868d9fa2..09bb06de483a8 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -1320,6 +1320,7 @@ impl<'tcx> Ty<'tcx> {
         ty
     }
 
+    // FIXME(compiler-errors): Think about removing this.
     #[inline]
     pub fn outer_exclusive_binder(self) -> ty::DebruijnIndex {
         self.0.outer_exclusive_binder
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index 7acdb931f1ae7..59292a281edec 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -1,140 +1,10 @@
 use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags};
-use rustc_errors::ErrorGuaranteed;
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sso::SsoHashSet;
 use std::ops::ControlFlow;
 
-pub use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
-
-pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
-    /// Returns `true` if `self` has any late-bound regions that are either
-    /// bound by `binder` or bound by some binder outside of `binder`.
-    /// If `binder` is `ty::INNERMOST`, this indicates whether
-    /// there are any late-bound regions that appear free.
-    fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
-        self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }).is_break()
-    }
-
-    /// Returns `true` if this type has any regions that escape `binder` (and
-    /// hence are not bound by it).
-    fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool {
-        self.has_vars_bound_at_or_above(binder.shifted_in(1))
-    }
-
-    /// Return `true` if this type has regions that are not a part of the type.
-    /// For example, `for<'a> fn(&'a i32)` return `false`, while `fn(&'a i32)`
-    /// would return `true`. The latter can occur when traversing through the
-    /// former.
-    ///
-    /// See [`HasEscapingVarsVisitor`] for more information.
-    fn has_escaping_bound_vars(&self) -> bool {
-        self.has_vars_bound_at_or_above(ty::INNERMOST)
-    }
-
-    fn has_type_flags(&self, flags: TypeFlags) -> bool {
-        let res =
-            self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags);
-        trace!(?self, ?flags, ?res, "has_type_flags");
-        res
-    }
-    fn has_projections(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_PROJECTION)
-    }
-    fn has_inherent_projections(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_TY_INHERENT)
-    }
-    fn has_opaque_types(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
-    }
-    fn has_coroutines(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_TY_COROUTINE)
-    }
-    fn references_error(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_ERROR)
-    }
-    fn error_reported(&self) -> Result<(), ErrorGuaranteed> {
-        if self.references_error() {
-            // We must include lint errors and delayed bugs here.
-            if let Some(reported) =
-                ty::tls::with(|tcx| tcx.dcx().has_errors_or_lint_errors_or_delayed_bugs())
-            {
-                Err(reported)
-            } else {
-                bug!("expected some kind of error in `error_reported`");
-            }
-        } else {
-            Ok(())
-        }
-    }
-    fn has_non_region_param(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_PARAM - TypeFlags::HAS_RE_PARAM)
-    }
-    fn has_infer_regions(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_RE_INFER)
-    }
-    fn has_infer_types(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_TY_INFER)
-    }
-    fn has_non_region_infer(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_INFER - TypeFlags::HAS_RE_INFER)
-    }
-    fn has_infer(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_INFER)
-    }
-    fn has_placeholders(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_PLACEHOLDER)
-    }
-    fn has_non_region_placeholders(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_PLACEHOLDER - TypeFlags::HAS_RE_PLACEHOLDER)
-    }
-    fn has_param(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_PARAM)
-    }
-    /// "Free" regions in this context means that it has any region
-    /// that is not (a) erased or (b) late-bound.
-    fn has_free_regions(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
-    }
-
-    fn has_erased_regions(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_RE_ERASED)
-    }
-
-    /// True if there are any un-erased free regions.
-    fn has_erasable_regions(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
-    }
-
-    /// Indicates whether this value references only 'global'
-    /// generic parameters that are the same regardless of what fn we are
-    /// in. This is used for caching.
-    fn is_global(&self) -> bool {
-        !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
-    }
-
-    /// True if there are any late-bound regions
-    fn has_bound_regions(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_RE_BOUND)
-    }
-    /// True if there are any late-bound non-region variables
-    fn has_non_region_bound_vars(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_BOUND_VARS - TypeFlags::HAS_RE_BOUND)
-    }
-    /// True if there are any bound variables
-    fn has_bound_vars(&self) -> bool {
-        self.has_type_flags(TypeFlags::HAS_BOUND_VARS)
-    }
-
-    /// Indicates whether this value still has parameters/placeholders/inference variables
-    /// which could be replaced later, in a way that would change the results of `impl`
-    /// specialization.
-    fn still_further_specializable(&self) -> bool {
-        self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE)
-    }
-}
-
-impl<'tcx, T: TypeVisitable<TyCtxt<'tcx>>> TypeVisitableExt<'tcx> for T {}
+pub use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
 
 ///////////////////////////////////////////////////////////////////////////
 // Region folder
@@ -370,185 +240,6 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ValidateBoundVars<'tcx> {
     }
 }
 
-#[derive(Debug, PartialEq, Eq, Copy, Clone)]
-struct FoundEscapingVars;
-
-/// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a
-/// bound region or a bound type.
-///
-/// So, for example, consider a type like the following, which has two binders:
-///
-///    for<'a> fn(x: for<'b> fn(&'a isize, &'b isize))
-///    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope
-///                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~  inner scope
-///
-/// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the
-/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner
-/// fn type*, that type has an escaping region: `'a`.
-///
-/// Note that what I'm calling an "escaping var" is often just called a "free var". However,
-/// we already use the term "free var". It refers to the regions or types that we use to represent
-/// bound regions or type params on a fn definition while we are type checking its body.
-///
-/// To clarify, conceptually there is no particular difference between
-/// an "escaping" var and a "free" var. However, there is a big
-/// difference in practice. Basically, when "entering" a binding
-/// level, one is generally required to do some sort of processing to
-/// a bound var, such as replacing it with a fresh/placeholder
-/// var, or making an entry in the environment to represent the
-/// scope to which it is attached, etc. An escaping var represents
-/// a bound var for which this processing has not yet been done.
-struct HasEscapingVarsVisitor {
-    /// Anything bound by `outer_index` or "above" is escaping.
-    outer_index: ty::DebruijnIndex,
-}
-
-impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasEscapingVarsVisitor {
-    type BreakTy = FoundEscapingVars;
-
-    fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
-        &mut self,
-        t: &Binder<'tcx, T>,
-    ) -> ControlFlow<Self::BreakTy> {
-        self.outer_index.shift_in(1);
-        let result = t.super_visit_with(self);
-        self.outer_index.shift_out(1);
-        result
-    }
-
-    #[inline]
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        // If the outer-exclusive-binder is *strictly greater* than
-        // `outer_index`, that means that `t` contains some content
-        // bound at `outer_index` or above (because
-        // `outer_exclusive_binder` is always 1 higher than the
-        // content in `t`). Therefore, `t` has some escaping vars.
-        if t.outer_exclusive_binder() > self.outer_index {
-            ControlFlow::Break(FoundEscapingVars)
-        } else {
-            ControlFlow::Continue(())
-        }
-    }
-
-    #[inline]
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-        // If the region is bound by `outer_index` or anything outside
-        // of outer index, then it escapes the binders we have
-        // visited.
-        if r.bound_at_or_above_binder(self.outer_index) {
-            ControlFlow::Break(FoundEscapingVars)
-        } else {
-            ControlFlow::Continue(())
-        }
-    }
-
-    fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-        // If the outer-exclusive-binder is *strictly greater* than
-        // `outer_index`, that means that `ct` contains some content
-        // bound at `outer_index` or above (because
-        // `outer_exclusive_binder` is always 1 higher than the
-        // content in `t`). Therefore, `t` has some escaping vars.
-        if ct.outer_exclusive_binder() > self.outer_index {
-            ControlFlow::Break(FoundEscapingVars)
-        } else {
-            ControlFlow::Continue(())
-        }
-    }
-
-    #[inline]
-    fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
-        if predicate.outer_exclusive_binder() > self.outer_index {
-            ControlFlow::Break(FoundEscapingVars)
-        } else {
-            ControlFlow::Continue(())
-        }
-    }
-}
-
-#[derive(Debug, PartialEq, Eq, Copy, Clone)]
-struct FoundFlags;
-
-// FIXME: Optimize for checking for infer flags
-struct HasTypeFlagsVisitor {
-    flags: ty::TypeFlags,
-}
-
-impl std::fmt::Debug for HasTypeFlagsVisitor {
-    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        self.flags.fmt(fmt)
-    }
-}
-
-// Note: this visitor traverses values down to the level of
-// `Ty`/`Const`/`Predicate`, but not within those types. This is because the
-// type flags at the outer layer are enough. So it's faster than it first
-// looks, particular for `Ty`/`Predicate` where it's just a field access.
-//
-// N.B. The only case where this isn't totally true is binders, which also
-// add `HAS_{RE,TY,CT}_LATE_BOUND` flag depending on the *bound variables* that
-// are present, regardless of whether those bound variables are used. This
-// is important for anonymization of binders in `TyCtxt::erase_regions`. We
-// specifically detect this case in `visit_binder`.
-impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for HasTypeFlagsVisitor {
-    type BreakTy = FoundFlags;
-
-    fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
-        &mut self,
-        t: &Binder<'tcx, T>,
-    ) -> ControlFlow<Self::BreakTy> {
-        // If we're looking for the HAS_BINDER_VARS flag, check if the
-        // binder has vars. This won't be present in the binder's bound
-        // value, so we need to check here too.
-        if self.flags.intersects(TypeFlags::HAS_BINDER_VARS) && !t.bound_vars().is_empty() {
-            return ControlFlow::Break(FoundFlags);
-        }
-
-        t.super_visit_with(self)
-    }
-
-    #[inline]
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
-        // Note: no `super_visit_with` call.
-        let flags = t.flags();
-        if flags.intersects(self.flags) {
-            ControlFlow::Break(FoundFlags)
-        } else {
-            ControlFlow::Continue(())
-        }
-    }
-
-    #[inline]
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
-        // Note: no `super_visit_with` call, as usual for `Region`.
-        let flags = r.type_flags();
-        if flags.intersects(self.flags) {
-            ControlFlow::Break(FoundFlags)
-        } else {
-            ControlFlow::Continue(())
-        }
-    }
-
-    #[inline]
-    fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
-        // Note: no `super_visit_with` call.
-        if c.flags().intersects(self.flags) {
-            ControlFlow::Break(FoundFlags)
-        } else {
-            ControlFlow::Continue(())
-        }
-    }
-
-    #[inline]
-    fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ControlFlow<Self::BreakTy> {
-        // Note: no `super_visit_with` call.
-        if predicate.flags().intersects(self.flags) {
-            ControlFlow::Break(FoundFlags)
-        } else {
-            ControlFlow::Continue(())
-        }
-    }
-}
-
 /// Collects all the late-bound regions at the innermost binding level
 /// into a hash set.
 struct LateBoundRegionsCollector {
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 8688c58906331..241b6c6cb2cad 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -33,7 +33,7 @@ struct UnsafetyVisitor<'a, 'tcx> {
     body_target_features: &'tcx [Symbol],
     /// When inside the LHS of an assignment to a field, this is the type
     /// of the LHS and the span of the assignment expression.
-    assignment_info: Option<(Ty<'tcx>, Span)>,
+    assignment_info: Option<Ty<'tcx>>,
     in_union_destructure: bool,
     param_env: ParamEnv<'tcx>,
     inside_adt: bool,
@@ -473,10 +473,15 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                 if let ty::Adt(adt_def, _) = lhs.ty.kind()
                     && adt_def.is_union()
                 {
-                    if let Some((assigned_ty, assignment_span)) = self.assignment_info {
+                    if let Some(assigned_ty) = self.assignment_info {
                         if assigned_ty.needs_drop(self.tcx, self.param_env) {
-                            // This would be unsafe, but should be outright impossible since we reject such unions.
-                            self.tcx.dcx().span_delayed_bug(assignment_span, format!("union fields that need dropping should be impossible: {assigned_ty}"));
+                            // This would be unsafe, but should be outright impossible since we
+                            // reject such unions.
+                            assert!(
+                                self.tcx.dcx().has_errors().is_some(),
+                                "union fields that need dropping should be impossible: \
+                                {assigned_ty}"
+                            );
                         }
                     } else {
                         self.requires_unsafe(expr.span, AccessToUnionField);
@@ -492,14 +497,15 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                     self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField);
                 }
 
-                // Second, check for accesses to union fields
-                // don't have any special handling for AssignOp since it causes a read *and* write to lhs
+                // Second, check for accesses to union fields. Don't have any
+                // special handling for AssignOp since it causes a read *and*
+                // write to lhs.
                 if matches!(expr.kind, ExprKind::Assign { .. }) {
-                    self.assignment_info = Some((lhs.ty, expr.span));
+                    self.assignment_info = Some(lhs.ty);
                     visit::walk_expr(self, lhs);
                     self.assignment_info = None;
                     visit::walk_expr(self, &self.thir()[rhs]);
-                    return; // we have already visited everything by now
+                    return; // We have already visited everything by now.
                 }
             }
             ExprKind::Borrow { borrow_kind, arg } => {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 18a00724c3d0e..c77c80d9f4b29 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -153,8 +153,7 @@ impl<'tcx> ConstToPat<'tcx> {
             // a hard error when we don't have a valtree or when we find something in
             // the valtree that is not structural; then this can all be made a lot simpler.
 
-            let structural =
-                traits::search_for_structural_match_violation(self.span, self.tcx(), cv.ty());
+            let structural = traits::search_for_structural_match_violation(self.tcx(), cv.ty());
             debug!(
                 "search_for_structural_match_violation cv.ty: {:?} returned: {:?}",
                 cv.ty(),
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index fbb626953835e..a0c3de3af5862 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -243,10 +243,11 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
                     // old value is being dropped.
                     let assigned_ty = place.ty(&self.body.local_decls, self.tcx).ty;
                     if assigned_ty.needs_drop(self.tcx, self.param_env) {
-                        // This would be unsafe, but should be outright impossible since we reject such unions.
-                        self.tcx.dcx().span_delayed_bug(
-                            self.source_info.span,
-                            format!("union fields that need dropping should be impossible: {assigned_ty}")
+                        // This would be unsafe, but should be outright impossible since we reject
+                        // such unions.
+                        assert!(
+                            self.tcx.dcx().has_errors().is_some(),
+                            "union fields that need dropping should be impossible: {assigned_ty}"
                         );
                     }
                 } else {
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 8d4afd5b5dce5..370f0db72cb78 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -561,9 +561,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                         .ok()?;
                     dest.into()
                 }
-                CastKind::FnPtrToPtr
-                | CastKind::PtrToPtr
-                | CastKind::PointerCoercion(
+                CastKind::FnPtrToPtr | CastKind::PtrToPtr => {
+                    let src = self.evaluated[value].as_ref()?;
+                    let src = self.ecx.read_immediate(src).ok()?;
+                    let to = self.ecx.layout_of(to).ok()?;
+                    let ret = self.ecx.ptr_to_ptr(&src, to).ok()?;
+                    ret.into()
+                }
+                CastKind::PointerCoercion(
                     ty::adjustment::PointerCoercion::MutToConstPointer
                     | ty::adjustment::PointerCoercion::ArrayToPointer
                     | ty::adjustment::PointerCoercion::UnsafeFnPointer,
@@ -571,8 +576,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                     let src = self.evaluated[value].as_ref()?;
                     let src = self.ecx.read_immediate(src).ok()?;
                     let to = self.ecx.layout_of(to).ok()?;
-                    let ret = self.ecx.ptr_to_ptr(&src, to).ok()?;
-                    ret.into()
+                    ImmTy::from_immediate(*src, to).into()
                 }
                 _ => return None,
             },
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 9f30f2836f195..c11fd5fcc90c5 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -265,7 +265,7 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs {
     let body = &tcx.mir_const(def).borrow();
 
     if body.return_ty().references_error() {
-        tcx.dcx().span_delayed_bug(body.span, "mir_const_qualif: MIR had errors");
+        assert!(tcx.dcx().has_errors().is_some(), "mir_const_qualif: MIR had errors");
         return Default::default();
     }
 
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index 42edbeaa622c2..cd434fecce2cb 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -1,6 +1,7 @@
 use std::cmp::Ordering;
 
 use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
+use rustc_type_ir::visit::TypeVisitableExt;
 use rustc_type_ir::{
     self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, ConstTy,
     InferCtxtLike, Interner, IntoKind, PlaceholderLike,
@@ -62,8 +63,8 @@ impl<'a, Infcx: InferCtxtLike<Interner = I>, I: Interner> Canonicalizer<'a, Infc
 
         let value = value.fold_with(&mut canonicalizer);
         // FIXME: Restore these assertions. Should we uplift type flags?
-        // assert!(!value.has_infer(), "unexpected infer in {value:?}");
-        // assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}");
+        assert!(!value.has_infer(), "unexpected infer in {value:?}");
+        assert!(!value.has_placeholders(), "unexpected placeholders in {value:?}");
 
         let (max_universe, variables) = canonicalizer.finalize();
 
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 9158ba00901c6..754757b5de539 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -429,16 +429,16 @@ where
             let formatter = query.format_value();
             if old_hash != new_hash {
                 // We have an inconsistency. This can happen if one of the two
-                // results is tainted by errors. In this case, delay a bug to
-                // ensure compilation is doomed.
-                qcx.dep_context().sess().dcx().delayed_bug(format!(
+                // results is tainted by errors.
+                assert!(
+                    qcx.dep_context().sess().dcx().has_errors().is_some(),
                     "Computed query value for {:?}({:?}) is inconsistent with fed value,\n\
                         computed={:#?}\nfed={:#?}",
                     query.dep_kind(),
                     key,
                     formatter(&result),
                     formatter(&cached_result),
-                ));
+                );
             }
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 522c645253a21..1edf6b11fc343 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -62,9 +62,10 @@ pub fn is_const_evaluatable<'tcx>(
 
         match unexpanded_ct.kind() {
             ty::ConstKind::Expr(_) => {
-                // FIXME(generic_const_exprs): we have a `ConstKind::Expr` which is fully concrete, but
-                // currently it is not possible to evaluate `ConstKind::Expr` so we are unable to tell if it
-                // is evaluatable or not. For now we just ICE until this is implemented.
+                // FIXME(generic_const_exprs): we have a `ConstKind::Expr` which is fully concrete,
+                // but currently it is not possible to evaluate `ConstKind::Expr` so we are unable
+                // to tell if it is evaluatable or not. For now we just ICE until this is
+                // implemented.
                 Err(NotConstEvaluatable::Error(tcx.dcx().span_delayed_bug(
                     span,
                     "evaluating `ConstKind::Expr` is not currently supported",
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index c7b56aac7e55b..335e6ff28226e 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -3041,7 +3041,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             this = "the implicit `Sized` requirement on this type parameter";
                         }
                         if let Some(hir::Node::TraitItem(hir::TraitItem {
-                            ident,
+                            generics,
                             kind: hir::TraitItemKind::Type(bounds, None),
                             ..
                         })) = tcx.hir().get_if_local(item_def_id)
@@ -3053,7 +3053,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             let (span, separator) = if let [.., last] = bounds {
                                 (last.span().shrink_to_hi(), " +")
                             } else {
-                                (ident.span.shrink_to_hi(), ":")
+                                (generics.span.shrink_to_hi(), ":")
                             };
                             err.span_suggestion_verbose(
                                 span,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index c5ee03916825c..2c8d3fc9de241 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -236,9 +236,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             }
         }
 
-        // It could be that we don't report an error because we have seen an `ErrorReported` from another source.
-        // We should probably be able to fix most of these, but some are delayed bugs that get a proper error
-        // after this function.
+        // It could be that we don't report an error because we have seen an `ErrorReported` from
+        // another source. We should probably be able to fix most of these, but some are delayed
+        // bugs that get a proper error after this function.
         reported.unwrap_or_else(|| self.dcx().delayed_bug("failed to report fulfillment errors"))
     }
 
@@ -519,7 +519,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 trait_ref,
                                 span,
                             ) {
-                                GetSafeTransmuteErrorAndReason::Silent => return self.dcx().span_delayed_bug(span, "silent safe transmute error"),
+                                GetSafeTransmuteErrorAndReason::Silent => {
+                                    return self.dcx().span_delayed_bug(
+                                        span, "silent safe transmute error"
+                                    );
+                                }
                                 GetSafeTransmuteErrorAndReason::Error {
                                     err_msg,
                                     safe_transmute_explanation,
@@ -2990,7 +2994,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         {
             (s, " +")
         } else {
-            (span.shrink_to_hi(), ":")
+            (param.name.ident().span.shrink_to_hi(), ":")
         };
         err.span_suggestion_verbose(
             span,
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 29a4a078fe03f..7b715984c2b27 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -555,7 +555,7 @@ fn virtual_call_violations_for_method<'tcx>(
 
     // NOTE: This check happens last, because it results in a lint, and not a
     // hard error.
-    if tcx.predicates_of(method.def_id).predicates.iter().any(|&(pred, span)| {
+    if tcx.predicates_of(method.def_id).predicates.iter().any(|&(pred, _span)| {
         // dyn Trait is okay:
         //
         //     trait Trait {
@@ -594,7 +594,10 @@ fn virtual_call_violations_for_method<'tcx>(
             // would already have reported an error at the definition of the
             // auto trait.
             if pred_trait_ref.args.len() != 1 {
-                tcx.dcx().span_delayed_bug(span, "auto traits cannot have generic parameters");
+                assert!(
+                    tcx.dcx().has_errors().is_some(),
+                    "auto traits cannot have generic parameters"
+                );
             }
             return false;
         }
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index 89459f377dd2b..e6b42f15d5140 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -1,7 +1,6 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
-use rustc_span::Span;
 use std::ops::ControlFlow;
 
 /// This method traverses the structure of `ty`, trying to find an
@@ -30,19 +29,16 @@ use std::ops::ControlFlow;
 /// that arose when the requirement was not enforced completely, see
 /// Rust RFC 1445, rust-lang/rust#61188, and rust-lang/rust#62307.
 pub fn search_for_structural_match_violation<'tcx>(
-    span: Span,
     tcx: TyCtxt<'tcx>,
     ty: Ty<'tcx>,
 ) -> Option<Ty<'tcx>> {
-    ty.visit_with(&mut Search { tcx, span, seen: FxHashSet::default() }).break_value()
+    ty.visit_with(&mut Search { tcx, seen: FxHashSet::default() }).break_value()
 }
 
 /// This implements the traversal over the structure of a given type to try to
 /// find instances of ADTs (specifically structs or enums) that do not implement
 /// `StructuralPartialEq`.
 struct Search<'tcx> {
-    span: Span,
-
     tcx: TyCtxt<'tcx>,
 
     /// Tracks ADTs previously encountered during search, so that
@@ -138,7 +134,6 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Search<'tcx> {
                 bug!("unexpected type during structural-match checking: {:?}", ty);
             }
             ty::Error(_) => {
-                self.tcx.dcx().span_delayed_bug(self.span, "ty::Error in structural-match check");
                 // We still want to check other types after encountering an error,
                 // as this may still emit relevant errors.
                 return ControlFlow::Continue(());
diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs
new file mode 100644
index 0000000000000..57f961ac97ec5
--- /dev/null
+++ b/compiler/rustc_type_ir/src/binder.rs
@@ -0,0 +1,7 @@
+use crate::Interner;
+
+pub trait BoundVars<I: Interner> {
+    fn bound_vars(&self) -> I::BoundVars;
+
+    fn has_no_bound_vars(&self) -> bool;
+}
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 188910ecc52d1..7728ee0e842a8 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -2,9 +2,10 @@ use smallvec::SmallVec;
 use std::fmt::Debug;
 use std::hash::Hash;
 
+use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
 use crate::{
-    BoundVar, CanonicalVarInfo, ConstKind, DebruijnIndex, DebugWithInfcx, RegionKind, TyKind,
-    UniverseIndex,
+    BoundVar, BoundVars, CanonicalVarInfo, ConstKind, DebruijnIndex, DebugWithInfcx, RegionKind,
+    TyKind, UniverseIndex,
 };
 
 pub trait Interner: Sized {
@@ -19,7 +20,10 @@ pub trait Interner: Sized {
     type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Ord;
     type Term: Copy + Debug + Hash + Ord;
 
-    type Binder<T>;
+    type Binder<T: TypeVisitable<Self>>: BoundVars<Self> + TypeSuperVisitable<Self>;
+    type BoundVars: IntoIterator<Item = Self::BoundVar>;
+    type BoundVar;
+
     type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator<Item = CanonicalVarInfo<Self>>;
 
     // Kinds of tys
@@ -28,7 +32,9 @@ pub trait Interner: Sized {
         + Hash
         + Ord
         + Into<Self::GenericArg>
-        + IntoKind<Kind = TyKind<Self>>;
+        + IntoKind<Kind = TyKind<Self>>
+        + TypeSuperVisitable<Self>
+        + Flags;
     type Tys: Copy + Debug + Hash + Ord + IntoIterator<Item = Self::Ty>;
     type AliasTy: Copy + DebugWithInfcx<Self> + Hash + Ord;
     type ParamTy: Copy + Debug + Hash + Ord;
@@ -48,7 +54,9 @@ pub trait Interner: Sized {
         + Ord
         + Into<Self::GenericArg>
         + IntoKind<Kind = ConstKind<Self>>
-        + ConstTy<Self>;
+        + ConstTy<Self>
+        + TypeSuperVisitable<Self>
+        + Flags;
     type AliasConst: Copy + DebugWithInfcx<Self> + Hash + Ord;
     type PlaceholderConst: Copy + Debug + Hash + Ord + PlaceholderLike;
     type ParamConst: Copy + Debug + Hash + Ord;
@@ -62,7 +70,8 @@ pub trait Interner: Sized {
         + Hash
         + Ord
         + Into<Self::GenericArg>
-        + IntoKind<Kind = RegionKind<Self>>;
+        + IntoKind<Kind = RegionKind<Self>>
+        + Flags;
     type EarlyParamRegion: Copy + Debug + Hash + Ord;
     type LateParamRegion: Copy + Debug + Hash + Ord;
     type BoundRegion: Copy + Debug + Hash + Ord;
@@ -70,7 +79,7 @@ pub trait Interner: Sized {
     type PlaceholderRegion: Copy + Debug + Hash + Ord + PlaceholderLike;
 
     // Predicates
-    type Predicate: Copy + Debug + Hash + Eq;
+    type Predicate: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags;
     type TraitPredicate: Copy + Debug + Hash + Eq;
     type RegionOutlivesPredicate: Copy + Debug + Hash + Eq;
     type TypeOutlivesPredicate: Copy + Debug + Hash + Eq;
@@ -86,6 +95,9 @@ pub trait Interner: Sized {
     fn mk_bound_ty(self, debruijn: DebruijnIndex, var: BoundVar) -> Self::Ty;
     fn mk_bound_region(self, debruijn: DebruijnIndex, var: BoundVar) -> Self::Region;
     fn mk_bound_const(self, debruijn: DebruijnIndex, var: BoundVar, ty: Self::Ty) -> Self::Const;
+
+    /// Assert that an error has been delayed or emitted.
+    fn expect_error_or_delayed_bug();
 }
 
 /// Common capabilities of placeholder kinds
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index f498c5531fcff..94ccbcbd8a570 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -30,6 +30,7 @@ pub mod visit;
 
 #[macro_use]
 mod macros;
+mod binder;
 mod canonical;
 mod const_kind;
 mod debug;
@@ -39,6 +40,7 @@ mod interner;
 mod predicate_kind;
 mod region_kind;
 
+pub use binder::*;
 pub use canonical::*;
 #[cfg(feature = "nightly")]
 pub use codec::*;
diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs
index 7aa990046675f..638fb9f7fa9db 100644
--- a/compiler/rustc_type_ir/src/visit.rs
+++ b/compiler/rustc_type_ir/src/visit.rs
@@ -45,8 +45,7 @@ use rustc_index::{Idx, IndexVec};
 use std::fmt;
 use std::ops::ControlFlow;
 
-use crate::Interner;
-use crate::Lrc;
+use crate::{self as ty, BoundVars, Interner, IntoKind, Lrc, TypeFlags};
 
 /// This trait is implemented for every type that can be visited,
 /// providing the skeleton of the traversal.
@@ -88,38 +87,28 @@ pub trait TypeVisitor<I: Interner>: Sized {
     #[cfg(not(feature = "nightly"))]
     type BreakTy;
 
-    fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &I::Binder<T>) -> ControlFlow<Self::BreakTy>
-    where
-        I::Binder<T>: TypeSuperVisitable<I>,
-    {
+    fn visit_binder<T: TypeVisitable<I>>(
+        &mut self,
+        t: &I::Binder<T>,
+    ) -> ControlFlow<Self::BreakTy> {
         t.super_visit_with(self)
     }
 
-    fn visit_ty(&mut self, t: I::Ty) -> ControlFlow<Self::BreakTy>
-    where
-        I::Ty: TypeSuperVisitable<I>,
-    {
+    fn visit_ty(&mut self, t: I::Ty) -> ControlFlow<Self::BreakTy> {
         t.super_visit_with(self)
     }
 
     // The default region visitor is a no-op because `Region` is non-recursive
-    // and has no `super_visit_with` method to call. That also explains the
-    // lack of `I::Region: TypeSuperVisitable<I>` bound.
+    // and has no `super_visit_with` method to call.
     fn visit_region(&mut self, _r: I::Region) -> ControlFlow<Self::BreakTy> {
         ControlFlow::Continue(())
     }
 
-    fn visit_const(&mut self, c: I::Const) -> ControlFlow<Self::BreakTy>
-    where
-        I::Const: TypeSuperVisitable<I>,
-    {
+    fn visit_const(&mut self, c: I::Const) -> ControlFlow<Self::BreakTy> {
         c.super_visit_with(self)
     }
 
-    fn visit_predicate(&mut self, p: I::Predicate) -> ControlFlow<Self::BreakTy>
-    where
-        I::Predicate: TypeSuperVisitable<I>,
-    {
+    fn visit_predicate(&mut self, p: I::Predicate) -> ControlFlow<Self::BreakTy> {
         p.super_visit_with(self)
     }
 }
@@ -200,3 +189,363 @@ impl<I: Interner, T: TypeVisitable<I>, Ix: Idx> TypeVisitable<I> for IndexVec<Ix
         self.iter().try_for_each(|t| t.visit_with(visitor))
     }
 }
+
+pub trait Flags {
+    fn flags(&self) -> TypeFlags;
+    fn outer_exclusive_binder(&self) -> ty::DebruijnIndex;
+}
+
+pub trait TypeVisitableExt<I: Interner>: TypeVisitable<I> {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool;
+
+    /// Returns `true` if `self` has any late-bound regions that are either
+    /// bound by `binder` or bound by some binder outside of `binder`.
+    /// If `binder` is `ty::INNERMOST`, this indicates whether
+    /// there are any late-bound regions that appear free.
+    fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool;
+
+    /// Returns `true` if this type has any regions that escape `binder` (and
+    /// hence are not bound by it).
+    fn has_vars_bound_above(&self, binder: ty::DebruijnIndex) -> bool {
+        self.has_vars_bound_at_or_above(binder.shifted_in(1))
+    }
+
+    /// Return `true` if this type has regions that are not a part of the type.
+    /// For example, `for<'a> fn(&'a i32)` return `false`, while `fn(&'a i32)`
+    /// would return `true`. The latter can occur when traversing through the
+    /// former.
+    ///
+    /// See [`HasEscapingVarsVisitor`] for more information.
+    fn has_escaping_bound_vars(&self) -> bool {
+        self.has_vars_bound_at_or_above(ty::INNERMOST)
+    }
+
+    fn has_projections(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_PROJECTION)
+    }
+
+    fn has_inherent_projections(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_TY_INHERENT)
+    }
+
+    fn has_opaque_types(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
+    }
+
+    fn has_coroutines(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_TY_COROUTINE)
+    }
+
+    fn references_error(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_ERROR)
+    }
+
+    fn error_reported(&self) -> Result<(), I::ErrorGuaranteed>;
+
+    fn has_non_region_param(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_PARAM - TypeFlags::HAS_RE_PARAM)
+    }
+
+    fn has_infer_regions(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_RE_INFER)
+    }
+
+    fn has_infer_types(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_TY_INFER)
+    }
+
+    fn has_non_region_infer(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_INFER - TypeFlags::HAS_RE_INFER)
+    }
+
+    fn has_infer(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_INFER)
+    }
+
+    fn has_placeholders(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_PLACEHOLDER)
+    }
+
+    fn has_non_region_placeholders(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_PLACEHOLDER - TypeFlags::HAS_RE_PLACEHOLDER)
+    }
+
+    fn has_param(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_PARAM)
+    }
+
+    /// "Free" regions in this context means that it has any region
+    /// that is not (a) erased or (b) late-bound.
+    fn has_free_regions(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
+    }
+
+    fn has_erased_regions(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_RE_ERASED)
+    }
+
+    /// True if there are any un-erased free regions.
+    fn has_erasable_regions(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_FREE_REGIONS)
+    }
+
+    /// Indicates whether this value references only 'global'
+    /// generic parameters that are the same regardless of what fn we are
+    /// in. This is used for caching.
+    fn is_global(&self) -> bool {
+        !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES)
+    }
+
+    /// True if there are any late-bound regions
+    fn has_bound_regions(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_RE_BOUND)
+    }
+    /// True if there are any late-bound non-region variables
+    fn has_non_region_bound_vars(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_BOUND_VARS - TypeFlags::HAS_RE_BOUND)
+    }
+    /// True if there are any bound variables
+    fn has_bound_vars(&self) -> bool {
+        self.has_type_flags(TypeFlags::HAS_BOUND_VARS)
+    }
+
+    /// Indicates whether this value still has parameters/placeholders/inference variables
+    /// which could be replaced later, in a way that would change the results of `impl`
+    /// specialization.
+    fn still_further_specializable(&self) -> bool {
+        self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE)
+    }
+}
+
+impl<I: Interner, T: TypeVisitable<I>> TypeVisitableExt<I> for T {
+    fn has_type_flags(&self, flags: TypeFlags) -> bool {
+        let res =
+            self.visit_with(&mut HasTypeFlagsVisitor { flags }) == ControlFlow::Break(FoundFlags);
+        res
+    }
+
+    fn has_vars_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool {
+        self.visit_with(&mut HasEscapingVarsVisitor { outer_index: binder }).is_break()
+    }
+
+    fn error_reported(&self) -> Result<(), I::ErrorGuaranteed> {
+        if self.references_error() {
+            if let ControlFlow::Break(guar) = self.visit_with(&mut HasErrorVisitor) {
+                Err(guar)
+            } else {
+                panic!("type flags said there was an error, but now there is not")
+            }
+        } else {
+            Ok(())
+        }
+    }
+}
+
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
+struct FoundFlags;
+
+// FIXME: Optimize for checking for infer flags
+struct HasTypeFlagsVisitor {
+    flags: ty::TypeFlags,
+}
+
+impl std::fmt::Debug for HasTypeFlagsVisitor {
+    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        self.flags.fmt(fmt)
+    }
+}
+
+// Note: this visitor traverses values down to the level of
+// `Ty`/`Const`/`Predicate`, but not within those types. This is because the
+// type flags at the outer layer are enough. So it's faster than it first
+// looks, particular for `Ty`/`Predicate` where it's just a field access.
+//
+// N.B. The only case where this isn't totally true is binders, which also
+// add `HAS_{RE,TY,CT}_LATE_BOUND` flag depending on the *bound variables* that
+// are present, regardless of whether those bound variables are used. This
+// is important for anonymization of binders in `TyCtxt::erase_regions`. We
+// specifically detect this case in `visit_binder`.
+impl<I: Interner> TypeVisitor<I> for HasTypeFlagsVisitor {
+    type BreakTy = FoundFlags;
+
+    fn visit_binder<T: TypeVisitable<I>>(
+        &mut self,
+        t: &I::Binder<T>,
+    ) -> ControlFlow<Self::BreakTy> {
+        // If we're looking for the HAS_BINDER_VARS flag, check if the
+        // binder has vars. This won't be present in the binder's bound
+        // value, so we need to check here too.
+        if self.flags.intersects(TypeFlags::HAS_BINDER_VARS) && !t.has_no_bound_vars() {
+            return ControlFlow::Break(FoundFlags);
+        }
+
+        t.super_visit_with(self)
+    }
+
+    #[inline]
+    fn visit_ty(&mut self, t: I::Ty) -> ControlFlow<Self::BreakTy> {
+        // Note: no `super_visit_with` call.
+        let flags = t.flags();
+        if flags.intersects(self.flags) {
+            ControlFlow::Break(FoundFlags)
+        } else {
+            ControlFlow::Continue(())
+        }
+    }
+
+    #[inline]
+    fn visit_region(&mut self, r: I::Region) -> ControlFlow<Self::BreakTy> {
+        // Note: no `super_visit_with` call, as usual for `Region`.
+        let flags = r.flags();
+        if flags.intersects(self.flags) {
+            ControlFlow::Break(FoundFlags)
+        } else {
+            ControlFlow::Continue(())
+        }
+    }
+
+    #[inline]
+    fn visit_const(&mut self, c: I::Const) -> ControlFlow<Self::BreakTy> {
+        // Note: no `super_visit_with` call.
+        if c.flags().intersects(self.flags) {
+            ControlFlow::Break(FoundFlags)
+        } else {
+            ControlFlow::Continue(())
+        }
+    }
+
+    #[inline]
+    fn visit_predicate(&mut self, predicate: I::Predicate) -> ControlFlow<Self::BreakTy> {
+        // Note: no `super_visit_with` call.
+        if predicate.flags().intersects(self.flags) {
+            ControlFlow::Break(FoundFlags)
+        } else {
+            ControlFlow::Continue(())
+        }
+    }
+}
+
+#[derive(Debug, PartialEq, Eq, Copy, Clone)]
+struct FoundEscapingVars;
+
+/// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a
+/// bound region or a bound type.
+///
+/// So, for example, consider a type like the following, which has two binders:
+///
+///    for<'a> fn(x: for<'b> fn(&'a isize, &'b isize))
+///    ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ outer scope
+///                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~  inner scope
+///
+/// This type has *bound regions* (`'a`, `'b`), but it does not have escaping regions, because the
+/// binders of both `'a` and `'b` are part of the type itself. However, if we consider the *inner
+/// fn type*, that type has an escaping region: `'a`.
+///
+/// Note that what I'm calling an "escaping var" is often just called a "free var". However,
+/// we already use the term "free var". It refers to the regions or types that we use to represent
+/// bound regions or type params on a fn definition while we are type checking its body.
+///
+/// To clarify, conceptually there is no particular difference between
+/// an "escaping" var and a "free" var. However, there is a big
+/// difference in practice. Basically, when "entering" a binding
+/// level, one is generally required to do some sort of processing to
+/// a bound var, such as replacing it with a fresh/placeholder
+/// var, or making an entry in the environment to represent the
+/// scope to which it is attached, etc. An escaping var represents
+/// a bound var for which this processing has not yet been done.
+struct HasEscapingVarsVisitor {
+    /// Anything bound by `outer_index` or "above" is escaping.
+    outer_index: ty::DebruijnIndex,
+}
+
+impl<I: Interner> TypeVisitor<I> for HasEscapingVarsVisitor {
+    type BreakTy = FoundEscapingVars;
+
+    fn visit_binder<T: TypeVisitable<I>>(
+        &mut self,
+        t: &I::Binder<T>,
+    ) -> ControlFlow<Self::BreakTy> {
+        self.outer_index.shift_in(1);
+        let result = t.super_visit_with(self);
+        self.outer_index.shift_out(1);
+        result
+    }
+
+    #[inline]
+    fn visit_ty(&mut self, t: I::Ty) -> ControlFlow<Self::BreakTy> {
+        // If the outer-exclusive-binder is *strictly greater* than
+        // `outer_index`, that means that `t` contains some content
+        // bound at `outer_index` or above (because
+        // `outer_exclusive_binder` is always 1 higher than the
+        // content in `t`). Therefore, `t` has some escaping vars.
+        if t.outer_exclusive_binder() > self.outer_index {
+            ControlFlow::Break(FoundEscapingVars)
+        } else {
+            ControlFlow::Continue(())
+        }
+    }
+
+    #[inline]
+    fn visit_region(&mut self, r: I::Region) -> ControlFlow<Self::BreakTy> {
+        // If the region is bound by `outer_index` or anything outside
+        // of outer index, then it escapes the binders we have
+        // visited.
+        if r.outer_exclusive_binder() > self.outer_index {
+            ControlFlow::Break(FoundEscapingVars)
+        } else {
+            ControlFlow::Continue(())
+        }
+    }
+
+    fn visit_const(&mut self, ct: I::Const) -> ControlFlow<Self::BreakTy> {
+        // If the outer-exclusive-binder is *strictly greater* than
+        // `outer_index`, that means that `ct` contains some content
+        // bound at `outer_index` or above (because
+        // `outer_exclusive_binder` is always 1 higher than the
+        // content in `t`). Therefore, `t` has some escaping vars.
+        if ct.outer_exclusive_binder() > self.outer_index {
+            ControlFlow::Break(FoundEscapingVars)
+        } else {
+            ControlFlow::Continue(())
+        }
+    }
+
+    #[inline]
+    fn visit_predicate(&mut self, predicate: I::Predicate) -> ControlFlow<Self::BreakTy> {
+        if predicate.outer_exclusive_binder() > self.outer_index {
+            ControlFlow::Break(FoundEscapingVars)
+        } else {
+            ControlFlow::Continue(())
+        }
+    }
+}
+
+struct HasErrorVisitor;
+
+impl<I: Interner> TypeVisitor<I> for HasErrorVisitor {
+    type BreakTy = I::ErrorGuaranteed;
+
+    fn visit_ty(&mut self, t: <I as Interner>::Ty) -> ControlFlow<Self::BreakTy> {
+        if let ty::Error(guar) = t.kind() {
+            ControlFlow::Break(guar)
+        } else {
+            t.super_visit_with(self)
+        }
+    }
+
+    fn visit_const(&mut self, c: <I as Interner>::Const) -> ControlFlow<Self::BreakTy> {
+        if let ty::ConstKind::Error(guar) = c.kind() {
+            ControlFlow::Break(guar)
+        } else {
+            c.super_visit_with(self)
+        }
+    }
+
+    fn visit_region(&mut self, r: <I as Interner>::Region) -> ControlFlow<Self::BreakTy> {
+        if let ty::ReError(guar) = r.kind() {
+            ControlFlow::Break(guar)
+        } else {
+            ControlFlow::Continue(())
+        }
+    }
+}
diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs
index 87db8629ad09a..b214f4946b1b5 100644
--- a/library/alloc/src/task.rs
+++ b/library/alloc/src/task.rs
@@ -19,7 +19,7 @@ use core::task::Waker;
 /// The implementation of waking a task on an executor.
 ///
 /// This trait can be used to create a [`Waker`]. An executor can define an
-/// implementation of this trait, and use that to construct a Waker to pass
+/// implementation of this trait, and use that to construct a [`Waker`] to pass
 /// to the tasks that are executed on that executor.
 ///
 /// This trait is a memory-safe and ergonomic alternative to constructing a
@@ -28,7 +28,14 @@ use core::task::Waker;
 /// those for embedded systems) cannot use this API, which is why [`RawWaker`]
 /// exists as an alternative for those systems.
 ///
-/// [arc]: ../../std/sync/struct.Arc.html
+/// To construct a [`Waker`] from some type `W` implementing this trait,
+/// wrap it in an [`Arc<W>`](Arc) and call `Waker::from()` on that.
+/// It is also possible to convert to [`RawWaker`] in the same way.
+///
+/// <!-- Ideally we'd link to the `From` impl, but rustdoc doesn't generate any page for it within
+///      `alloc` because `alloc` neither defines nor re-exports `From` or `Waker`, and we can't
+///      link ../../std/task/struct.Waker.html#impl-From%3CArc%3CW,+Global%3E%3E-for-Waker
+///      without getting a link-checking error in CI. -->
 ///
 /// # Examples
 ///
@@ -100,7 +107,7 @@ pub trait Wake {
 #[cfg(target_has_atomic = "ptr")]
 #[stable(feature = "wake_trait", since = "1.51.0")]
 impl<W: Wake + Send + Sync + 'static> From<Arc<W>> for Waker {
-    /// Use a `Wake`-able type as a `Waker`.
+    /// Use a [`Wake`]-able type as a `Waker`.
     ///
     /// No heap allocations or atomic operations are used for this conversion.
     fn from(waker: Arc<W>) -> Waker {
diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs
index 78091c0172955..1c8e667654469 100644
--- a/library/core/src/alloc/mod.rs
+++ b/library/core/src/alloc/mod.rs
@@ -95,8 +95,10 @@ impl fmt::Display for AllocError {
 /// # Safety
 ///
 /// * Memory blocks returned from an allocator that are [*currently allocated*] must point to
-///   valid memory and retain their validity while they are [*currently allocated*] and at
-///   least one of the instance and all of its clones has not been dropped.
+///   valid memory and retain their validity while they are [*currently allocated*] and the shorter
+///   of:
+///   - the borrow-checker lifetime of the allocator type itself.
+///   - as long as at least one of the instance and all of its clones has not been dropped.
 ///
 /// * copying, cloning, or moving the allocator must not invalidate memory blocks returned from this
 ///   allocator. A copied or cloned allocator must behave like the same allocator, and
@@ -114,6 +116,10 @@ pub unsafe trait Allocator {
     /// The returned block may have a larger size than specified by `layout.size()`, and may or may
     /// not have its contents initialized.
     ///
+    /// The returned block of memory remains valid as long as it is [*currently allocated*] and the shorter of:
+    ///   - the borrow-checker lifetime of the allocator type itself.
+    ///   - as long as at the allocator and all its clones has not been dropped.
+    ///
     /// # Errors
     ///
     /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet
diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs
index 5f758af162477..34a05ac38884d 100644
--- a/library/core/src/ascii/ascii_char.rs
+++ b/library/core/src/ascii/ascii_char.rs
@@ -58,7 +58,7 @@ use crate::mem::transmute;
 #[unstable(feature = "ascii_char", issue = "110998")]
 #[repr(u8)]
 pub enum AsciiChar {
-    /// U+0000
+    /// U+0000 (The default variant)
     #[unstable(feature = "ascii_char_variants", issue = "110998")]
     Null = 0,
     /// U+0001
diff --git a/library/core/src/default.rs b/library/core/src/default.rs
index 16618b38769d2..a1303fcd82158 100644
--- a/library/core/src/default.rs
+++ b/library/core/src/default.rs
@@ -2,6 +2,8 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+use crate::ascii::Char as AsciiChar;
+
 /// A trait for giving a type a useful default value.
 ///
 /// Sometimes, you want to fall back to some kind of default value, and
@@ -158,6 +160,7 @@ macro_rules! default_impl {
 default_impl! { (), (), "Returns the default value of `()`" }
 default_impl! { bool, false, "Returns the default value of `false`" }
 default_impl! { char, '\x00', "Returns the default value of `\\x00`" }
+default_impl! { AsciiChar, AsciiChar::Null, "Returns the default value of `Null`" }
 
 default_impl! { usize, 0, "Returns the default value of `0`" }
 default_impl! { u8, 0, "Returns the default value of `0`" }
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index 09f3f2f02eab1..b9895f7edeaa4 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -9,10 +9,14 @@ use crate::ptr;
 /// A `RawWaker` allows the implementor of a task executor to create a [`Waker`]
 /// or a [`LocalWaker`] which provides customized wakeup behavior.
 ///
-/// [vtable]: https://en.wikipedia.org/wiki/Virtual_method_table
-///
 /// It consists of a data pointer and a [virtual function pointer table (vtable)][vtable]
 /// that customizes the behavior of the `RawWaker`.
+///
+/// `RawWaker`s are unsafe to use.
+/// Implementing the [`Wake`] trait is a safe alternative that requires memory allocation.
+///
+/// [vtable]: https://en.wikipedia.org/wiki/Virtual_method_table
+/// [`Wake`]: ../../alloc/task/trait.Wake.html
 #[derive(PartialEq, Debug)]
 #[stable(feature = "futures_api", since = "1.36.0")]
 pub struct RawWaker {
@@ -355,8 +359,12 @@ impl<'a> ContextBuilder<'a> {
 /// of `*waker = new_waker.clone()`, as the former will avoid cloning the waker
 /// unnecessarily if the two wakers [wake the same task](Self::will_wake).
 ///
+/// Constructing a `Waker` from a [`RawWaker`] is unsafe.
+/// Implementing the [`Wake`] trait is a safe alternative that requires memory allocation.
+///
 /// [`Future::poll()`]: core::future::Future::poll
 /// [`Poll::Pending`]: core::task::Poll::Pending
+/// [`Wake`]: ../../alloc/task/trait.Wake.html
 #[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/66401
 #[stable(feature = "futures_api", since = "1.36.0")]
 pub struct Waker {
@@ -438,9 +446,15 @@ impl Waker {
 
     /// Creates a new `Waker` from [`RawWaker`].
     ///
+    /// # Safety
+    ///
     /// The behavior of the returned `Waker` is undefined if the contract defined
     /// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld.
-    /// Therefore this method is unsafe.
+    ///
+    /// (Authors wishing to avoid unsafe code may implement the [`Wake`] trait instead, at the
+    /// cost of a required heap allocation.)
+    ///
+    /// [`Wake`]: ../../alloc/task/trait.Wake.html
     #[inline]
     #[must_use]
     #[stable(feature = "futures_api", since = "1.36.0")]
diff --git a/library/std/build.rs b/library/std/build.rs
index 35b183c47d791..ee3f3612d2e0f 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -7,7 +7,9 @@ fn main() {
     let target_vendor =
         env::var("CARGO_CFG_TARGET_VENDOR").expect("CARGO_CFG_TARGET_VENDOR was not set");
     let target_env = env::var("CARGO_CFG_TARGET_ENV").expect("CARGO_CFG_TARGET_ENV was not set");
-
+    if target_os == "netbsd" && env::var("RUSTC_STD_NETBSD10").is_ok() {
+        println!("cargo:rustc-cfg=netbsd10");
+    }
     if target_os == "linux"
         || target_os == "android"
         || target_os == "netbsd"
diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs
index b8873a3b59a0b..6d068613f8f30 100644
--- a/library/std/src/sync/once_lock.rs
+++ b/library/std/src/sync/once_lock.rs
@@ -13,7 +13,7 @@ use crate::sync::Once;
 ///
 /// # Examples
 ///
-/// Using `OnceCell` to store a function’s previously computed value (a.k.a.
+/// Using `OnceLock` to store a function’s previously computed value (a.k.a.
 /// ‘lazy static’ or ‘memoizing’):
 ///
 /// ```
diff --git a/library/std/src/sys/pal/unix/rand.rs b/library/std/src/sys/pal/unix/rand.rs
index 1dba1ccf64e68..5c32957bc519c 100644
--- a/library/std/src/sys/pal/unix/rand.rs
+++ b/library/std/src/sys/pal/unix/rand.rs
@@ -62,7 +62,7 @@ mod imp {
         unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), libc::GRND_NONBLOCK) }
     }
 
-    #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "freebsd"))]
+    #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "freebsd", netbsd10))]
     fn getrandom(buf: &mut [u8]) -> libc::ssize_t {
         unsafe { libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) }
     }
@@ -72,7 +72,8 @@ mod imp {
         target_os = "android",
         target_os = "espidf",
         target_os = "horizon",
-        target_os = "freebsd"
+        target_os = "freebsd",
+        netbsd10
     )))]
     fn getrandom_fill_bytes(_buf: &mut [u8]) -> bool {
         false
@@ -83,7 +84,8 @@ mod imp {
         target_os = "android",
         target_os = "espidf",
         target_os = "horizon",
-        target_os = "freebsd"
+        target_os = "freebsd",
+        netbsd10
     ))]
     fn getrandom_fill_bytes(v: &mut [u8]) -> bool {
         use crate::sync::atomic::{AtomicBool, Ordering};
@@ -230,7 +232,7 @@ mod imp {
 }
 
 // FIXME: once the 10.x release becomes the minimum, this can be dropped for simplification.
-#[cfg(target_os = "netbsd")]
+#[cfg(all(target_os = "netbsd", not(netbsd10)))]
 mod imp {
     use crate::ptr;
 
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 36f9ee6aff665..0e9a9791fb251 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -86,6 +86,7 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &str, Option<&[&'static str]>)] = &[
     (Some(Mode::Std), "no_global_oom_handling", None),
     (Some(Mode::Std), "no_rc", None),
     (Some(Mode::Std), "no_sync", None),
+    (Some(Mode::Std), "netbsd10", None),
     (Some(Mode::Std), "backtrace_in_libstd", None),
     /* Extra values not defined in the built-in targets yet, but used in std */
     (Some(Mode::Std), "target_env", Some(&["libnx"])),
diff --git a/tests/mir-opt/issue_120925_unsafefncast.rs b/tests/mir-opt/issue_120925_unsafefncast.rs
new file mode 100644
index 0000000000000..f80ae66efdae3
--- /dev/null
+++ b/tests/mir-opt/issue_120925_unsafefncast.rs
@@ -0,0 +1,25 @@
+// Verify that we do not ICE when attempting to interpret casts between fn types.
+// skip-filecheck
+
+static FOO: fn() = || assert_ne!(42, 43);
+static BAR: fn(i32, i32) = |a, b| assert_ne!(a, b);
+
+fn main() {
+    FOO();
+
+    let bar: unsafe fn(i32, i32) = BAR;
+
+    let f: fn() = || {};
+    f();
+
+    f();
+
+    f();
+
+    let g: fn(i32) = |i| assert_eq!(i, 2);
+    g(2);
+
+    g(2);
+
+    g(2);
+}
diff --git a/tests/ui/asm/inline-syntax.arm.stderr b/tests/ui/asm/inline-syntax.arm.stderr
index 6bc38811f1b5f..4a50ec8d0d5ac 100644
--- a/tests/ui/asm/inline-syntax.arm.stderr
+++ b/tests/ui/asm/inline-syntax.arm.stderr
@@ -13,7 +13,7 @@ LL | .intel_syntax noprefix
    | ^
 
 error: unknown directive
-  --> $DIR/inline-syntax.rs:38:15
+  --> $DIR/inline-syntax.rs:35:15
    |
 LL |         asm!(".intel_syntax noprefix", "nop");
    |               ^
@@ -25,7 +25,7 @@ LL |     .intel_syntax noprefix
    |     ^
 
 error: unknown directive
-  --> $DIR/inline-syntax.rs:42:15
+  --> $DIR/inline-syntax.rs:39:15
    |
 LL |         asm!(".intel_syntax aaa noprefix", "nop");
    |               ^
@@ -37,7 +37,7 @@ LL |     .intel_syntax aaa noprefix
    |     ^
 
 error: unknown directive
-  --> $DIR/inline-syntax.rs:46:15
+  --> $DIR/inline-syntax.rs:43:15
    |
 LL |         asm!(".att_syntax noprefix", "nop");
    |               ^
@@ -49,7 +49,7 @@ LL |     .att_syntax noprefix
    |     ^
 
 error: unknown directive
-  --> $DIR/inline-syntax.rs:50:15
+  --> $DIR/inline-syntax.rs:47:15
    |
 LL |         asm!(".att_syntax bbb noprefix", "nop");
    |               ^
@@ -61,7 +61,7 @@ LL |     .att_syntax bbb noprefix
    |     ^
 
 error: unknown directive
-  --> $DIR/inline-syntax.rs:54:15
+  --> $DIR/inline-syntax.rs:51:15
    |
 LL |         asm!(".intel_syntax noprefix; nop");
    |               ^
@@ -73,7 +73,7 @@ LL |     .intel_syntax noprefix; nop
    |     ^
 
 error: unknown directive
-  --> $DIR/inline-syntax.rs:61:13
+  --> $DIR/inline-syntax.rs:58:13
    |
 LL |             .intel_syntax noprefix
    |             ^
diff --git a/tests/ui/asm/inline-syntax.arm_llvm_18.stderr b/tests/ui/asm/inline-syntax.arm_llvm_18.stderr
index 4926293bb88ad..ada3f4891d3ac 100644
--- a/tests/ui/asm/inline-syntax.arm_llvm_18.stderr
+++ b/tests/ui/asm/inline-syntax.arm_llvm_18.stderr
@@ -15,7 +15,7 @@ LL | .intel_syntax noprefix
    | ^
 
 error: unknown directive
-  --> $DIR/inline-syntax.rs:38:15
+  --> $DIR/inline-syntax.rs:35:15
    |
 LL |         asm!(".intel_syntax noprefix", "nop");
    |               ^
@@ -27,7 +27,7 @@ LL |     .intel_syntax noprefix
    |     ^
 
 error: unknown directive
-  --> $DIR/inline-syntax.rs:42:15
+  --> $DIR/inline-syntax.rs:39:15
    |
 LL |         asm!(".intel_syntax aaa noprefix", "nop");
    |               ^
@@ -39,7 +39,7 @@ LL |     .intel_syntax aaa noprefix
    |     ^
 
 error: unknown directive
-  --> $DIR/inline-syntax.rs:46:15
+  --> $DIR/inline-syntax.rs:43:15
    |
 LL |         asm!(".att_syntax noprefix", "nop");
    |               ^
@@ -51,7 +51,7 @@ LL |     .att_syntax noprefix
    |     ^
 
 error: unknown directive
-  --> $DIR/inline-syntax.rs:50:15
+  --> $DIR/inline-syntax.rs:47:15
    |
 LL |         asm!(".att_syntax bbb noprefix", "nop");
    |               ^
@@ -63,7 +63,7 @@ LL |     .att_syntax bbb noprefix
    |     ^
 
 error: unknown directive
-  --> $DIR/inline-syntax.rs:54:15
+  --> $DIR/inline-syntax.rs:51:15
    |
 LL |         asm!(".intel_syntax noprefix; nop");
    |               ^
@@ -75,7 +75,7 @@ LL |     .intel_syntax noprefix; nop
    |     ^
 
 error: unknown directive
-  --> $DIR/inline-syntax.rs:61:13
+  --> $DIR/inline-syntax.rs:58:13
    |
 LL |             .intel_syntax noprefix
    |             ^
diff --git a/tests/ui/asm/inline-syntax.rs b/tests/ui/asm/inline-syntax.rs
index 9398a87df6273..a8c6c71b805f2 100644
--- a/tests/ui/asm/inline-syntax.rs
+++ b/tests/ui/asm/inline-syntax.rs
@@ -2,14 +2,11 @@
 //[x86_64] compile-flags: --target x86_64-unknown-linux-gnu
 //[x86_64] check-pass
 //[x86_64] needs-llvm-components: x86
-//[x86_64_allowed] compile-flags: --target x86_64-unknown-linux-gnu
-//[x86_64_allowed] check-pass
-//[x86_64_allowed] needs-llvm-components: x86
 //[arm] compile-flags: --target armv7-unknown-linux-gnueabihf
 //[arm] build-fail
 //[arm] needs-llvm-components: arm
 //[arm] ignore-llvm-version: 18 - 99
-// Newer LLVM produces extra error notes.
+//Newer LLVM produces extra error notes.
 //[arm_llvm_18] compile-flags: --target armv7-unknown-linux-gnueabihf
 //[arm_llvm_18] build-fail
 //[arm_llvm_18] needs-llvm-components: arm
diff --git a/tests/ui/asm/inline-syntax.x86_64.stderr b/tests/ui/asm/inline-syntax.x86_64.stderr
index b54b3560447c9..66dc37f3089e1 100644
--- a/tests/ui/asm/inline-syntax.x86_64.stderr
+++ b/tests/ui/asm/inline-syntax.x86_64.stderr
@@ -1,5 +1,5 @@
 warning: avoid using `.intel_syntax`, Intel syntax is the default
-  --> $DIR/inline-syntax.rs:70:14
+  --> $DIR/inline-syntax.rs:67:14
    |
 LL | global_asm!(".intel_syntax noprefix", "nop");
    |              ^^^^^^^^^^^^^^^^^^^^^^
@@ -7,37 +7,37 @@ LL | global_asm!(".intel_syntax noprefix", "nop");
    = note: `#[warn(bad_asm_style)]` on by default
 
 warning: avoid using `.intel_syntax`, Intel syntax is the default
-  --> $DIR/inline-syntax.rs:38:15
+  --> $DIR/inline-syntax.rs:35:15
    |
 LL |         asm!(".intel_syntax noprefix", "nop");
    |               ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: avoid using `.intel_syntax`, Intel syntax is the default
-  --> $DIR/inline-syntax.rs:42:15
+  --> $DIR/inline-syntax.rs:39:15
    |
 LL |         asm!(".intel_syntax aaa noprefix", "nop");
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: avoid using `.att_syntax`, prefer using `options(att_syntax)` instead
-  --> $DIR/inline-syntax.rs:46:15
+  --> $DIR/inline-syntax.rs:43:15
    |
 LL |         asm!(".att_syntax noprefix", "nop");
    |               ^^^^^^^^^^^^^^^^^^^^
 
 warning: avoid using `.att_syntax`, prefer using `options(att_syntax)` instead
-  --> $DIR/inline-syntax.rs:50:15
+  --> $DIR/inline-syntax.rs:47:15
    |
 LL |         asm!(".att_syntax bbb noprefix", "nop");
    |               ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: avoid using `.intel_syntax`, Intel syntax is the default
-  --> $DIR/inline-syntax.rs:54:15
+  --> $DIR/inline-syntax.rs:51:15
    |
 LL |         asm!(".intel_syntax noprefix; nop");
    |               ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: avoid using `.intel_syntax`, Intel syntax is the default
-  --> $DIR/inline-syntax.rs:61:13
+  --> $DIR/inline-syntax.rs:58:13
    |
 LL |             .intel_syntax noprefix
    |             ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/borrowck/copy-suggestion-region-vid.fixed b/tests/ui/borrowck/copy-suggestion-region-vid.fixed
new file mode 100644
index 0000000000000..ec16469757a71
--- /dev/null
+++ b/tests/ui/borrowck/copy-suggestion-region-vid.fixed
@@ -0,0 +1,18 @@
+// run-rustfix
+pub struct DataStruct();
+
+pub struct HelperStruct<'n> {
+    pub helpers: [Vec<&'n i64>; 2],
+    pub is_empty: bool,
+}
+
+impl DataStruct {
+    pub fn f(&self) -> HelperStruct {
+        let helpers = [vec![], vec![]];
+
+        HelperStruct { helpers: helpers.clone(), is_empty: helpers[0].is_empty() }
+        //~^ ERROR borrow of moved value
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/borrowck/copy-suggestion-region-vid.rs b/tests/ui/borrowck/copy-suggestion-region-vid.rs
index 3c5b887ce17bd..f95c6b03e014a 100644
--- a/tests/ui/borrowck/copy-suggestion-region-vid.rs
+++ b/tests/ui/borrowck/copy-suggestion-region-vid.rs
@@ -1,4 +1,4 @@
-//@run-rustfix
+// run-rustfix
 pub struct DataStruct();
 
 pub struct HelperStruct<'n> {
diff --git a/tests/ui/consts/issue-89088.stderr b/tests/ui/consts/issue-89088.stderr
index d5c5f76b90a01..7cb85d5279d0d 100644
--- a/tests/ui/consts/issue-89088.stderr
+++ b/tests/ui/consts/issue-89088.stderr
@@ -9,9 +9,4 @@ LL |         FOO => todo!(),
    = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
-note: the lint level is defined here
-  --> $DIR/issue-89088.rs:5:10
-   |
-LL | #![allow(indirect_structural_match)]
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/tests/ui/did_you_mean/bad-assoc-ty.stderr b/tests/ui/did_you_mean/bad-assoc-ty.stderr
index 3c474d19d1d05..4a119f673c8ee 100644
--- a/tests/ui/did_you_mean/bad-assoc-ty.stderr
+++ b/tests/ui/did_you_mean/bad-assoc-ty.stderr
@@ -182,7 +182,7 @@ LL | type H = Fn(u8) -> (u8)::Output;
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: `#[warn(bare_trait_objects)]` on by default
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL | type H = <dyn Fn(u8) -> (u8)>::Output;
    |          ++++               +
diff --git a/tests/ui/dyn-keyword/dyn-2018-edition-lint.stderr b/tests/ui/dyn-keyword/dyn-2018-edition-lint.stderr
index 65d44604dc9fc..711bfa188ecd8 100644
--- a/tests/ui/dyn-keyword/dyn-2018-edition-lint.stderr
+++ b/tests/ui/dyn-keyword/dyn-2018-edition-lint.stderr
@@ -11,7 +11,7 @@ note: the lint level is defined here
    |
 LL | #[deny(bare_trait_objects)]
    |        ^^^^^^^^^^^^^^^^^^
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL | fn function(x: &dyn SomeTrait, y: Box<SomeTrait>) {
    |                 +++
@@ -24,7 +24,7 @@ LL | fn function(x: &SomeTrait, y: Box<SomeTrait>) {
    |
    = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL | fn function(x: &SomeTrait, y: Box<dyn SomeTrait>) {
    |                                   +++
@@ -37,7 +37,7 @@ LL |     let _x: &SomeTrait = todo!();
    |
    = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL |     let _x: &dyn SomeTrait = todo!();
    |              +++
diff --git a/tests/ui/dyn-keyword/dyn-angle-brackets.stderr b/tests/ui/dyn-keyword/dyn-angle-brackets.stderr
index 0b194cb8364c6..41298cc73c818 100644
--- a/tests/ui/dyn-keyword/dyn-angle-brackets.stderr
+++ b/tests/ui/dyn-keyword/dyn-angle-brackets.stderr
@@ -11,7 +11,7 @@ note: the lint level is defined here
    |
 LL | #![deny(bare_trait_objects)]
    |         ^^^^^^^^^^^^^^^^^^
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL |         <dyn fmt::Debug>::fmt(self, f)
    |          +++
diff --git a/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.stderr b/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.stderr
index 84aaedf183815..3cb3af89bfc25 100644
--- a/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.stderr
+++ b/tests/ui/impl-trait/fresh-lifetime-from-bare-trait-obj-114664.stderr
@@ -7,7 +7,7 @@ LL | fn ice() -> impl AsRef<Fn(&())> {
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: `#[warn(bare_trait_objects)]` on by default
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL | fn ice() -> impl AsRef<dyn Fn(&())> {
    |                        +++
diff --git a/tests/ui/issues/issue-28344.stderr b/tests/ui/issues/issue-28344.stderr
index 71d642109ac8c..8b427b692a79c 100644
--- a/tests/ui/issues/issue-28344.stderr
+++ b/tests/ui/issues/issue-28344.stderr
@@ -7,7 +7,7 @@ LL |     let x: u8 = BitXor::bitor(0 as u8, 0 as u8);
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: `#[warn(bare_trait_objects)]` on by default
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL |     let x: u8 = <dyn BitXor>::bitor(0 as u8, 0 as u8);
    |                 ++++       +
@@ -35,7 +35,7 @@ LL |     let g = BitXor::bitor;
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL |     let g = <dyn BitXor>::bitor;
    |             ++++       +
diff --git a/tests/ui/issues/issue-58734.stderr b/tests/ui/issues/issue-58734.stderr
index 5ae1ec7cac8f8..71581e96844ee 100644
--- a/tests/ui/issues/issue-58734.stderr
+++ b/tests/ui/issues/issue-58734.stderr
@@ -7,7 +7,7 @@ LL |     Trait::nonexistent(());
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: `#[warn(bare_trait_objects)]` on by default
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL |     <dyn Trait>::nonexistent(());
    |     ++++      +
diff --git a/tests/ui/issues/issue-86756.stderr b/tests/ui/issues/issue-86756.stderr
index bfa7459ab4a39..d0906a6fa74f4 100644
--- a/tests/ui/issues/issue-86756.stderr
+++ b/tests/ui/issues/issue-86756.stderr
@@ -21,7 +21,7 @@ LL |     eq::<dyn, Foo>
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: `#[warn(bare_trait_objects)]` on by default
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL |     eq::<dyn, dyn Foo>
    |               +++
diff --git a/tests/ui/lint/bare-trait-objects-path.stderr b/tests/ui/lint/bare-trait-objects-path.stderr
index c5d72707f80e8..da1d9f248a01f 100644
--- a/tests/ui/lint/bare-trait-objects-path.stderr
+++ b/tests/ui/lint/bare-trait-objects-path.stderr
@@ -7,7 +7,7 @@ LL |     let _: Dyn::Ty;
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: `#[warn(bare_trait_objects)]` on by default
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL |     let _: <dyn Dyn>::Ty;
    |            ++++    +
@@ -26,7 +26,7 @@ LL |     Dyn::func();
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL |     <dyn Dyn>::func();
    |     ++++    +
@@ -39,7 +39,7 @@ LL |     ::Dyn::func();
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL |     <dyn (::Dyn)>::func();
    |     ++++++     ++
@@ -52,7 +52,7 @@ LL |     Dyn::CONST;
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL |     <dyn Dyn>::CONST;
    |     ++++    +
diff --git a/tests/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr b/tests/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr
index e9b7b248e612f..388dc6160cb95 100644
--- a/tests/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr
+++ b/tests/ui/lint/force-warn/allowed-group-warn-by-default-lint.stderr
@@ -7,7 +7,7 @@ LL | pub fn function(_x: Box<SomeTrait>) {}
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: requested on the command line with `--force-warn bare-trait-objects`
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL | pub fn function(_x: Box<dyn SomeTrait>) {}
    |                         +++
diff --git a/tests/ui/lint/force-warn/cap-lints-allow.stderr b/tests/ui/lint/force-warn/cap-lints-allow.stderr
index e569b2f9f1ae9..a037fb671af29 100644
--- a/tests/ui/lint/force-warn/cap-lints-allow.stderr
+++ b/tests/ui/lint/force-warn/cap-lints-allow.stderr
@@ -7,7 +7,7 @@ LL | pub fn function(_x: Box<SomeTrait>) {}
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: requested on the command line with `--force-warn bare-trait-objects`
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL | pub fn function(_x: Box<dyn SomeTrait>) {}
    |                         +++
diff --git a/tests/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr b/tests/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr
index c971e4d0d4d21..a74cda2239f50 100644
--- a/tests/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr
+++ b/tests/ui/lint/force-warn/lint-group-allowed-cli-warn-by-default-lint.stderr
@@ -8,7 +8,7 @@ LL | pub fn function(_x: Box<SomeTrait>) {}
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: `--force-warn bare-trait-objects` implied by `--force-warn rust-2018-idioms`
    = help: to override `--force-warn rust-2018-idioms` add `#[allow(bare_trait_objects)]`
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL | pub fn function(_x: Box<dyn SomeTrait>) {}
    |                         +++
diff --git a/tests/ui/lint/force-warn/lint-group-allowed-lint-group.stderr b/tests/ui/lint/force-warn/lint-group-allowed-lint-group.stderr
index 97b8694984dd7..c9472a3b9b9d3 100644
--- a/tests/ui/lint/force-warn/lint-group-allowed-lint-group.stderr
+++ b/tests/ui/lint/force-warn/lint-group-allowed-lint-group.stderr
@@ -8,7 +8,7 @@ LL | pub fn function(_x: Box<SomeTrait>) {}
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: `--force-warn bare-trait-objects` implied by `--force-warn rust-2018-idioms`
    = help: to override `--force-warn rust-2018-idioms` add `#[allow(bare_trait_objects)]`
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL | pub fn function(_x: Box<dyn SomeTrait>) {}
    |                         +++
diff --git a/tests/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr b/tests/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr
index cd030cc1fcd18..558d5cbb53156 100644
--- a/tests/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr
+++ b/tests/ui/lint/force-warn/lint-group-allowed-warn-by-default-lint.stderr
@@ -8,7 +8,7 @@ LL | pub fn function(_x: Box<SomeTrait>) {}
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: `--force-warn bare-trait-objects` implied by `--force-warn rust-2018-idioms`
    = help: to override `--force-warn rust-2018-idioms` add `#[allow(bare_trait_objects)]`
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL | pub fn function(_x: Box<dyn SomeTrait>) {}
    |                         +++
diff --git a/tests/ui/lint/future-incompat-json-test.stderr b/tests/ui/lint/future-incompat-json-test.stderr
index 18fc3f17f0020..f33a5cab6ba09 100644
--- a/tests/ui/lint/future-incompat-json-test.stderr
+++ b/tests/ui/lint/future-incompat-json-test.stderr
@@ -1,10 +1,7 @@
-{"$message_type":"future_incompat","future_incompat_report":[{"diagnostic":{"$message_type":"diagnostic","message":"unused variable: `x`","code":{"code":"unused_variables","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/future-incompat-json-test.rs","byte_start":338,"byte_end":339,"line_start":9,"line_end":9,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":"    let x = 1;","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"`-A unused-variables` implied by `-A unused`","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"to override `-A unused` add `#[allow(unused_variables)]`","code":null,"level":"help","spans":[],"children":[],"rendered":null},{"message":"if this is intentional, prefix it with an underscore","code":null,"level":"help","spans":[{"file_name":"$DIR/future-incompat-json-test.rs","byte_start":338,"byte_end":339,"line_start":9,"line_end":9,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":"    let x = 1;","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":"_x","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"warning: unused variable: `x`
+{"$message_type":"future_incompat","future_incompat_report":[{"diagnostic":{"$message_type":"diagnostic","message":"unused variable: `x`","code":{"code":"unused_variables","explanation":null},"level":"warning","spans":[{"file_name":"$DIR/future-incompat-json-test.rs","byte_start":338,"byte_end":339,"line_start":9,"line_end":9,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":"    let x = 1;","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"if this is intentional, prefix it with an underscore","code":null,"level":"help","spans":[{"file_name":"$DIR/future-incompat-json-test.rs","byte_start":338,"byte_end":339,"line_start":9,"line_end":9,"column_start":9,"column_end":10,"is_primary":true,"text":[{"text":"    let x = 1;","highlight_start":9,"highlight_end":10}],"label":null,"suggested_replacement":"_x","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"warning: unused variable: `x`
   --> $DIR/future-incompat-json-test.rs:9:9
    |
 LL |     let x = 1;
    |         ^ help: if this is intentional, prefix it with an underscore: `_x`
-   |
-   = note: `-A unused-variables` implied by `-A unused`
-   = help: to override `-A unused` add `#[allow(unused_variables)]`
 
 "}}]}
diff --git a/tests/ui/lint/future-incompat-test.stderr b/tests/ui/lint/future-incompat-test.stderr
index 2951f904fb5e8..f24e1c7aba452 100644
--- a/tests/ui/lint/future-incompat-test.stderr
+++ b/tests/ui/lint/future-incompat-test.stderr
@@ -4,7 +4,4 @@ warning: unused variable: `x`
    |
 LL |     let x = 1;
    |         ^ help: if this is intentional, prefix it with an underscore: `_x`
-   |
-   = note: `-A unused-variables` implied by `-A unused`
-   = help: to override `-A unused` add `#[allow(unused_variables)]`
 
diff --git a/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr b/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr
index c60120061643d..ea72ef84b9dae 100644
--- a/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr
+++ b/tests/ui/lint/semicolon-in-expressions-from-macros/semicolon-in-expressions-from-macros.stderr
@@ -60,11 +60,6 @@ LL |         foo!(first)
    = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
    = note: macro invocations at the end of a block are treated as expressions
    = note: to ignore the value produced by the macro, add a semicolon after the invocation of `foo`
-note: the lint level is defined here
-  --> $DIR/semicolon-in-expressions-from-macros.rs:24:13
-   |
-LL |     #[allow(semicolon_in_expressions_from_macros)]
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
@@ -79,11 +74,6 @@ LL |     let _ = foo!(second);
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
-note: the lint level is defined here
-  --> $DIR/semicolon-in-expressions-from-macros.rs:29:13
-   |
-LL |     #[allow(semicolon_in_expressions_from_macros)]
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
@@ -98,11 +88,6 @@ LL |         let _ = foo!(third);
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
-note: the lint level is defined here
-  --> $DIR/semicolon-in-expressions-from-macros.rs:32:13
-   |
-LL |     #[allow(semicolon_in_expressions_from_macros)]
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
@@ -117,11 +102,6 @@ LL |         let _ = foo!(fourth);
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #79813 <https://github.com/rust-lang/rust/issues/79813>
-note: the lint level is defined here
-  --> $DIR/semicolon-in-expressions-from-macros.rs:37:13
-   |
-LL |     #[allow(semicolon_in_expressions_from_macros)]
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
diff --git a/tests/ui/object-safety/avoid-ice-on-warning-2.old.stderr b/tests/ui/object-safety/avoid-ice-on-warning-2.old.stderr
index 41c09b7df6289..70e7ea535284d 100644
--- a/tests/ui/object-safety/avoid-ice-on-warning-2.old.stderr
+++ b/tests/ui/object-safety/avoid-ice-on-warning-2.old.stderr
@@ -7,7 +7,7 @@ LL | fn id<F>(f: Copy) -> usize {
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: `#[warn(bare_trait_objects)]` on by default
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL | fn id<F>(f: dyn Copy) -> usize {
    |             +++
@@ -21,7 +21,7 @@ LL | fn id<F>(f: Copy) -> usize {
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL | fn id<F>(f: dyn Copy) -> usize {
    |             +++
diff --git a/tests/ui/object-safety/avoid-ice-on-warning-3.old.stderr b/tests/ui/object-safety/avoid-ice-on-warning-3.old.stderr
index a36e2519c804d..f499e2d946ffe 100644
--- a/tests/ui/object-safety/avoid-ice-on-warning-3.old.stderr
+++ b/tests/ui/object-safety/avoid-ice-on-warning-3.old.stderr
@@ -7,7 +7,7 @@ LL | trait B { fn f(a: A) -> A; }
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: `#[warn(bare_trait_objects)]` on by default
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL | trait B { fn f(a: dyn A) -> A; }
    |                   +++
@@ -20,7 +20,7 @@ LL | trait B { fn f(a: A) -> A; }
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL | trait B { fn f(a: A) -> dyn A; }
    |                         +++
@@ -33,7 +33,7 @@ LL | trait A { fn g(b: B) -> B; }
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL | trait A { fn g(b: dyn B) -> B; }
    |                   +++
@@ -46,7 +46,7 @@ LL | trait A { fn g(b: B) -> B; }
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL | trait A { fn g(b: B) -> dyn B; }
    |                         +++
@@ -60,7 +60,7 @@ LL | trait B { fn f(a: A) -> A; }
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL | trait B { fn f(a: dyn A) -> A; }
    |                   +++
@@ -96,7 +96,7 @@ LL | trait A { fn g(b: B) -> B; }
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL | trait A { fn g(b: dyn B) -> B; }
    |                   +++
diff --git a/tests/ui/object-safety/avoid-ice-on-warning.old.stderr b/tests/ui/object-safety/avoid-ice-on-warning.old.stderr
index 7c7af9682800f..3939c06eabe5b 100644
--- a/tests/ui/object-safety/avoid-ice-on-warning.old.stderr
+++ b/tests/ui/object-safety/avoid-ice-on-warning.old.stderr
@@ -19,7 +19,7 @@ LL | fn call_this<F>(f: F) : Fn(&str) + call_that {}
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: `#[warn(bare_trait_objects)]` on by default
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL | fn call_this<F>(f: F) : dyn Fn(&str) + call_that {}
    |                         +++
diff --git a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr
index 274d5a639a43b..f795e910d2152 100644
--- a/tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr
+++ b/tests/ui/object-safety/bare-trait-dont-suggest-dyn.old.stderr
@@ -11,7 +11,7 @@ note: the lint level is defined here
    |
 LL | #![deny(bare_trait_objects)]
    |         ^^^^^^^^^^^^^^^^^^
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL | fn ord_prefer_dot(s: String) -> dyn Ord {
    |                                 +++
diff --git a/tests/ui/parser/trait-object-trait-parens.stderr b/tests/ui/parser/trait-object-trait-parens.stderr
index 5e07a3fe6c740..3134746b930ac 100644
--- a/tests/ui/parser/trait-object-trait-parens.stderr
+++ b/tests/ui/parser/trait-object-trait-parens.stderr
@@ -25,7 +25,7 @@ LL |     let _: Box<(Obj) + (?Sized) + (for<'a> Trait<'a>)>;
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: `#[warn(bare_trait_objects)]` on by default
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL |     let _: Box<dyn (Obj) + (?Sized) + (for<'a> Trait<'a>)>;
    |                +++
@@ -49,7 +49,7 @@ LL |     let _: Box<?Sized + (for<'a> Trait<'a>) + (Obj)>;
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL |     let _: Box<dyn ?Sized + (for<'a> Trait<'a>) + (Obj)>;
    |                +++
@@ -73,7 +73,7 @@ LL |     let _: Box<for<'a> Trait<'a> + (Obj) + (?Sized)>;
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL |     let _: Box<dyn for<'a> Trait<'a> + (Obj) + (?Sized)>;
    |                +++
diff --git a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr
index 59b454d398195..2a1cd3a7aa4bb 100644
--- a/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr
+++ b/tests/ui/pattern/usefulness/const-partial_eq-fallback-ice.stderr
@@ -20,10 +20,4 @@ LL |     if let CONSTANT = &&MyType {
    = note: for more information, see issue #120362 <https://github.com/rust-lang/rust/issues/120362>
    = note: the traits must be derived, manual `impl`s are not sufficient
    = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
-note: the lint level is defined here
-  --> $DIR/const-partial_eq-fallback-ice.rs:1:10
-   |
-LL | #![allow(warnings)]
-   |          ^^^^^^^^
-   = note: `#[allow(indirect_structural_match)]` implied by `#[allow(warnings)]`
 
diff --git a/tests/ui/proc-macro/generate-mod.stderr b/tests/ui/proc-macro/generate-mod.stderr
index db629b5b5e239..cbe6b14ca9af5 100644
--- a/tests/ui/proc-macro/generate-mod.stderr
+++ b/tests/ui/proc-macro/generate-mod.stderr
@@ -139,11 +139,6 @@ LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
-note: the lint level is defined here
-  --> $DIR/generate-mod.rs:30:10
-   |
-LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: this warning originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 Future breakage diagnostic:
@@ -155,10 +150,5 @@ LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
-note: the lint level is defined here
-  --> $DIR/generate-mod.rs:30:10
-   |
-LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: this warning originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/suggestions/issue-116434-2015.rs b/tests/ui/suggestions/issue-116434-2015.rs
new file mode 100644
index 0000000000000..614fc27b77187
--- /dev/null
+++ b/tests/ui/suggestions/issue-116434-2015.rs
@@ -0,0 +1,23 @@
+trait Foo {
+    type Clone;
+    fn foo() -> Clone;
+    //~^ WARNING trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+    //~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+    //~| WARNING trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+    //~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+    //~| ERROR the trait `Clone` cannot be made into an object [E0038]
+}
+
+trait DbHandle: Sized {}
+
+trait DbInterface {
+    type DbHandle;
+    fn handle() -> DbHandle;
+    //~^ WARNING trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+    //~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+    //~| WARNING trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
+    //~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+    //~| ERROR the trait `DbHandle` cannot be made into an object [E0038]
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/issue-116434-2015.stderr b/tests/ui/suggestions/issue-116434-2015.stderr
new file mode 100644
index 0000000000000..2d87029b6eb11
--- /dev/null
+++ b/tests/ui/suggestions/issue-116434-2015.stderr
@@ -0,0 +1,81 @@
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/issue-116434-2015.rs:3:17
+   |
+LL |     fn foo() -> Clone;
+   |                 ^^^^^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+   = note: `#[warn(bare_trait_objects)]` on by default
+help: if this is an object-safe trait, use `dyn`
+   |
+LL |     fn foo() -> dyn Clone;
+   |                 +++
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/issue-116434-2015.rs:15:20
+   |
+LL |     fn handle() -> DbHandle;
+   |                    ^^^^^^^^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+help: if this is an object-safe trait, use `dyn`
+   |
+LL |     fn handle() -> dyn DbHandle;
+   |                    +++
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/issue-116434-2015.rs:3:17
+   |
+LL |     fn foo() -> Clone;
+   |                 ^^^^^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: if this is an object-safe trait, use `dyn`
+   |
+LL |     fn foo() -> dyn Clone;
+   |                 +++
+
+error[E0038]: the trait `Clone` cannot be made into an object
+  --> $DIR/issue-116434-2015.rs:3:17
+   |
+LL |     fn foo() -> Clone;
+   |                 ^^^^^ `Clone` cannot be made into an object
+   |
+   = note: the trait cannot be made into an object because it requires `Self: Sized`
+   = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+
+warning: trait objects without an explicit `dyn` are deprecated
+  --> $DIR/issue-116434-2015.rs:15:20
+   |
+LL |     fn handle() -> DbHandle;
+   |                    ^^^^^^^^
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: if this is an object-safe trait, use `dyn`
+   |
+LL |     fn handle() -> dyn DbHandle;
+   |                    +++
+
+error[E0038]: the trait `DbHandle` cannot be made into an object
+  --> $DIR/issue-116434-2015.rs:15:20
+   |
+LL |     fn handle() -> DbHandle;
+   |                    ^^^^^^^^ `DbHandle` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-116434-2015.rs:11:17
+   |
+LL | trait DbHandle: Sized {}
+   |       --------  ^^^^^ ...because it requires `Self: Sized`
+   |       |
+   |       this trait cannot be made into an object...
+
+error: aborting due to 2 previous errors; 4 warnings emitted
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/suggestions/issue-116434-2021.rs b/tests/ui/suggestions/issue-116434-2021.rs
new file mode 100644
index 0000000000000..74c30e0cc1fbe
--- /dev/null
+++ b/tests/ui/suggestions/issue-116434-2021.rs
@@ -0,0 +1,17 @@
+// edition:2021
+
+trait Foo {
+    type Clone;
+    fn foo() -> Clone;
+    //~^ ERROR the trait `Clone` cannot be made into an object [E0038]
+}
+
+trait DbHandle: Sized {}
+
+trait DbInterface {
+    type DbHandle;
+    fn handle() -> DbHandle;
+    //~^ ERROR the trait `DbHandle` cannot be made into an object [E0038]
+}
+
+fn main() {}
diff --git a/tests/ui/suggestions/issue-116434-2021.stderr b/tests/ui/suggestions/issue-116434-2021.stderr
new file mode 100644
index 0000000000000..43ad82d484a66
--- /dev/null
+++ b/tests/ui/suggestions/issue-116434-2021.stderr
@@ -0,0 +1,26 @@
+error[E0038]: the trait `Clone` cannot be made into an object
+  --> $DIR/issue-116434-2021.rs:5:17
+   |
+LL |     fn foo() -> Clone;
+   |                 ^^^^^ `Clone` cannot be made into an object
+   |
+   = note: the trait cannot be made into an object because it requires `Self: Sized`
+   = note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+
+error[E0038]: the trait `DbHandle` cannot be made into an object
+  --> $DIR/issue-116434-2021.rs:13:20
+   |
+LL |     fn handle() -> DbHandle;
+   |                    ^^^^^^^^ `DbHandle` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/issue-116434-2021.rs:9:17
+   |
+LL | trait DbHandle: Sized {}
+   |       --------  ^^^^^ ...because it requires `Self: Sized`
+   |       |
+   |       this trait cannot be made into an object...
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/suggestions/issue-61963.stderr b/tests/ui/suggestions/issue-61963.stderr
index 754d02b1c021b..084b0cbeef292 100644
--- a/tests/ui/suggestions/issue-61963.stderr
+++ b/tests/ui/suggestions/issue-61963.stderr
@@ -11,7 +11,7 @@ note: the lint level is defined here
    |
 LL | #![deny(bare_trait_objects)]
    |         ^^^^^^^^^^^^^^^^^^
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL |     bar: Box<dyn Bar>,
    |              +++
@@ -24,7 +24,7 @@ LL | pub struct Foo {
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL | dyn pub struct Foo {
    | +++
diff --git a/tests/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr b/tests/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr
index ffd505fffb48e..0098814f81e78 100644
--- a/tests/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr
+++ b/tests/ui/suggestions/suggest-swapping-self-ty-and-trait.stderr
@@ -40,7 +40,7 @@ LL | impl<'a, T> Struct<T> for Trait<'a, T> {}
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: `#[warn(bare_trait_objects)]` on by default
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL | impl<'a, T> Struct<T> for dyn Trait<'a, T> {}
    |                           +++
diff --git a/tests/ui/trait-bounds/suggest-maybe-sized-bound.rs b/tests/ui/trait-bounds/suggest-maybe-sized-bound.rs
new file mode 100644
index 0000000000000..15aa27349aa91
--- /dev/null
+++ b/tests/ui/trait-bounds/suggest-maybe-sized-bound.rs
@@ -0,0 +1,20 @@
+// issue: 120878
+fn main() {
+    struct StructA<A, B = A> {
+        _marker: std::marker::PhantomData<fn() -> (A, B)>,
+    }
+
+    struct StructB {
+        a: StructA<isize, [u8]>,
+        //~^ ERROR: the size for values of type `[u8]` cannot be known at compilation time [E0277]
+    }
+
+    trait Trait {
+        type P<X>;
+    }
+
+    impl Trait for () {
+        type P<X> = [u8];
+        //~^ ERROR: the size for values of type `[u8]` cannot be known at compilation time [E0277]
+    }
+}
diff --git a/tests/ui/trait-bounds/suggest-maybe-sized-bound.stderr b/tests/ui/trait-bounds/suggest-maybe-sized-bound.stderr
new file mode 100644
index 0000000000000..4ce936582f43d
--- /dev/null
+++ b/tests/ui/trait-bounds/suggest-maybe-sized-bound.stderr
@@ -0,0 +1,37 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/suggest-maybe-sized-bound.rs:8:12
+   |
+LL |         a: StructA<isize, [u8]>,
+   |            ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `StructA`
+  --> $DIR/suggest-maybe-sized-bound.rs:3:23
+   |
+LL |     struct StructA<A, B = A> {
+   |                       ^^^^^ required by the implicit `Sized` requirement on this type parameter in `StructA`
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL |     struct StructA<A, B: ?Sized = A> {
+   |                        ++++++++
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/suggest-maybe-sized-bound.rs:17:21
+   |
+LL |         type P<X> = [u8];
+   |                     ^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `Trait::P`
+  --> $DIR/suggest-maybe-sized-bound.rs:13:9
+   |
+LL |         type P<X>;
+   |         ^^^^^^^^^^ required by this bound in `Trait::P`
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL |         type P<X>: ?Sized;
+   |                  ++++++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/bound/not-on-bare-trait.stderr b/tests/ui/traits/bound/not-on-bare-trait.stderr
index 6d56851bf3495..f1e7a28654a74 100644
--- a/tests/ui/traits/bound/not-on-bare-trait.stderr
+++ b/tests/ui/traits/bound/not-on-bare-trait.stderr
@@ -7,7 +7,7 @@ LL | fn foo(_x: Foo + Send) {
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: `#[warn(bare_trait_objects)]` on by default
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL | fn foo(_x: dyn Foo + Send) {
    |            +++
diff --git a/tests/ui/traits/issue-28576.stderr b/tests/ui/traits/issue-28576.stderr
index adba5830b10e1..653ce05d28574 100644
--- a/tests/ui/traits/issue-28576.stderr
+++ b/tests/ui/traits/issue-28576.stderr
@@ -36,8 +36,8 @@ LL | pub trait Bar: Foo<Assoc=()> + Sized {
    |                              +++++++
 help: consider relaxing the implicit `Sized` restriction
    |
-LL | pub trait Foo<RHS=Self: ?Sized> {
-   |                       ++++++++
+LL | pub trait Foo<RHS: ?Sized=Self> {
+   |                  ++++++++
 
 error[E0277]: the size for values of type `Self` cannot be known at compilation time
   --> $DIR/issue-28576.rs:5:16
@@ -56,8 +56,8 @@ LL |     ) where Self: Sized;
    |       +++++++++++++++++
 help: consider relaxing the implicit `Sized` restriction
    |
-LL | pub trait Foo<RHS=Self: ?Sized> {
-   |                       ++++++++
+LL | pub trait Foo<RHS: ?Sized=Self> {
+   |                  ++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/traits/issue-33140-hack-boundaries.stderr b/tests/ui/traits/issue-33140-hack-boundaries.stderr
index 06e1dfd372751..d9c4efbb721c7 100644
--- a/tests/ui/traits/issue-33140-hack-boundaries.stderr
+++ b/tests/ui/traits/issue-33140-hack-boundaries.stderr
@@ -77,9 +77,4 @@ LL | impl Trait0 for dyn Send {}
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #56484 <https://github.com/rust-lang/rust/issues/56484>
-note: the lint level is defined here
-  --> $DIR/issue-33140-hack-boundaries.rs:2:10
-   |
-LL | #![allow(order_dependent_trait_objects)]
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/tests/ui/traits/unspecified-self-in-trait-ref.stderr b/tests/ui/traits/unspecified-self-in-trait-ref.stderr
index b5e8e88676c61..3614348ceedc7 100644
--- a/tests/ui/traits/unspecified-self-in-trait-ref.stderr
+++ b/tests/ui/traits/unspecified-self-in-trait-ref.stderr
@@ -7,7 +7,7 @@ LL |     let a = Foo::lol();
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
    = note: `#[warn(bare_trait_objects)]` on by default
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL |     let a = <dyn Foo>::lol();
    |             ++++    +
@@ -26,7 +26,7 @@ LL |     let b = Foo::<_>::lol();
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL |     let b = <dyn Foo::<_>>::lol();
    |             ++++         +
@@ -45,7 +45,7 @@ LL |     let c = Bar::lol();
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL |     let c = <dyn Bar>::lol();
    |             ++++    +
@@ -64,7 +64,7 @@ LL |     let d = Bar::<usize, _>::lol();
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL |     let d = <dyn Bar::<usize, _>>::lol();
    |             ++++                +
@@ -83,7 +83,7 @@ LL |     let e = Bar::<usize>::lol();
    |
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-help: use `dyn`
+help: if this is an object-safe trait, use `dyn`
    |
 LL |     let e = <dyn Bar::<usize>>::lol();
    |             ++++             +