about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs616
-rw-r--r--compiler/rustc_ast/src/visit.rs1215
-rw-r--r--compiler/rustc_attr_data_structures/src/attributes.rs44
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs5
-rw-r--r--compiler/rustc_const_eval/src/check_consts/check.rs5
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs15
-rw-r--r--compiler/rustc_expand/messages.ftl1
-rw-r--r--compiler/rustc_expand/src/config.rs11
-rw-r--r--compiler/rustc_expand/src/errors.rs4
-rw-r--r--compiler/rustc_feature/src/accepted.rs2
-rw-r--r--compiler/rustc_feature/src/removed.rs182
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs42
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs2
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs48
-rw-r--r--compiler/rustc_passes/src/check_attr.rs22
-rw-r--r--compiler/rustc_target/src/target_features.rs4
-rw-r--r--library/compiler-builtins/compiler-builtins/src/lib.rs1
-rw-r--r--library/compiler-builtins/compiler-builtins/src/probestack.rs440
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/macros/mod.rs13
-rw-r--r--library/core/src/ptr/const_ptr.rs64
-rw-r--r--library/core/src/ptr/docs/as_uninit_slice.md44
-rw-r--r--library/core/src/ptr/docs/is_null.md18
-rw-r--r--library/core/src/ptr/mut_ptr.rs68
-rw-r--r--library/core/src/slice/mod.rs1
-rw-r--r--library/std/src/io/mod.rs40
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs3
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs3
-rw-r--r--src/bootstrap/src/core/builder/cargo.rs2
-rw-r--r--src/bootstrap/src/core/builder/mod.rs17
-rw-r--r--src/bootstrap/src/core/builder/tests.rs2
-rw-r--r--src/bootstrap/src/core/config/config.rs138
-rw-r--r--src/bootstrap/src/core/config/flags.rs3
-rw-r--r--src/bootstrap/src/core/download.rs75
-rw-r--r--src/bootstrap/src/core/sanity.rs2
-rw-r--r--src/bootstrap/src/lib.rs159
-rw-r--r--src/bootstrap/src/utils/channel.rs13
-rw-r--r--src/bootstrap/src/utils/exec.rs16
-rw-r--r--src/bootstrap/src/utils/execution_context.rs202
-rw-r--r--src/bootstrap/src/utils/mod.rs1
-rw-r--r--src/bootstrap/src/utils/render_tests.rs3
-rw-r--r--src/doc/rustc/src/platform-support.md38
-rw-r--r--src/librustdoc/clean/auto_trait.rs4
-rw-r--r--src/librustdoc/clean/blanket_impl.rs6
-rw-r--r--src/librustdoc/clean/inline.rs69
-rw-r--r--src/librustdoc/clean/mod.rs14
-rw-r--r--tests/crashes/139825.rs5
-rw-r--r--tests/ui/abi/unsupported.aarch64.stderr54
-rw-r--r--tests/ui/abi/unsupported.arm.stderr54
-rw-r--r--tests/ui/abi/unsupported.i686.stderr12
-rw-r--r--tests/ui/abi/unsupported.riscv32.stderr54
-rw-r--r--tests/ui/abi/unsupported.riscv64.stderr54
-rw-r--r--tests/ui/abi/unsupported.rs8
-rw-r--r--tests/ui/abi/unsupported.x64.stderr46
-rw-r--r--tests/ui/abi/unsupported.x64_win.stderr66
-rw-r--r--tests/ui/check-cfg/hrtb-crash.rs7
-rw-r--r--tests/ui/check-cfg/hrtb-crash.stderr13
-rw-r--r--tests/ui/deprecation/deprecated_no_stack_check.rs2
-rw-r--r--tests/ui/deprecation/deprecated_no_stack_check.stderr4
-rw-r--r--tests/ui/feature-gates/feature-gate-coverage-attribute.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-coverage-attribute.stderr5
-rw-r--r--tests/ui/feature-gates/feature-gate-keylocker_x86.rs6
-rw-r--r--tests/ui/feature-gates/feature-gate-keylocker_x86.stderr13
-rw-r--r--tests/ui/feature-gates/gated-bad-feature.rs1
-rw-r--r--tests/ui/feature-gates/gated-bad-feature.stderr16
-rw-r--r--tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.rs6
-rw-r--r--tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.stderr20
-rw-r--r--tests/ui/macros/macro-reexport-removed.rs1
-rw-r--r--tests/ui/macros/macro-reexport-removed.stderr5
-rw-r--r--tests/ui/rustdoc/renamed-features-rustdoc_internals.rs2
-rw-r--r--tests/ui/rustdoc/renamed-features-rustdoc_internals.stderr6
-rw-r--r--tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs1
-rw-r--r--tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.stderr5
-rw-r--r--tests/ui/type/pattern_types/matching.rs1
75 files changed, 1837 insertions, 2312 deletions
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 77cbdde61a4..71a47dcfcba 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -11,7 +11,7 @@ use std::ops::DerefMut;
 use std::panic;
 
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
-use rustc_data_structures::stack::ensure_sufficient_stack;
+use rustc_span::source_map::Spanned;
 use rustc_span::{Ident, Span};
 use smallvec::{Array, SmallVec, smallvec};
 use thin_vec::ThinVec;
@@ -19,7 +19,7 @@ use thin_vec::ThinVec;
 use crate::ast::*;
 use crate::ptr::P;
 use crate::tokenstream::*;
-use crate::visit::{AssocCtxt, BoundKind, FnCtxt, try_visit, visit_opt, walk_list};
+use crate::visit::{AssocCtxt, BoundKind, FnCtxt, VisitorResult, try_visit, visit_opt, walk_list};
 
 pub trait ExpectOne<A: Array> {
     fn expect_one(self, err: &'static str) -> A::Item;
@@ -32,7 +32,22 @@ impl<A: Array> ExpectOne<A> for SmallVec<A> {
     }
 }
 
-pub trait MutVisitor: Sized {
+mod sealed {
+    use rustc_ast_ir::visit::VisitorResult;
+
+    /// This is for compatibility with the regular `Visitor`.
+    pub trait MutVisitorResult {
+        type Result: VisitorResult;
+    }
+
+    impl<T> MutVisitorResult for T {
+        type Result = ();
+    }
+}
+
+use sealed::MutVisitorResult;
+
+pub trait MutVisitor: Sized + MutVisitorResult<Result = ()> {
     // Methods in this trait have one of three forms:
     //
     //   fn visit_t(&mut self, t: &mut T);                      // common
@@ -227,14 +242,6 @@ pub trait MutVisitor: Sized {
         walk_generic_args(self, p);
     }
 
-    fn visit_angle_bracketed_parameter_data(&mut self, p: &mut AngleBracketedArgs) {
-        walk_angle_bracketed_parameter_data(self, p);
-    }
-
-    fn visit_parenthesized_parameter_data(&mut self, p: &mut ParenthesizedArgs) {
-        walk_parenthesized_parameter_data(self, p);
-    }
-
     fn visit_local(&mut self, l: &mut Local) {
         walk_local(self, l);
     }
@@ -303,10 +310,6 @@ pub trait MutVisitor: Sized {
         walk_flat_map_expr_field(self, f)
     }
 
-    fn visit_where_clause(&mut self, where_clause: &mut WhereClause) {
-        walk_where_clause(self, where_clause);
-    }
-
     fn flat_map_where_predicate(
         &mut self,
         where_predicate: WherePredicate,
@@ -385,19 +388,14 @@ generate_flat_map_visitor_fns! {
     visit_generic_params, GenericParam, flat_map_generic_param;
     visit_stmts, Stmt, flat_map_stmt;
     visit_exprs, P<Expr>, filter_map_expr;
+    visit_expr_fields, ExprField, flat_map_expr_field;
     visit_pat_fields, PatField, flat_map_pat_field;
     visit_variants, Variant, flat_map_variant;
     visit_assoc_items, P<AssocItem>, flat_map_assoc_item, ctxt: AssocCtxt;
-}
-
-#[inline]
-fn visit_vec<T, F>(elems: &mut Vec<T>, mut visit_elem: F)
-where
-    F: FnMut(&mut T),
-{
-    for elem in elems {
-        visit_elem(elem);
-    }
+    visit_where_predicates, WherePredicate, flat_map_where_predicate;
+    visit_params, Param, flat_map_param;
+    visit_field_defs, FieldDef, flat_map_field_def;
+    visit_arms, Arm, flat_map_arm;
 }
 
 #[inline]
@@ -410,40 +408,12 @@ where
     }
 }
 
-#[inline]
-fn visit_opt<T, F>(opt: &mut Option<T>, mut visit_elem: F)
-where
-    F: FnMut(&mut T),
-{
-    if let Some(elem) = opt {
-        visit_elem(elem);
-    }
-}
-
 fn visit_attrs<T: MutVisitor>(vis: &mut T, attrs: &mut AttrVec) {
     for attr in attrs.iter_mut() {
         vis.visit_attribute(attr);
     }
 }
 
-fn visit_attr_args<T: MutVisitor>(vis: &mut T, args: &mut AttrArgs) {
-    match args {
-        AttrArgs::Empty => {}
-        AttrArgs::Delimited(args) => visit_delim_args(vis, args),
-        AttrArgs::Eq { eq_span, expr } => {
-            vis.visit_expr(expr);
-            vis.visit_span(eq_span);
-        }
-    }
-}
-
-fn visit_delim_args<T: MutVisitor>(vis: &mut T, args: &mut DelimArgs) {
-    let DelimArgs { dspan, delim: _, tokens: _ } = args;
-    let DelimSpan { open, close } = dspan;
-    vis.visit_span(open);
-    vis.visit_span(close);
-}
-
 pub fn walk_flat_map_pat_field<T: MutVisitor>(
     vis: &mut T,
     mut fp: PatField,
@@ -461,40 +431,11 @@ fn visit_nested_use_tree<V: MutVisitor>(
     vis.visit_use_tree(nested_tree);
 }
 
-pub fn walk_arm<T: MutVisitor>(vis: &mut T, arm: &mut Arm) {
-    let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = arm;
-    vis.visit_id(id);
-    visit_attrs(vis, attrs);
-    vis.visit_pat(pat);
-    visit_opt(guard, |guard| vis.visit_expr(guard));
-    visit_opt(body, |body| vis.visit_expr(body));
-    vis.visit_span(span);
-}
-
 pub fn walk_flat_map_arm<T: MutVisitor>(vis: &mut T, mut arm: Arm) -> SmallVec<[Arm; 1]> {
     vis.visit_arm(&mut arm);
     smallvec![arm]
 }
 
-fn walk_assoc_item_constraint<T: MutVisitor>(
-    vis: &mut T,
-    AssocItemConstraint { id, ident, gen_args, kind, span }: &mut AssocItemConstraint,
-) {
-    vis.visit_id(id);
-    vis.visit_ident(ident);
-    if let Some(gen_args) = gen_args {
-        vis.visit_generic_args(gen_args);
-    }
-    match kind {
-        AssocItemConstraintKind::Equality { term } => match term {
-            Term::Ty(ty) => vis.visit_ty(ty),
-            Term::Const(c) => vis.visit_anon_const(c),
-        },
-        AssocItemConstraintKind::Bound { bounds } => visit_bounds(vis, bounds, BoundKind::Bound),
-    }
-    vis.visit_span(span);
-}
-
 pub fn walk_flat_map_variant<T: MutVisitor>(
     vis: &mut T,
     mut variant: Variant,
@@ -503,64 +444,6 @@ pub fn walk_flat_map_variant<T: MutVisitor>(
     smallvec![variant]
 }
 
-fn walk_generic_args<T: MutVisitor>(vis: &mut T, generic_args: &mut GenericArgs) {
-    match generic_args {
-        GenericArgs::AngleBracketed(data) => vis.visit_angle_bracketed_parameter_data(data),
-        GenericArgs::Parenthesized(data) => vis.visit_parenthesized_parameter_data(data),
-        GenericArgs::ParenthesizedElided(span) => vis.visit_span(span),
-    }
-}
-
-fn walk_generic_arg<T: MutVisitor>(vis: &mut T, arg: &mut GenericArg) {
-    match arg {
-        GenericArg::Lifetime(lt) => vis.visit_lifetime(lt),
-        GenericArg::Type(ty) => vis.visit_ty(ty),
-        GenericArg::Const(ct) => vis.visit_anon_const(ct),
-    }
-}
-
-fn walk_angle_bracketed_parameter_data<T: MutVisitor>(vis: &mut T, data: &mut AngleBracketedArgs) {
-    let AngleBracketedArgs { args, span } = data;
-    visit_thin_vec(args, |arg| match arg {
-        AngleBracketedArg::Arg(arg) => vis.visit_generic_arg(arg),
-        AngleBracketedArg::Constraint(constraint) => vis.visit_assoc_item_constraint(constraint),
-    });
-    vis.visit_span(span);
-}
-
-fn walk_parenthesized_parameter_data<T: MutVisitor>(vis: &mut T, args: &mut ParenthesizedArgs) {
-    let ParenthesizedArgs { inputs, output, span, inputs_span } = args;
-    visit_thin_vec(inputs, |input| vis.visit_ty(input));
-    vis.visit_fn_ret_ty(output);
-    vis.visit_span(span);
-    vis.visit_span(inputs_span);
-}
-
-fn walk_attribute<T: MutVisitor>(vis: &mut T, attr: &mut Attribute) {
-    let Attribute { kind, id: _, style: _, span } = attr;
-    match kind {
-        AttrKind::Normal(normal) => {
-            let NormalAttr { item: AttrItem { unsafety: _, path, args, tokens: _ }, tokens: _ } =
-                &mut **normal;
-            vis.visit_path(path);
-            visit_attr_args(vis, args);
-        }
-        AttrKind::DocComment(_kind, _sym) => {}
-    }
-    vis.visit_span(span);
-}
-
-fn walk_mac<T: MutVisitor>(vis: &mut T, mac: &mut MacCall) {
-    let MacCall { path, args } = mac;
-    vis.visit_path(path);
-    visit_delim_args(vis, args);
-}
-
-fn walk_macro_def<T: MutVisitor>(vis: &mut T, macro_def: &mut MacroDef) {
-    let MacroDef { body, macro_rules: _ } = macro_def;
-    visit_delim_args(vis, body);
-}
-
 fn walk_meta_list_item<T: MutVisitor>(vis: &mut T, li: &mut MetaItemInner) {
     match li {
         MetaItemInner::MetaItem(mi) => vis.visit_meta_item(mi),
@@ -578,138 +461,11 @@ fn walk_meta_item<T: MutVisitor>(vis: &mut T, mi: &mut MetaItem) {
     vis.visit_span(span);
 }
 
-pub fn walk_param<T: MutVisitor>(vis: &mut T, param: &mut Param) {
-    let Param { attrs, id, pat, span, ty, is_placeholder: _ } = param;
-    vis.visit_id(id);
-    visit_attrs(vis, attrs);
-    vis.visit_pat(pat);
-    vis.visit_ty(ty);
-    vis.visit_span(span);
-}
-
 pub fn walk_flat_map_param<T: MutVisitor>(vis: &mut T, mut param: Param) -> SmallVec<[Param; 1]> {
     vis.visit_param(&mut param);
     smallvec![param]
 }
 
-fn walk_closure_binder<T: MutVisitor>(vis: &mut T, binder: &mut ClosureBinder) {
-    match binder {
-        ClosureBinder::NotPresent => {}
-        ClosureBinder::For { span: _, generic_params } => {
-            generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
-        }
-    }
-}
-
-fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
-    match kind {
-        FnKind::Fn(
-            _ctxt,
-            _vis,
-            Fn {
-                defaultness,
-                ident,
-                generics,
-                contract,
-                body,
-                sig: FnSig { header, decl, span },
-                define_opaque,
-            },
-        ) => {
-            // Visibility is visited as a part of the item.
-            visit_defaultness(vis, defaultness);
-            vis.visit_ident(ident);
-            vis.visit_fn_header(header);
-            vis.visit_generics(generics);
-            vis.visit_fn_decl(decl);
-            if let Some(contract) = contract {
-                vis.visit_contract(contract);
-            }
-            if let Some(body) = body {
-                vis.visit_block(body);
-            }
-            vis.visit_span(span);
-
-            walk_define_opaques(vis, define_opaque);
-        }
-        FnKind::Closure(binder, coroutine_kind, decl, body) => {
-            vis.visit_closure_binder(binder);
-            coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind));
-            vis.visit_fn_decl(decl);
-            vis.visit_expr(body);
-        }
-    }
-}
-
-fn walk_contract<T: MutVisitor>(vis: &mut T, contract: &mut FnContract) {
-    let FnContract { requires, ensures } = contract;
-    if let Some(pred) = requires {
-        vis.visit_expr(pred);
-    }
-    if let Some(pred) = ensures {
-        vis.visit_expr(pred);
-    }
-}
-
-fn walk_fn_decl<T: MutVisitor>(vis: &mut T, decl: &mut FnDecl) {
-    let FnDecl { inputs, output } = decl;
-    inputs.flat_map_in_place(|param| vis.flat_map_param(param));
-    vis.visit_fn_ret_ty(output);
-}
-
-fn walk_fn_ret_ty<T: MutVisitor>(vis: &mut T, fn_ret_ty: &mut FnRetTy) {
-    match fn_ret_ty {
-        FnRetTy::Default(span) => vis.visit_span(span),
-        FnRetTy::Ty(ty) => vis.visit_ty(ty),
-    }
-}
-
-fn walk_param_bound<T: MutVisitor>(vis: &mut T, pb: &mut GenericBound) {
-    match pb {
-        GenericBound::Trait(trait_ref) => vis.visit_poly_trait_ref(trait_ref),
-        GenericBound::Outlives(lifetime) => walk_lifetime(vis, lifetime),
-        GenericBound::Use(args, span) => {
-            for arg in args {
-                vis.visit_precise_capturing_arg(arg);
-            }
-            vis.visit_span(span);
-        }
-    }
-}
-
-fn walk_precise_capturing_arg<T: MutVisitor>(vis: &mut T, arg: &mut PreciseCapturingArg) {
-    match arg {
-        PreciseCapturingArg::Lifetime(lt) => {
-            vis.visit_lifetime(lt);
-        }
-        PreciseCapturingArg::Arg(path, id) => {
-            vis.visit_id(id);
-            vis.visit_path(path);
-        }
-    }
-}
-
-pub fn walk_generic_param<T: MutVisitor>(vis: &mut T, param: &mut GenericParam) {
-    let GenericParam { id, ident, attrs, bounds, kind, colon_span, is_placeholder: _ } = param;
-    vis.visit_id(id);
-    visit_attrs(vis, attrs);
-    vis.visit_ident(ident);
-    visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound));
-    match kind {
-        GenericParamKind::Lifetime => {}
-        GenericParamKind::Type { default } => {
-            visit_opt(default, |default| vis.visit_ty(default));
-        }
-        GenericParamKind::Const { ty, kw_span: _, default } => {
-            vis.visit_ty(ty);
-            visit_opt(default, |default| vis.visit_anon_const(default));
-        }
-    }
-    if let Some(colon_span) = colon_span {
-        vis.visit_span(colon_span);
-    }
-}
-
 pub fn walk_flat_map_generic_param<T: MutVisitor>(
     vis: &mut T,
     mut param: GenericParam,
@@ -718,13 +474,6 @@ pub fn walk_flat_map_generic_param<T: MutVisitor>(
     smallvec![param]
 }
 
-fn walk_generics<T: MutVisitor>(vis: &mut T, generics: &mut Generics) {
-    let Generics { params, where_clause, span } = generics;
-    params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
-    vis.visit_where_clause(where_clause);
-    vis.visit_span(span);
-}
-
 fn walk_ty_alias_where_clauses<T: MutVisitor>(vis: &mut T, tawcs: &mut TyAliasWhereClauses) {
     let TyAliasWhereClauses { before, after, split: _ } = tawcs;
     let TyAliasWhereClause { has_where_token: _, span: span_before } = before;
@@ -733,70 +482,14 @@ fn walk_ty_alias_where_clauses<T: MutVisitor>(vis: &mut T, tawcs: &mut TyAliasWh
     vis.visit_span(span_after);
 }
 
-fn walk_where_clause<T: MutVisitor>(vis: &mut T, wc: &mut WhereClause) {
-    let WhereClause { has_where_token: _, predicates, span } = wc;
-    predicates.flat_map_in_place(|predicate| vis.flat_map_where_predicate(predicate));
-    vis.visit_span(span);
-}
-
 pub fn walk_flat_map_where_predicate<T: MutVisitor>(
     vis: &mut T,
     mut pred: WherePredicate,
 ) -> SmallVec<[WherePredicate; 1]> {
-    let WherePredicate { attrs, kind, id, span, is_placeholder: _ } = &mut pred;
-    vis.visit_id(id);
-    visit_attrs(vis, attrs);
-    vis.visit_where_predicate_kind(kind);
-    vis.visit_span(span);
+    walk_where_predicate(vis, &mut pred);
     smallvec![pred]
 }
 
-pub fn walk_where_predicate_kind<T: MutVisitor>(vis: &mut T, kind: &mut WherePredicateKind) {
-    match kind {
-        WherePredicateKind::BoundPredicate(bp) => {
-            let WhereBoundPredicate { bound_generic_params, bounded_ty, bounds } = bp;
-            bound_generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
-            vis.visit_ty(bounded_ty);
-            visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound));
-        }
-        WherePredicateKind::RegionPredicate(rp) => {
-            let WhereRegionPredicate { lifetime, bounds } = rp;
-            vis.visit_lifetime(lifetime);
-            visit_vec(bounds, |bound| vis.visit_param_bound(bound, BoundKind::Bound));
-        }
-        WherePredicateKind::EqPredicate(ep) => {
-            let WhereEqPredicate { lhs_ty, rhs_ty } = ep;
-            vis.visit_ty(lhs_ty);
-            vis.visit_ty(rhs_ty);
-        }
-    }
-}
-
-fn walk_variant_data<T: MutVisitor>(vis: &mut T, vdata: &mut VariantData) {
-    match vdata {
-        VariantData::Struct { fields, recovered: _ } => {
-            fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
-        }
-        VariantData::Tuple(fields, id) => {
-            vis.visit_id(id);
-            fields.flat_map_in_place(|field| vis.flat_map_field_def(field));
-        }
-        VariantData::Unit(id) => vis.visit_id(id),
-    }
-}
-
-pub fn walk_field_def<T: MutVisitor>(visitor: &mut T, fd: &mut FieldDef) {
-    let FieldDef { span, ident, vis, id, ty, attrs, is_placeholder: _, safety, default } = fd;
-    visitor.visit_id(id);
-    visit_attrs(visitor, attrs);
-    visitor.visit_vis(vis);
-    visit_safety(visitor, safety);
-    visit_opt(ident, |ident| visitor.visit_ident(ident));
-    visitor.visit_ty(ty);
-    visit_opt(default, |default| visitor.visit_anon_const(default));
-    visitor.visit_span(span);
-}
-
 pub fn walk_flat_map_field_def<T: MutVisitor>(
     vis: &mut T,
     mut fd: FieldDef,
@@ -846,255 +539,6 @@ pub fn walk_flat_map_assoc_item(
     smallvec![item]
 }
 
-fn walk_inline_asm<T: MutVisitor>(vis: &mut T, asm: &mut InlineAsm) {
-    // FIXME: Visit spans inside all this currently ignored stuff.
-    let InlineAsm {
-        asm_macro: _,
-        template: _,
-        template_strs: _,
-        operands,
-        clobber_abis: _,
-        options: _,
-        line_spans: _,
-    } = asm;
-    for (op, span) in operands {
-        match op {
-            InlineAsmOperand::In { expr, reg: _ }
-            | InlineAsmOperand::Out { expr: Some(expr), reg: _, late: _ }
-            | InlineAsmOperand::InOut { expr, reg: _, late: _ } => vis.visit_expr(expr),
-            InlineAsmOperand::Out { expr: None, reg: _, late: _ } => {}
-            InlineAsmOperand::SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
-                vis.visit_expr(in_expr);
-                if let Some(out_expr) = out_expr {
-                    vis.visit_expr(out_expr);
-                }
-            }
-            InlineAsmOperand::Const { anon_const } => vis.visit_anon_const(anon_const),
-            InlineAsmOperand::Sym { sym } => vis.visit_inline_asm_sym(sym),
-            InlineAsmOperand::Label { block } => vis.visit_block(block),
-        }
-        vis.visit_span(span);
-    }
-}
-
-fn walk_inline_asm_sym<T: MutVisitor>(
-    vis: &mut T,
-    InlineAsmSym { id, qself, path }: &mut InlineAsmSym,
-) {
-    vis.visit_id(id);
-    vis.visit_qself(qself);
-    vis.visit_path(path);
-}
-
-fn walk_format_args<T: MutVisitor>(vis: &mut T, fmt: &mut FormatArgs) {
-    // FIXME: visit the template exhaustively.
-    let FormatArgs { span, template: _, arguments, uncooked_fmt_str: _ } = fmt;
-    for FormatArgument { kind, expr } in arguments.all_args_mut() {
-        match kind {
-            FormatArgumentKind::Named(ident) | FormatArgumentKind::Captured(ident) => {
-                vis.visit_ident(ident)
-            }
-            FormatArgumentKind::Normal => {}
-        }
-        vis.visit_expr(expr);
-    }
-    vis.visit_span(span);
-}
-
-pub fn walk_expr<T: MutVisitor>(vis: &mut T, Expr { kind, id, span, attrs, tokens: _ }: &mut Expr) {
-    vis.visit_id(id);
-    visit_attrs(vis, attrs);
-    match kind {
-        ExprKind::Array(exprs) => visit_exprs(vis, exprs),
-        ExprKind::ConstBlock(anon_const) => {
-            vis.visit_anon_const(anon_const);
-        }
-        ExprKind::Repeat(expr, count) => {
-            vis.visit_expr(expr);
-            vis.visit_anon_const(count);
-        }
-        ExprKind::Tup(exprs) => visit_exprs(vis, exprs),
-        ExprKind::Call(f, args) => {
-            vis.visit_expr(f);
-            visit_exprs(vis, args);
-        }
-        ExprKind::MethodCall(box MethodCall {
-            seg: PathSegment { ident, id, args: seg_args },
-            receiver,
-            args: call_args,
-            span,
-        }) => {
-            vis.visit_method_receiver_expr(receiver);
-            vis.visit_id(id);
-            vis.visit_ident(ident);
-            visit_opt(seg_args, |args| vis.visit_generic_args(args));
-            visit_exprs(vis, call_args);
-            vis.visit_span(span);
-        }
-        ExprKind::Binary(binop, lhs, rhs) => {
-            vis.visit_expr(lhs);
-            vis.visit_expr(rhs);
-            vis.visit_span(&mut binop.span);
-        }
-        ExprKind::Unary(_unop, ohs) => vis.visit_expr(ohs),
-        ExprKind::Cast(expr, ty) => {
-            vis.visit_expr(expr);
-            vis.visit_ty(ty);
-        }
-        ExprKind::Type(expr, ty) => {
-            vis.visit_expr(expr);
-            vis.visit_ty(ty);
-        }
-        ExprKind::AddrOf(_kind, _mut, ohs) => vis.visit_expr(ohs),
-        ExprKind::Let(pat, scrutinee, span, _recovered) => {
-            vis.visit_pat(pat);
-            vis.visit_expr(scrutinee);
-            vis.visit_span(span);
-        }
-        ExprKind::If(cond, tr, fl) => {
-            vis.visit_expr(cond);
-            vis.visit_block(tr);
-            visit_opt(fl, |fl| ensure_sufficient_stack(|| vis.visit_expr(fl)));
-        }
-        ExprKind::While(cond, body, label) => {
-            visit_opt(label, |label| vis.visit_label(label));
-            vis.visit_expr(cond);
-            vis.visit_block(body);
-        }
-        ExprKind::ForLoop { pat, iter, body, label, kind: _ } => {
-            visit_opt(label, |label| vis.visit_label(label));
-            vis.visit_pat(pat);
-            vis.visit_expr(iter);
-            vis.visit_block(body);
-        }
-        ExprKind::Loop(body, label, span) => {
-            visit_opt(label, |label| vis.visit_label(label));
-            vis.visit_block(body);
-            vis.visit_span(span);
-        }
-        ExprKind::Match(expr, arms, _kind) => {
-            vis.visit_expr(expr);
-            arms.flat_map_in_place(|arm| vis.flat_map_arm(arm));
-        }
-        ExprKind::Closure(box Closure {
-            binder,
-            capture_clause,
-            constness,
-            coroutine_kind,
-            movability: _,
-            fn_decl,
-            body,
-            fn_decl_span,
-            fn_arg_span,
-        }) => {
-            visit_constness(vis, constness);
-            vis.visit_capture_by(capture_clause);
-            vis.visit_fn(FnKind::Closure(binder, coroutine_kind, fn_decl, body), *span, *id);
-            vis.visit_span(fn_decl_span);
-            vis.visit_span(fn_arg_span);
-        }
-        ExprKind::Block(blk, label) => {
-            visit_opt(label, |label| vis.visit_label(label));
-            vis.visit_block(blk);
-        }
-        ExprKind::Gen(_capture_by, body, _kind, decl_span) => {
-            vis.visit_block(body);
-            vis.visit_span(decl_span);
-        }
-        ExprKind::Await(expr, await_kw_span) => {
-            vis.visit_expr(expr);
-            vis.visit_span(await_kw_span);
-        }
-        ExprKind::Use(expr, use_kw_span) => {
-            vis.visit_expr(expr);
-            vis.visit_span(use_kw_span);
-        }
-        ExprKind::Assign(el, er, span) => {
-            vis.visit_expr(el);
-            vis.visit_expr(er);
-            vis.visit_span(span);
-        }
-        ExprKind::AssignOp(_op, el, er) => {
-            vis.visit_expr(el);
-            vis.visit_expr(er);
-        }
-        ExprKind::Field(el, ident) => {
-            vis.visit_expr(el);
-            vis.visit_ident(ident);
-        }
-        ExprKind::Index(el, er, brackets_span) => {
-            vis.visit_expr(el);
-            vis.visit_expr(er);
-            vis.visit_span(brackets_span);
-        }
-        ExprKind::Range(e1, e2, _lim) => {
-            visit_opt(e1, |e1| vis.visit_expr(e1));
-            visit_opt(e2, |e2| vis.visit_expr(e2));
-        }
-        ExprKind::Underscore => {}
-        ExprKind::Path(qself, path) => {
-            vis.visit_qself(qself);
-            vis.visit_path(path);
-        }
-        ExprKind::Break(label, expr) => {
-            visit_opt(label, |label| vis.visit_label(label));
-            visit_opt(expr, |expr| vis.visit_expr(expr));
-        }
-        ExprKind::Continue(label) => {
-            visit_opt(label, |label| vis.visit_label(label));
-        }
-        ExprKind::Ret(expr) => {
-            visit_opt(expr, |expr| vis.visit_expr(expr));
-        }
-        ExprKind::Yeet(expr) => {
-            visit_opt(expr, |expr| vis.visit_expr(expr));
-        }
-        ExprKind::Become(expr) => vis.visit_expr(expr),
-        ExprKind::InlineAsm(asm) => vis.visit_inline_asm(asm),
-        ExprKind::FormatArgs(fmt) => vis.visit_format_args(fmt),
-        ExprKind::OffsetOf(container, fields) => {
-            vis.visit_ty(container);
-            for field in fields.iter_mut() {
-                vis.visit_ident(field);
-            }
-        }
-        ExprKind::MacCall(mac) => vis.visit_mac_call(mac),
-        ExprKind::Struct(se) => {
-            let StructExpr { qself, path, fields, rest } = se.deref_mut();
-            vis.visit_qself(qself);
-            vis.visit_path(path);
-            fields.flat_map_in_place(|field| vis.flat_map_expr_field(field));
-            match rest {
-                StructRest::Base(expr) => vis.visit_expr(expr),
-                StructRest::Rest(_span) => {}
-                StructRest::None => {}
-            }
-        }
-        ExprKind::Paren(expr) => {
-            vis.visit_expr(expr);
-        }
-        ExprKind::Yield(kind) => {
-            let expr = kind.expr_mut();
-            if let Some(expr) = expr {
-                vis.visit_expr(expr);
-            }
-        }
-        ExprKind::Try(expr) => vis.visit_expr(expr),
-        ExprKind::TryBlock(body) => vis.visit_block(body),
-        ExprKind::Lit(_token) => {}
-        ExprKind::IncludedBytes(_bytes) => {}
-        ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
-            vis.visit_expr(expr);
-            if let Some(ty) = ty {
-                vis.visit_ty(ty);
-            }
-        }
-        ExprKind::Err(_guar) => {}
-        ExprKind::Dummy => {}
-    }
-    vis.visit_span(span);
-}
-
 pub fn walk_filter_map_expr<T: MutVisitor>(vis: &mut T, mut e: P<Expr>) -> Option<P<Expr>> {
     vis.visit_expr(&mut e);
     Some(e)
@@ -1139,18 +583,6 @@ fn walk_flat_map_stmt_kind<T: MutVisitor>(vis: &mut T, kind: StmtKind) -> SmallV
     }
 }
 
-fn walk_vis<T: MutVisitor>(vis: &mut T, visibility: &mut Visibility) {
-    let Visibility { kind, span, tokens: _ } = visibility;
-    match kind {
-        VisibilityKind::Public | VisibilityKind::Inherited => {}
-        VisibilityKind::Restricted { path, id, shorthand: _ } => {
-            vis.visit_id(id);
-            vis.visit_path(path);
-        }
-    }
-    vis.visit_span(span);
-}
-
 fn walk_capture_by<T: MutVisitor>(vis: &mut T, capture_by: &mut CaptureBy) {
     match capture_by {
         CaptureBy::Ref => {}
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index d2f22b04a67..c88aa5c33ea 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -15,11 +15,13 @@
 
 pub use rustc_ast_ir::visit::VisitorResult;
 pub use rustc_ast_ir::{try_visit, visit_opt, walk_list, walk_visitable_list};
+use rustc_span::source_map::Spanned;
 use rustc_span::{Ident, Span};
 use thin_vec::ThinVec;
 
 use crate::ast::*;
 use crate::ptr::P;
+use crate::tokenstream::DelimSpan;
 
 #[derive(Copy, Clone, Debug, PartialEq)]
 pub enum AssocCtxt {
@@ -237,8 +239,8 @@ pub trait Visitor<'ast>: Sized {
     fn visit_id(&mut self, _id: NodeId) -> Self::Result {
         Self::Result::output()
     }
-    fn visit_macro_def(&mut self, _mac: &'ast MacroDef) -> Self::Result {
-        Self::Result::output()
+    fn visit_macro_def(&mut self, macro_def: &'ast MacroDef) -> Self::Result {
+        walk_macro_def(self, macro_def)
     }
     fn visit_path(&mut self, path: &'ast Path) -> Self::Result {
         walk_path(self, path)
@@ -320,8 +322,8 @@ macro_rules! common_visitor_and_walkers {
                 id: NodeId,
                 visibility: &$($lt)? $($mut)? Visibility,
                 ctxt: Self::Ctxt,
-                visitor: &mut V,
-            ) $(-> <V as Visitor<$lt>>::Result)?;
+                vis: &mut V,
+            ) -> V::Result;
         }
 
         // this is only used by the MutVisitor. We include this symmetry here to make writing other functions easier
@@ -329,12 +331,12 @@ macro_rules! common_visitor_and_walkers {
             #[expect(unused, rustc::pass_by_value)]
             #[inline]
         )?
-        fn visit_span<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, span: &$($lt)? $($mut)? Span) $(-> <V as Visitor<$lt>>::Result)? {
+        fn visit_span<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, span: &$($lt)? $($mut)? Span) -> V::Result {
             $(
                 ${ignore($mut)}
-                visitor.visit_span(span);
+                vis.visit_span(span);
             )?
-            $(${ignore($lt)}V::Result::output())?
+            V::Result::output()
         }
 
         /// helper since `Visitor` wants `NodeId` but `MutVisitor` wants `&mut NodeId`
@@ -342,34 +344,34 @@ macro_rules! common_visitor_and_walkers {
             #[expect(rustc::pass_by_value)]
         )?
         #[inline]
-        fn visit_id<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, id: &$($lt)? $($mut)? NodeId) $(-> <V as Visitor<$lt>>::Result)? {
+        fn visit_id<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, id: &$($lt)? $($mut)? NodeId) -> V::Result {
             // deref `&NodeId` into `NodeId` only for `Visitor`
-            visitor.visit_id( $(${ignore($lt)} * )? id)
+            vis.visit_id( $(${ignore($lt)} * )? id)
         }
 
         // this is only used by the MutVisitor. We include this symmetry here to make writing other functions easier
-        fn visit_safety<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, safety: &$($lt)? $($mut)? Safety) $(-> <V as Visitor<$lt>>::Result)? {
+        fn visit_safety<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, safety: &$($lt)? $($mut)? Safety) -> V::Result {
             match safety {
                 Safety::Unsafe(span) => visit_span(vis, span),
                 Safety::Safe(span) => visit_span(vis, span),
-                Safety::Default => { $(${ignore($lt)}V::Result::output())? }
+                Safety::Default => { V::Result::output() }
             }
         }
 
-        fn visit_constness<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, constness: &$($lt)? $($mut)? Const) $(-> <V as Visitor<$lt>>::Result)? {
+        fn visit_constness<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, constness: &$($lt)? $($mut)? Const) -> V::Result {
             match constness {
                 Const::Yes(span) => visit_span(vis, span),
                 Const::No => {
-                    $(<V as Visitor<$lt>>::Result::output())?
+                    V::Result::output()
                 }
             }
         }
 
-        fn visit_defaultness<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, defaultness: &$($lt)? $($mut)? Defaultness) $(-> <V as Visitor<$lt>>::Result)? {
+        fn visit_defaultness<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, defaultness: &$($lt)? $($mut)? Defaultness) -> V::Result {
             match defaultness {
                 Defaultness::Default(span) => visit_span(vis, span),
                 Defaultness::Final => {
-                    $(<V as Visitor<$lt>>::Result::output())?
+                    V::Result::output()
                 }
             }
         }
@@ -377,9 +379,9 @@ macro_rules! common_visitor_and_walkers {
         fn visit_polarity<$($lt,)? V: $Visitor$(<$lt>)?>(
             vis: &mut V,
             polarity: &$($lt)? $($mut)? ImplPolarity,
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             match polarity {
-                ImplPolarity::Positive => { $(<V as Visitor<$lt>>::Result::output())? }
+                ImplPolarity::Positive => { V::Result::output() }
                 ImplPolarity::Negative(span) => visit_span(vis, span),
             }
         }
@@ -390,7 +392,7 @@ macro_rules! common_visitor_and_walkers {
         fn visit_modifiers<$($lt,)? V: $Visitor$(<$lt>)?>(
             vis: &mut V,
             m: &$($lt)? $($mut)? TraitBoundModifiers
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             let TraitBoundModifiers { constness, asyncness, polarity } = m;
             match constness {
                 BoundConstness::Never => {}
@@ -404,26 +406,26 @@ macro_rules! common_visitor_and_walkers {
                 BoundPolarity::Positive => {}
                 BoundPolarity::Negative(span) | BoundPolarity::Maybe(span) => try_visit!(visit_span(vis, span)),
             }
-            $(<V as Visitor<$lt>>::Result::output())?
+            V::Result::output()
         }
 
-        fn visit_bounds<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, bounds: &$($lt)? $($mut)? GenericBounds, ctxt: BoundKind) $(-> <V as Visitor<$lt>>::Result)? {
+        fn visit_bounds<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, bounds: &$($lt)? $($mut)? GenericBounds, ctxt: BoundKind) -> V::Result {
             walk_list!(visitor, visit_param_bound, bounds, ctxt);
-            $(<V as Visitor<$lt>>::Result::output())?
+            V::Result::output()
         }
 
-        pub fn walk_label<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, Label { ident }: &$($lt)? $($mut)? Label) $(-> <V as Visitor<$lt>>::Result)? {
+        pub fn walk_label<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, Label { ident }: &$($lt)? $($mut)? Label) -> V::Result {
             visitor.visit_ident(ident)
         }
 
-        pub fn walk_fn_header<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, header: &$($lt)? $($mut)? FnHeader) $(-> <V as Visitor<$lt>>::Result)? {
+        pub fn walk_fn_header<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, header: &$($lt)? $($mut)? FnHeader) -> V::Result {
             let FnHeader { safety, coroutine_kind, constness, ext: _ } = header;
             try_visit!(visit_constness(visitor, constness));
             visit_opt!(visitor, visit_coroutine_kind, coroutine_kind);
             visit_safety(visitor, safety)
         }
 
-        pub fn walk_lifetime<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, Lifetime { id, ident }: &$($lt)? $($mut)? Lifetime) $(-> <V as Visitor<$lt>>::Result)? {
+        pub fn walk_lifetime<$($lt,)? V: $Visitor$(<$lt>)?>(visitor: &mut V, Lifetime { id, ident }: &$($lt)? $($mut)? Lifetime) -> V::Result {
             try_visit!(visit_id(visitor, id));
             visitor.visit_ident(ident)
         }
@@ -432,7 +434,7 @@ macro_rules! common_visitor_and_walkers {
             visitor: &mut V,
             item: &$($mut)? $($lt)? Item<K>,
             ctxt: K::Ctxt,
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             let Item { attrs, id, kind, vis, span, tokens: _ } = item;
             try_visit!(visit_id(visitor, id));
             walk_list!(visitor, visit_attribute, attrs);
@@ -444,7 +446,7 @@ macro_rules! common_visitor_and_walkers {
         pub fn walk_item<$($lt,)? V: $Visitor$(<$lt>)?, K: WalkItemKind<Ctxt = ()>>(
             visitor: &mut V,
             item: &$($mut)? $($lt)? Item<K>,
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             walk_item_ctxt(visitor, item, ())
         }
 
@@ -452,7 +454,7 @@ macro_rules! common_visitor_and_walkers {
             visitor: &mut V,
             item: &$($mut)? $($lt)? AssocItem,
             ctxt: AssocCtxt,
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             walk_item_ctxt(visitor, item, ctxt)
         }
 
@@ -465,7 +467,7 @@ macro_rules! common_visitor_and_walkers {
                 visibility: &$($lt)? $($mut)? Visibility,
                 _ctxt: Self::Ctxt,
                 vis: &mut V,
-            ) $(-> <V as Visitor<$lt>>::Result)? {
+            ) -> V::Result {
                 match self {
                     ItemKind::ExternCrate(_orig_name, ident) => vis.visit_ident(ident),
                     ItemKind::Use(use_tree) => vis.visit_use_tree(use_tree),
@@ -505,7 +507,7 @@ macro_rules! common_visitor_and_walkers {
                             }
                             ModKind::Unloaded => {}
                         }
-                        $(<V as Visitor<$lt>>::Result::output())?
+                        V::Result::output()
                     }
                     ItemKind::ForeignMod(nm) => vis.visit_foreign_mod(nm),
                     ItemKind::GlobalAsm(asm) => vis.visit_inline_asm(asm),
@@ -526,7 +528,7 @@ macro_rules! common_visitor_and_walkers {
                         $(${ignore($mut)}
                             walk_ty_alias_where_clauses(vis, where_clauses);
                         )?
-                        $(<V as Visitor<$lt>>::Result::output())?
+                        V::Result::output()
                     }
                     ItemKind::Enum(ident, generics, enum_definition) => {
                         try_visit!(vis.visit_ident(ident));
@@ -590,7 +592,7 @@ macro_rules! common_visitor_and_walkers {
                         try_visit!(vis.visit_ident(ident));
                         visit_opt!(vis, visit_ident, rename);
                         visit_opt!(vis, visit_block, body);
-                        $(<V as Visitor<$lt>>::Result::output())?
+                        V::Result::output()
                     }
                     ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
                         try_visit!(vis.visit_qself(qself));
@@ -602,7 +604,7 @@ macro_rules! common_visitor_and_walkers {
                             }
                         }
                         visit_opt!(vis, visit_block, body);
-                        $(<V as Visitor<$lt>>::Result::output())?
+                        V::Result::output()
                     }
                 }
             }
@@ -611,7 +613,7 @@ macro_rules! common_visitor_and_walkers {
         fn walk_const_item<$($lt,)? V: $Visitor$(<$lt>)?>(
             vis: &mut V,
             item: &$($lt)? $($mut)? ConstItem,
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             let ConstItem { defaultness, ident, generics, ty, expr, define_opaque } = item;
             try_visit!(visit_defaultness(vis, defaultness));
             try_visit!(vis.visit_ident(ident));
@@ -621,7 +623,7 @@ macro_rules! common_visitor_and_walkers {
             walk_define_opaques(vis, define_opaque)
         }
 
-        fn walk_foreign_mod<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, foreign_mod: &$($lt)? $($mut)? ForeignMod) $(-> <V as Visitor<$lt>>::Result)? {
+        fn walk_foreign_mod<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, foreign_mod: &$($lt)? $($mut)? ForeignMod) -> V::Result {
             let ForeignMod { extern_span: _, safety, abi: _, items } = foreign_mod;
             try_visit!(visit_safety(vis, safety));
             visit_foreign_items(vis, items)
@@ -630,14 +632,14 @@ macro_rules! common_visitor_and_walkers {
         fn walk_define_opaques<$($lt,)? V: $Visitor$(<$lt>)?>(
             visitor: &mut V,
             define_opaque: &$($lt)? $($mut)? Option<ThinVec<(NodeId, Path)>>,
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             if let Some(define_opaque) = define_opaque {
                 for (id, path) in define_opaque {
                     try_visit!(visit_id(visitor, id));
                     try_visit!(visitor.visit_path(path));
                 }
             }
-            $(<V as Visitor<$lt>>::Result::output())?
+            V::Result::output()
         }
 
         impl WalkItemKind for AssocItemKind {
@@ -649,7 +651,7 @@ macro_rules! common_visitor_and_walkers {
                 visibility: &$($lt)? $($mut)? Visibility,
                 ctxt: Self::Ctxt,
                 vis: &mut V,
-            ) $(-> <V as Visitor<$lt>>::Result)? {
+            ) -> V::Result {
                 match self {
                     AssocItemKind::Const(item) => {
                         walk_const_item(vis, item)
@@ -674,7 +676,7 @@ macro_rules! common_visitor_and_walkers {
                         $(${ignore($mut)}
                             walk_ty_alias_where_clauses(vis, where_clauses);
                         )?
-                        $(<V as Visitor<$lt>>::Result::output())?
+                        V::Result::output()
                     }
                     AssocItemKind::MacCall(mac) => {
                         vis.visit_mac_call(mac)
@@ -694,7 +696,7 @@ macro_rules! common_visitor_and_walkers {
                         try_visit!(vis.visit_ident(ident));
                         visit_opt!(vis, visit_ident, rename);
                         visit_opt!(vis, visit_block, body);
-                        $(<V as Visitor<$lt>>::Result::output())?
+                        V::Result::output()
                     }
                     AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
                         try_visit!(vis.visit_qself(qself));
@@ -706,7 +708,7 @@ macro_rules! common_visitor_and_walkers {
                             }
                         }
                         visit_opt!(vis, visit_block, body);
-                        $(<V as Visitor<$lt>>::Result::output())?
+                        V::Result::output()
                     }
                 }
             }
@@ -721,7 +723,7 @@ macro_rules! common_visitor_and_walkers {
                 visibility: &$($lt)? $($mut)? Visibility,
                 _ctxt: Self::Ctxt,
                 vis: &mut V,
-            ) $(-> <V as Visitor<$lt>>::Result)? {
+            ) -> V::Result {
                 match self {
                     ForeignItemKind::Static(box StaticItem {
                         ident,
@@ -756,7 +758,7 @@ macro_rules! common_visitor_and_walkers {
                         $(${ignore($mut)}
                             walk_ty_alias_where_clauses(vis, where_clauses);
                         )?
-                        $(<V as Visitor<$lt>>::Result::output())?
+                        V::Result::output()
                     }
                     ForeignItemKind::MacCall(mac) => {
                         vis.visit_mac_call(mac)
@@ -768,7 +770,7 @@ macro_rules! common_visitor_and_walkers {
         fn walk_coroutine_kind<$($lt,)? V: $Visitor$(<$lt>)?>(
             vis: &mut V,
             coroutine_kind: &$($lt)? $($mut)? CoroutineKind,
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             let (CoroutineKind::Async { span, closure_id, return_impl_trait_id }
                 | CoroutineKind::Gen { span, closure_id, return_impl_trait_id }
                 | CoroutineKind::AsyncGen { span, closure_id, return_impl_trait_id })
@@ -781,7 +783,7 @@ macro_rules! common_visitor_and_walkers {
         pub fn walk_pat<$($lt,)? V: $Visitor$(<$lt>)?>(
             vis: &mut V,
             pattern: &$($lt)? $($mut)? Pat
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             let Pat { id, kind, span, tokens: _ } = pattern;
             try_visit!(visit_id(vis, id));
             match kind {
@@ -832,7 +834,7 @@ macro_rules! common_visitor_and_walkers {
         pub fn walk_anon_const<$($lt,)? V: $Visitor$(<$lt>)?>(
             vis: &mut V,
             constant: &$($lt)? $($mut)? AnonConst,
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             let AnonConst { id, value } = constant;
             try_visit!(visit_id(vis, id));
             vis.visit_expr(value)
@@ -841,18 +843,18 @@ macro_rules! common_visitor_and_walkers {
         pub fn walk_path_segment<$($lt,)? V: $Visitor$(<$lt>)?>(
             vis: &mut V,
             segment: &$($lt)? $($mut)? PathSegment,
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             let PathSegment { ident, id, args } = segment;
             try_visit!(visit_id(vis, id));
             try_visit!(vis.visit_ident(ident));
             visit_opt!(vis, visit_generic_args, args);
-            $(<V as Visitor<$lt>>::Result::output())?
+            V::Result::output()
         }
 
         pub fn walk_block<$($lt,)? V: $Visitor$(<$lt>)?>(
             vis: &mut V,
             block: &$($lt)? $($mut)? Block
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             let Block { stmts, id, rules: _, span, tokens: _ } = block;
             try_visit!(visit_id(vis, id));
             try_visit!(visit_stmts(vis, stmts));
@@ -862,7 +864,7 @@ macro_rules! common_visitor_and_walkers {
 
         pub fn walk_ty<$($lt,)? V: $Visitor$(<$lt>)?>(
             vis: &mut V, ty: &$($lt)? $($mut)? Ty
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             let Ty { id, kind, span, tokens: _ } = ty;
             try_visit!(visit_id(vis, id));
             match kind {
@@ -920,7 +922,7 @@ macro_rules! common_visitor_and_walkers {
         pub fn walk_crate<$($lt,)? V: $Visitor$(<$lt>)?>(
             vis: &mut V,
             krate: &$($lt)? $($mut)? Crate,
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             let Crate { attrs, items, spans, id, is_placeholder: _ } = krate;
             try_visit!(visit_id(vis, id));
             walk_list!(vis, visit_attribute, attrs);
@@ -933,7 +935,7 @@ macro_rules! common_visitor_and_walkers {
         pub fn walk_local<$($lt,)? V: $Visitor$(<$lt>)?>(
             vis: &mut V,
             local: &$($lt)? $($mut)? Local,
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             let Local { id, super_, pat, ty, kind, span, colon_sp, attrs, tokens: _ } = local;
             if let Some(sp) = super_ {
                 try_visit!(visit_span(vis, sp));
@@ -961,7 +963,7 @@ macro_rules! common_visitor_and_walkers {
         pub fn walk_poly_trait_ref<$($lt,)? V: $Visitor$(<$lt>)?>(
             vis: &mut V,
             p: &$($lt)? $($mut)? PolyTraitRef,
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             let PolyTraitRef { bound_generic_params, modifiers, trait_ref, span } = p;
             try_visit!(visit_modifiers(vis, modifiers));
             try_visit!(visit_generic_params(vis, bound_generic_params));
@@ -972,7 +974,7 @@ macro_rules! common_visitor_and_walkers {
         pub fn walk_trait_ref<$($lt,)? V: $Visitor$(<$lt>)?>(
             vis: &mut V,
             TraitRef { path, ref_id }: &$($lt)? $($mut)? TraitRef,
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             try_visit!(vis.visit_path(path));
             visit_id(vis, ref_id)
         }
@@ -980,7 +982,7 @@ macro_rules! common_visitor_and_walkers {
         pub fn walk_variant<$($lt,)? V: $Visitor$(<$lt>)?>(
             vis: &mut V,
             variant: &$($lt)? $($mut)? Variant,
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             let Variant { attrs, id, span, vis: visibility, ident, data, disr_expr, is_placeholder: _ } = variant;
             try_visit!(visit_id(vis, id));
             walk_list!(vis, visit_attribute, attrs);
@@ -995,7 +997,7 @@ macro_rules! common_visitor_and_walkers {
         pub fn walk_expr_field<$($lt,)? V: $Visitor$(<$lt>)?>(
             vis: &mut V,
             f: &$($lt)? $($mut)? ExprField,
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             let ExprField { attrs, id, span, ident, expr, is_shorthand: _, is_placeholder: _ } = f;
             try_visit!(visit_id(vis, id));
             walk_list!(vis, visit_attribute, attrs);
@@ -1007,7 +1009,7 @@ macro_rules! common_visitor_and_walkers {
         pub fn walk_pat_field<$($lt,)? V: $Visitor$(<$lt>)?>(
             vis: &mut V,
             fp: &$($lt)? $($mut)? PatField,
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             let PatField { ident, pat, is_shorthand: _, attrs, id, span, is_placeholder: _ } = fp;
             try_visit!(visit_id(vis, id));
             walk_list!(vis, visit_attribute, attrs);
@@ -1019,7 +1021,7 @@ macro_rules! common_visitor_and_walkers {
         pub fn walk_ty_pat<$($lt,)? V: $Visitor$(<$lt>)?>(
             vis: &mut V,
             tp: &$($lt)? $($mut)? TyPat,
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             let TyPat { id, kind, span, tokens: _ } = tp;
             try_visit!(visit_id(vis, id));
             match kind {
@@ -1036,19 +1038,19 @@ macro_rules! common_visitor_and_walkers {
         fn walk_qself<$($lt,)? V: $Visitor$(<$lt>)?>(
             vis: &mut V,
             qself: &$($lt)? $($mut)? Option<P<QSelf>>,
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             if let Some(qself) = qself {
                 let QSelf { ty, path_span, position: _ } = &$($mut)? **qself;
                 try_visit!(vis.visit_ty(ty));
                 try_visit!(visit_span(vis, path_span));
             }
-            $(<V as Visitor<$lt>>::Result::output())?
+            V::Result::output()
         }
 
         pub fn walk_path<$($lt,)? V: $Visitor$(<$lt>)?>(
             vis: &mut V,
             path: &$($lt)? $($mut)? Path,
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             let Path { span, segments, tokens: _ } = path;
             walk_list!(vis, visit_path_segment, segments);
             visit_span(vis, span)
@@ -1057,7 +1059,7 @@ macro_rules! common_visitor_and_walkers {
         pub fn walk_use_tree<$($lt,)? V: $Visitor$(<$lt>)?>(
             vis: &mut V,
             use_tree: &$($lt)? $($mut)? UseTree,
-        ) $(-> <V as Visitor<$lt>>::Result)? {
+        ) -> V::Result {
             let UseTree { prefix, kind, span } = use_tree;
             try_visit!(vis.visit_path(prefix));
             match kind {
@@ -1075,573 +1077,640 @@ macro_rules! common_visitor_and_walkers {
             }
             visit_span(vis, span)
         }
-    };
-}
-
-common_visitor_and_walkers!(Visitor<'a>);
 
-macro_rules! generate_list_visit_fns {
-    ($($name:ident, $Ty:ty, $visit_fn:ident$(, $param:ident: $ParamTy:ty)*;)+) => {
-        $(
-            fn $name<'a, V: Visitor<'a>>(
-                vis: &mut V,
-                values: &'a ThinVec<$Ty>,
-                $(
-                    $param: $ParamTy,
-                )*
-            ) -> V::Result {
-                walk_list!(vis, $visit_fn, values$(,$param)*);
-                V::Result::output()
+        pub fn walk_generic_args<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            generic_args: &$($lt)? $($mut)? GenericArgs
+        ) -> V::Result {
+            match generic_args {
+                GenericArgs::AngleBracketed(AngleBracketedArgs { span, args }) => {
+                    for arg in args {
+                        match arg {
+                            AngleBracketedArg::Arg(a) => try_visit!(vis.visit_generic_arg(a)),
+                            AngleBracketedArg::Constraint(c) => {
+                                try_visit!(vis.visit_assoc_item_constraint(c))
+                            }
+                        }
+                    }
+                    visit_span(vis, span)
+                }
+                GenericArgs::Parenthesized(data) => {
+                    let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
+                    walk_list!(vis, visit_ty, inputs);
+                    try_visit!(vis.visit_fn_ret_ty(output));
+                    try_visit!(visit_span(vis, span));
+                    visit_span(vis, inputs_span)
+                }
+                GenericArgs::ParenthesizedElided(span) => visit_span(vis, span)
             }
-        )+
-    }
-}
+        }
 
-generate_list_visit_fns! {
-    visit_items, P<Item>, visit_item;
-    visit_foreign_items, P<ForeignItem>, visit_foreign_item;
-    visit_generic_params, GenericParam, visit_generic_param;
-    visit_stmts, Stmt, visit_stmt;
-    visit_pat_fields, PatField, visit_pat_field;
-    visit_variants, Variant, visit_variant;
-    visit_assoc_items, P<AssocItem>, visit_assoc_item, ctxt: AssocCtxt;
-}
+        pub fn walk_generic_arg<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            generic_arg: &$($lt)? $($mut)? GenericArg,
+        ) -> V::Result {
+            match generic_arg {
+                GenericArg::Lifetime(lt) => vis.visit_lifetime(lt, $(${ignore($lt)} LifetimeCtxt::GenericArg)? ),
+                GenericArg::Type(ty) => vis.visit_ty(ty),
+                GenericArg::Const(ct) => vis.visit_anon_const(ct),
+            }
+        }
 
-#[expect(rustc::pass_by_value)] // needed for symmetry with mut_visit
-fn visit_nested_use_tree<'a, V: Visitor<'a>>(
-    vis: &mut V,
-    nested_tree: &'a UseTree,
-    &nested_id: &NodeId,
-) -> V::Result {
-    vis.visit_nested_use_tree(nested_tree, nested_id)
-}
+        pub fn walk_assoc_item_constraint<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            constraint: &$($lt)? $($mut)? AssocItemConstraint,
+        ) -> V::Result {
+            let AssocItemConstraint { id, ident, gen_args, kind, span } = constraint;
+            try_visit!(visit_id(vis, id));
+            try_visit!(vis.visit_ident(ident));
+            visit_opt!(vis, visit_generic_args, gen_args);
+            match kind {
+                AssocItemConstraintKind::Equality { term } => match term {
+                    Term::Ty(ty) => try_visit!(vis.visit_ty(ty)),
+                    Term::Const(c) => try_visit!(vis.visit_anon_const(c)),
+                },
+                AssocItemConstraintKind::Bound { bounds } => {
+                    try_visit!(visit_bounds(vis, bounds, BoundKind::Bound));
+                }
+            }
+            visit_span(vis, span)
+        }
 
-pub fn walk_generic_args<'a, V>(visitor: &mut V, generic_args: &'a GenericArgs) -> V::Result
-where
-    V: Visitor<'a>,
-{
-    match generic_args {
-        GenericArgs::AngleBracketed(AngleBracketedArgs { span: _, args }) => {
-            for arg in args {
-                match arg {
-                    AngleBracketedArg::Arg(a) => try_visit!(visitor.visit_generic_arg(a)),
-                    AngleBracketedArg::Constraint(c) => {
-                        try_visit!(visitor.visit_assoc_item_constraint(c))
-                    }
+        pub fn walk_param_bound<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, bound: &$($lt)? $($mut)? GenericBound) -> V::Result {
+            match bound {
+                GenericBound::Trait(trait_ref) => vis.visit_poly_trait_ref(trait_ref),
+                GenericBound::Outlives(lifetime) => vis.visit_lifetime(lifetime, $(${ignore($lt)} LifetimeCtxt::Bound)?),
+                GenericBound::Use(args, span) => {
+                    walk_list!(vis, visit_precise_capturing_arg, args);
+                    visit_span(vis, span)
                 }
             }
         }
-        GenericArgs::Parenthesized(data) => {
-            let ParenthesizedArgs { span: _, inputs, inputs_span: _, output } = data;
-            walk_list!(visitor, visit_ty, inputs);
-            try_visit!(visitor.visit_fn_ret_ty(output));
+
+        pub fn walk_precise_capturing_arg<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            arg: &$($lt)? $($mut)? PreciseCapturingArg,
+        ) -> V::Result {
+            match arg {
+                PreciseCapturingArg::Lifetime(lt) => vis.visit_lifetime(lt, $(${ignore($lt)} LifetimeCtxt::GenericArg)?),
+                PreciseCapturingArg::Arg(path, id) => {
+                    try_visit!(visit_id(vis, id));
+                    vis.visit_path(path)
+                }
+            }
         }
-        GenericArgs::ParenthesizedElided(_span) => {}
-    }
-    V::Result::output()
-}
 
-pub fn walk_generic_arg<'a, V>(visitor: &mut V, generic_arg: &'a GenericArg) -> V::Result
-where
-    V: Visitor<'a>,
-{
-    match generic_arg {
-        GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt, LifetimeCtxt::GenericArg),
-        GenericArg::Type(ty) => visitor.visit_ty(ty),
-        GenericArg::Const(ct) => visitor.visit_anon_const(ct),
-    }
-}
+        pub fn walk_generic_param<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            param: &$($lt)? $($mut)? GenericParam,
+        ) -> V::Result {
+            let GenericParam { id, ident, attrs, bounds, is_placeholder: _, kind, colon_span } =
+                param;
+            try_visit!(visit_id(vis, id));
+            walk_list!(vis, visit_attribute, attrs);
+            try_visit!(vis.visit_ident(ident));
+            walk_list!(vis, visit_param_bound, bounds, BoundKind::Bound);
+            match kind {
+                GenericParamKind::Lifetime => (),
+                GenericParamKind::Type { default } => visit_opt!(vis, visit_ty, default),
+                GenericParamKind::Const { ty, default, kw_span: _ } => {
+                    try_visit!(vis.visit_ty(ty));
+                    visit_opt!(vis, visit_anon_const, default);
+                }
+            }
+            if let Some(sp) = colon_span {
+                try_visit!(visit_span(vis, sp))
+            }
+            V::Result::output()
+        }
 
-pub fn walk_assoc_item_constraint<'a, V: Visitor<'a>>(
-    visitor: &mut V,
-    constraint: &'a AssocItemConstraint,
-) -> V::Result {
-    let AssocItemConstraint { id: _, ident, gen_args, kind, span: _ } = constraint;
-    try_visit!(visitor.visit_ident(ident));
-    visit_opt!(visitor, visit_generic_args, gen_args);
-    match kind {
-        AssocItemConstraintKind::Equality { term } => match term {
-            Term::Ty(ty) => try_visit!(visitor.visit_ty(ty)),
-            Term::Const(c) => try_visit!(visitor.visit_anon_const(c)),
-        },
-        AssocItemConstraintKind::Bound { bounds } => {
-            walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
+        pub fn walk_generics<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, generics: &$($lt)? $($mut)? Generics) -> V::Result {
+            let Generics { params, where_clause, span } = generics;
+            let WhereClause { has_where_token: _, predicates, span: where_clause_span } = where_clause;
+            try_visit!(visit_generic_params(vis, params));
+            try_visit!(visit_where_predicates(vis, predicates));
+            try_visit!(visit_span(vis, span));
+            visit_span(vis, where_clause_span)
         }
-    }
-    V::Result::output()
-}
 
-pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericBound) -> V::Result {
-    match bound {
-        GenericBound::Trait(trait_ref) => visitor.visit_poly_trait_ref(trait_ref),
-        GenericBound::Outlives(lifetime) => visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound),
-        GenericBound::Use(args, _span) => {
-            walk_list!(visitor, visit_precise_capturing_arg, args);
+        pub fn walk_contract<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, c: &$($lt)? $($mut)? FnContract) -> V::Result {
+            let FnContract { requires, ensures } = c;
+            visit_opt!(vis, visit_expr, requires);
+            visit_opt!(vis, visit_expr, ensures);
             V::Result::output()
         }
-    }
-}
 
-pub fn walk_precise_capturing_arg<'a, V: Visitor<'a>>(
-    visitor: &mut V,
-    arg: &'a PreciseCapturingArg,
-) -> V::Result {
-    match arg {
-        PreciseCapturingArg::Lifetime(lt) => visitor.visit_lifetime(lt, LifetimeCtxt::GenericArg),
-        PreciseCapturingArg::Arg(path, id) => {
-            try_visit!(visitor.visit_id(*id));
-            visitor.visit_path(path)
+        pub fn walk_where_predicate<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            predicate: &$($lt)? $($mut)? WherePredicate,
+        ) -> V::Result {
+            let WherePredicate { attrs, kind, id, span, is_placeholder: _ } = predicate;
+            try_visit!(visit_id(vis, id));
+            walk_list!(vis, visit_attribute, attrs);
+            try_visit!(visit_span(vis, span));
+            vis.visit_where_predicate_kind(kind)
         }
-    }
-}
 
-pub fn walk_generic_param<'a, V: Visitor<'a>>(
-    visitor: &mut V,
-    param: &'a GenericParam,
-) -> V::Result {
-    let GenericParam { id: _, ident, attrs, bounds, is_placeholder: _, kind, colon_span: _ } =
-        param;
-    walk_list!(visitor, visit_attribute, attrs);
-    try_visit!(visitor.visit_ident(ident));
-    walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
-    match kind {
-        GenericParamKind::Lifetime => (),
-        GenericParamKind::Type { default } => visit_opt!(visitor, visit_ty, default),
-        GenericParamKind::Const { ty, default, kw_span: _ } => {
-            try_visit!(visitor.visit_ty(ty));
-            visit_opt!(visitor, visit_anon_const, default);
+        pub fn walk_closure_binder<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            binder: &$($lt)? $($mut)? ClosureBinder,
+        ) -> V::Result {
+            match binder {
+                ClosureBinder::NotPresent => {}
+                ClosureBinder::For { generic_params, span } => {
+                    try_visit!(visit_generic_params(vis, generic_params));
+                    try_visit!(visit_span(vis, span));
+                }
+            }
+            V::Result::output()
         }
-    }
-    V::Result::output()
-}
-
-pub fn walk_generics<'a, V: Visitor<'a>>(visitor: &mut V, generics: &'a Generics) -> V::Result {
-    let Generics { params, where_clause, span: _ } = generics;
-    let WhereClause { has_where_token: _, predicates, span: _ } = where_clause;
-    walk_list!(visitor, visit_generic_param, params);
-    walk_list!(visitor, visit_where_predicate, predicates);
-    V::Result::output()
-}
 
-pub fn walk_closure_binder<'a, V: Visitor<'a>>(
-    visitor: &mut V,
-    binder: &'a ClosureBinder,
-) -> V::Result {
-    match binder {
-        ClosureBinder::NotPresent => {}
-        ClosureBinder::For { generic_params, span: _ } => {
-            walk_list!(visitor, visit_generic_param, generic_params)
+        pub fn walk_where_predicate_kind<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            kind: &$($lt)? $($mut)? WherePredicateKind,
+        ) -> V::Result {
+            match kind {
+                WherePredicateKind::BoundPredicate(WhereBoundPredicate {
+                    bounded_ty,
+                    bounds,
+                    bound_generic_params,
+                }) => {
+                    visit_generic_params(vis, bound_generic_params);
+                    try_visit!(vis.visit_ty(bounded_ty));
+                    walk_list!(vis, visit_param_bound, bounds, BoundKind::Bound);
+                }
+                WherePredicateKind::RegionPredicate(WhereRegionPredicate { lifetime, bounds }) => {
+                    try_visit!(vis.visit_lifetime(lifetime, $(${ignore($lt)} LifetimeCtxt::Bound )?));
+                    walk_list!(vis, visit_param_bound, bounds, BoundKind::Bound);
+                }
+                WherePredicateKind::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty }) => {
+                    try_visit!(vis.visit_ty(lhs_ty));
+                    try_visit!(vis.visit_ty(rhs_ty));
+                }
+            }
+            V::Result::output()
         }
-    }
-    V::Result::output()
-}
 
-pub fn walk_contract<'a, V: Visitor<'a>>(visitor: &mut V, c: &'a FnContract) -> V::Result {
-    let FnContract { requires, ensures } = c;
-    if let Some(pred) = requires {
-        visitor.visit_expr(pred);
-    }
-    if let Some(pred) = ensures {
-        visitor.visit_expr(pred);
-    }
-    V::Result::output()
-}
+        pub fn walk_fn_decl<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            FnDecl { inputs, output }: &$($lt)? $($mut)? FnDecl,
+        ) -> V::Result {
+            try_visit!(visit_params(vis, inputs));
+            vis.visit_fn_ret_ty(output)
+        }
 
-pub fn walk_where_predicate<'a, V: Visitor<'a>>(
-    visitor: &mut V,
-    predicate: &'a WherePredicate,
-) -> V::Result {
-    let WherePredicate { attrs, kind, id: _, span: _, is_placeholder: _ } = predicate;
-    walk_list!(visitor, visit_attribute, attrs);
-    visitor.visit_where_predicate_kind(kind)
-}
+        pub fn walk_fn_ret_ty<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, ret_ty: &$($lt)? $($mut)? FnRetTy) -> V::Result {
+            match ret_ty {
+                FnRetTy::Default(span) => visit_span(vis, span),
+                FnRetTy::Ty(output_ty) => vis.visit_ty(output_ty),
+            }
+        }
 
-pub fn walk_where_predicate_kind<'a, V: Visitor<'a>>(
-    visitor: &mut V,
-    kind: &'a WherePredicateKind,
-) -> V::Result {
-    match kind {
-        WherePredicateKind::BoundPredicate(WhereBoundPredicate {
-            bounded_ty,
-            bounds,
-            bound_generic_params,
-        }) => {
-            walk_list!(visitor, visit_generic_param, bound_generic_params);
-            try_visit!(visitor.visit_ty(bounded_ty));
-            walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
+        pub fn walk_fn<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, kind: FnKind<$($lt)? $(${ignore($mut)} '_)?>) -> V::Result {
+            match kind {
+                FnKind::Fn(
+                    _ctxt,
+                    _vis,
+                    Fn {
+                        defaultness,
+                        ident,
+                        sig: FnSig { header, decl, span },
+                        generics,
+                        contract,
+                        body,
+                        define_opaque,
+                    },
+                ) => {
+                    // Visibility is visited as a part of the item.
+                    try_visit!(visit_defaultness(vis, defaultness));
+                    try_visit!(vis.visit_ident(ident));
+                    try_visit!(vis.visit_fn_header(header));
+                    try_visit!(vis.visit_generics(generics));
+                    try_visit!(vis.visit_fn_decl(decl));
+                    visit_opt!(vis, visit_contract, contract);
+                    visit_opt!(vis, visit_block, body);
+                    try_visit!(visit_span(vis, span));
+                    walk_define_opaques(vis, define_opaque)
+                }
+                FnKind::Closure(binder, coroutine_kind, decl, body) => {
+                    try_visit!(vis.visit_closure_binder(binder));
+                    visit_opt!(vis, visit_coroutine_kind, coroutine_kind);
+                    try_visit!(vis.visit_fn_decl(decl));
+                    vis.visit_expr(body)
+                }
+            }
         }
-        WherePredicateKind::RegionPredicate(WhereRegionPredicate { lifetime, bounds }) => {
-            try_visit!(visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound));
-            walk_list!(visitor, visit_param_bound, bounds, BoundKind::Bound);
+
+        pub fn walk_variant_data<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, data: &$($lt)? $($mut)? VariantData) -> V::Result {
+            match data {
+                VariantData::Struct { fields, recovered: _ } => {
+                    visit_field_defs(vis, fields)
+                }
+                VariantData::Tuple(fields, id) => {
+                    try_visit!(visit_id(vis, id));
+                    visit_field_defs(vis, fields)
+                }
+                VariantData::Unit(id) => visit_id(vis, id),
+            }
         }
-        WherePredicateKind::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty }) => {
-            try_visit!(visitor.visit_ty(lhs_ty));
-            try_visit!(visitor.visit_ty(rhs_ty));
+
+        pub fn walk_field_def<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, field: &$($lt)? $($mut)? FieldDef) -> V::Result {
+            let FieldDef { attrs, id, span, vis: visibility, ident, ty, is_placeholder: _, safety: _, default } =
+                field;
+            try_visit!(visit_id(vis, id));
+            walk_list!(vis, visit_attribute, attrs);
+            try_visit!(vis.visit_vis(visibility));
+            visit_opt!(vis, visit_ident, ident);
+            try_visit!(vis.visit_ty(ty));
+            visit_opt!(vis, visit_anon_const, default);
+            visit_span(vis, span)
         }
-    }
-    V::Result::output()
-}
 
-pub fn walk_fn_ret_ty<'a, V: Visitor<'a>>(visitor: &mut V, ret_ty: &'a FnRetTy) -> V::Result {
-    match ret_ty {
-        FnRetTy::Default(_span) => {}
-        FnRetTy::Ty(output_ty) => try_visit!(visitor.visit_ty(output_ty)),
-    }
-    V::Result::output()
-}
+        fn visit_delim_args<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, args: &$($lt)? $($mut)? DelimArgs) -> V::Result {
+            let DelimArgs { dspan, delim: _, tokens: _ } = args;
+            let DelimSpan { open, close } = dspan;
+            try_visit!(visit_span(vis, open));
+            visit_span(vis, close)
+        }
 
-pub fn walk_fn_decl<'a, V: Visitor<'a>>(
-    visitor: &mut V,
-    FnDecl { inputs, output }: &'a FnDecl,
-) -> V::Result {
-    walk_list!(visitor, visit_param, inputs);
-    visitor.visit_fn_ret_ty(output)
-}
+        pub fn walk_mac<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, mac: &$($lt)? $($mut)? MacCall) -> V::Result {
+            let MacCall { path, args } = mac;
+            try_visit!(vis.visit_path(path));
+            visit_delim_args(vis, args)
+        }
+
+        fn walk_macro_def<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, macro_def: &$($lt)? $($mut)? MacroDef) -> V::Result {
+            let MacroDef { body, macro_rules: _ } = macro_def;
+            visit_delim_args(vis, body)
+        }
+
+        pub fn walk_inline_asm<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, asm: &$($lt)? $($mut)? InlineAsm) -> V::Result {
+            // FIXME: Visit spans inside all this currently ignored stuff.
+            let InlineAsm {
+                asm_macro: _,
+                template: _,
+                template_strs: _,
+                operands,
+                clobber_abis: _,
+                options: _,
+                line_spans: _,
+            } = asm;
+            for (op, span) in operands {
+                match op {
+                    InlineAsmOperand::In { expr, reg: _ }
+                    | InlineAsmOperand::Out { expr: Some(expr), reg: _, late: _ }
+                    | InlineAsmOperand::InOut { expr, reg: _, late: _ } => {
+                        try_visit!(vis.visit_expr(expr))
+                    }
+                    InlineAsmOperand::Out { expr: None, reg: _, late: _ } => {}
+                    InlineAsmOperand::SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
+                        try_visit!(vis.visit_expr(in_expr));
+                        visit_opt!(vis, visit_expr, out_expr);
+                    }
+                    InlineAsmOperand::Const { anon_const } => {
+                        try_visit!(vis.visit_anon_const(anon_const))
+                    }
+                    InlineAsmOperand::Sym { sym } => try_visit!(vis.visit_inline_asm_sym(sym)),
+                    InlineAsmOperand::Label { block } => try_visit!(vis.visit_block(block)),
+                }
+                try_visit!(visit_span(vis, span));
+            }
+            V::Result::output()
+        }
 
-pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Result {
-    match kind {
-        FnKind::Fn(
-            _ctxt,
-            _vis,
-            Fn {
-                defaultness: _,
-                ident,
-                sig: FnSig { header, decl, span: _ },
-                generics,
-                contract,
-                body,
-                define_opaque,
-            },
-        ) => {
-            // Visibility is visited as a part of the item.
-            try_visit!(visitor.visit_ident(ident));
-            try_visit!(visitor.visit_fn_header(header));
-            try_visit!(visitor.visit_generics(generics));
-            try_visit!(visitor.visit_fn_decl(decl));
-            visit_opt!(visitor, visit_contract, contract);
-            visit_opt!(visitor, visit_block, body);
-            try_visit!(walk_define_opaques(visitor, define_opaque));
-        }
-        FnKind::Closure(binder, coroutine_kind, decl, body) => {
-            try_visit!(visitor.visit_closure_binder(binder));
-            visit_opt!(visitor, visit_coroutine_kind, coroutine_kind.as_ref());
-            try_visit!(visitor.visit_fn_decl(decl));
-            try_visit!(visitor.visit_expr(body));
+        pub fn walk_inline_asm_sym<$($lt,)? V: $Visitor$(<$lt>)?>(
+            vis: &mut V,
+            InlineAsmSym { id, qself, path }: &$($lt)? $($mut)? InlineAsmSym,
+        ) -> V::Result {
+            try_visit!(visit_id(vis, id));
+            try_visit!(vis.visit_qself(qself));
+            vis.visit_path(path)
+        }
+
+        // FIXME: visit the template exhaustively.
+        pub fn walk_format_args<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, fmt: &$($lt)? $($mut)? FormatArgs) -> V::Result {
+            let FormatArgs { span, template: _, arguments, uncooked_fmt_str: _ } = fmt;
+            let args = $(${ignore($mut)} arguments.all_args_mut())? $(${ignore($lt)} arguments.all_args())? ;
+            for FormatArgument { kind, expr } in args {
+                match kind {
+                    FormatArgumentKind::Named(ident) | FormatArgumentKind::Captured(ident) => {
+                        try_visit!(vis.visit_ident(ident))
+                    }
+                    FormatArgumentKind::Normal => {}
+                }
+                try_visit!(vis.visit_expr(expr));
+            }
+            visit_span(vis, span)
         }
-    }
-    V::Result::output()
-}
 
-pub fn walk_variant_data<'a, V: Visitor<'a>>(visitor: &mut V, data: &'a VariantData) -> V::Result {
-    visit_opt!(visitor, visit_id, data.ctor_node_id());
-    walk_list!(visitor, visit_field_def, data.fields());
-    V::Result::output()
-}
+        pub fn walk_expr<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, expression: &$($lt)? $($mut)? Expr) -> V::Result {
+            let Expr { id, kind, span, attrs, tokens: _ } = expression;
+            try_visit!(visit_id(vis, id));
+            walk_list!(vis, visit_attribute, attrs);
+            match kind {
+                ExprKind::Array(exprs) => {
+                    try_visit!(visit_exprs(vis, exprs));
+                }
+                ExprKind::ConstBlock(anon_const) => try_visit!(vis.visit_anon_const(anon_const)),
+                ExprKind::Repeat(element, count) => {
+                    try_visit!(vis.visit_expr(element));
+                    try_visit!(vis.visit_anon_const(count));
+                }
+                ExprKind::Struct(se) => {
+                    let StructExpr { qself, path, fields, rest } = &$($mut)?**se;
+                    try_visit!(vis.visit_qself(qself));
+                    try_visit!(vis.visit_path(path));
+                    visit_expr_fields(vis, fields);
+                    match rest {
+                        StructRest::Base(expr) => try_visit!(vis.visit_expr(expr)),
+                        StructRest::Rest(_span) => {}
+                        StructRest::None => {}
+                    }
+                }
+                ExprKind::Tup(exprs) => {
+                    try_visit!(visit_exprs(vis, exprs));
+                }
+                ExprKind::Call(callee_expression, arguments) => {
+                    try_visit!(vis.visit_expr(callee_expression));
+                    try_visit!(visit_exprs(vis, arguments));
+                }
+                ExprKind::MethodCall(box MethodCall { seg, receiver, args, span }) => {
+                    try_visit!(vis.visit_method_receiver_expr(receiver));
+                    try_visit!(vis.visit_path_segment(seg));
+                    try_visit!(visit_exprs(vis, args));
+                    try_visit!(visit_span(vis, span));
+                }
+                ExprKind::Binary(Spanned { span, node: _ }, left_expression, right_expression) => {
+                    try_visit!(vis.visit_expr(left_expression));
+                    try_visit!(vis.visit_expr(right_expression));
+                    try_visit!(visit_span(vis, span))
+                }
+                ExprKind::AddrOf(_kind, _mutbl, subexpression) => {
+                    try_visit!(vis.visit_expr(subexpression));
+                }
+                ExprKind::Unary(_op, subexpression) => {
+                    try_visit!(vis.visit_expr(subexpression));
+                }
+                ExprKind::Cast(subexpression, typ) | ExprKind::Type(subexpression, typ) => {
+                    try_visit!(vis.visit_expr(subexpression));
+                    try_visit!(vis.visit_ty(typ));
+                }
+                ExprKind::Let(pat, expr, span, _recovered) => {
+                    try_visit!(vis.visit_pat(pat));
+                    try_visit!(vis.visit_expr(expr));
+                    try_visit!(visit_span(vis, span))
+                }
+                ExprKind::If(head_expression, if_block, optional_else) => {
+                    try_visit!(vis.visit_expr(head_expression));
+                    try_visit!(vis.visit_block(if_block));
+                    visit_opt!(vis, visit_expr, optional_else);
+                }
+                ExprKind::While(subexpression, block, opt_label) => {
+                    visit_opt!(vis, visit_label, opt_label);
+                    try_visit!(vis.visit_expr(subexpression));
+                    try_visit!(vis.visit_block(block));
+                }
+                ExprKind::ForLoop { pat, iter, body, label, kind: _ } => {
+                    visit_opt!(vis, visit_label, label);
+                    try_visit!(vis.visit_pat(pat));
+                    try_visit!(vis.visit_expr(iter));
+                    try_visit!(vis.visit_block(body));
+                }
+                ExprKind::Loop(block, opt_label, span) => {
+                    visit_opt!(vis, visit_label, opt_label);
+                    try_visit!(vis.visit_block(block));
+                    try_visit!(visit_span(vis, span))
+                }
+                ExprKind::Match(subexpression, arms, _kind) => {
+                    try_visit!(vis.visit_expr(subexpression));
+                    try_visit!(visit_arms(vis, arms));
+                }
+                ExprKind::Closure(box Closure {
+                    binder,
+                    capture_clause,
+                    coroutine_kind,
+                    constness,
+                    movability: _,
+                    fn_decl,
+                    body,
+                    fn_decl_span,
+                    fn_arg_span,
+                }) => {
+                    try_visit!(visit_constness(vis, constness));
+                    try_visit!(vis.visit_capture_by(capture_clause));
+                    try_visit!(vis.visit_fn(
+                        FnKind::Closure(binder, coroutine_kind, fn_decl, body),
+                        *span,
+                        *id
+                    ));
+                    try_visit!(visit_span(vis, fn_decl_span));
+                    try_visit!(visit_span(vis, fn_arg_span));
+                }
+                ExprKind::Block(block, opt_label) => {
+                    visit_opt!(vis, visit_label, opt_label);
+                    try_visit!(vis.visit_block(block));
+                }
+                ExprKind::Gen(_capt, body, _kind, decl_span) => {
+                    try_visit!(vis.visit_block(body));
+                    try_visit!(visit_span(vis, decl_span));
+                }
+                ExprKind::Await(expr, span) => {
+                    try_visit!(vis.visit_expr(expr));
+                    try_visit!(visit_span(vis, span));
+                }
+                ExprKind::Use(expr, span) => {
+                    try_visit!(vis.visit_expr(expr));
+                    try_visit!(visit_span(vis, span));
+                }
+                ExprKind::Assign(lhs, rhs, span) => {
+                    try_visit!(vis.visit_expr(lhs));
+                    try_visit!(vis.visit_expr(rhs));
+                    try_visit!(visit_span(vis, span));
+                }
+                ExprKind::AssignOp(_op, left_expression, right_expression) => {
+                    try_visit!(vis.visit_expr(left_expression));
+                    try_visit!(vis.visit_expr(right_expression));
+                }
+                ExprKind::Field(subexpression, ident) => {
+                    try_visit!(vis.visit_expr(subexpression));
+                    try_visit!(vis.visit_ident(ident));
+                }
+                ExprKind::Index(main_expression, index_expression, span) => {
+                    try_visit!(vis.visit_expr(main_expression));
+                    try_visit!(vis.visit_expr(index_expression));
+                    try_visit!(visit_span(vis, span));
+                }
+                ExprKind::Range(start, end, _limit) => {
+                    visit_opt!(vis, visit_expr, start);
+                    visit_opt!(vis, visit_expr, end);
+                }
+                ExprKind::Underscore => {}
+                ExprKind::Path(maybe_qself, path) => {
+                    try_visit!(vis.visit_qself(maybe_qself));
+                    try_visit!(vis.visit_path(path));
+                }
+                ExprKind::Break(opt_label, opt_expr) => {
+                    visit_opt!(vis, visit_label, opt_label);
+                    visit_opt!(vis, visit_expr, opt_expr);
+                }
+                ExprKind::Continue(opt_label) => {
+                    visit_opt!(vis, visit_label, opt_label);
+                }
+                ExprKind::Ret(optional_expression) => {
+                    visit_opt!(vis, visit_expr, optional_expression);
+                }
+                ExprKind::Yeet(optional_expression) => {
+                    visit_opt!(vis, visit_expr, optional_expression);
+                }
+                ExprKind::Become(expr) => try_visit!(vis.visit_expr(expr)),
+                ExprKind::MacCall(mac) => try_visit!(vis.visit_mac_call(mac)),
+                ExprKind::Paren(subexpression) => try_visit!(vis.visit_expr(subexpression)),
+                ExprKind::InlineAsm(asm) => try_visit!(vis.visit_inline_asm(asm)),
+                ExprKind::FormatArgs(f) => try_visit!(vis.visit_format_args(f)),
+                ExprKind::OffsetOf(container, fields) => {
+                    try_visit!(vis.visit_ty(container));
+                    walk_list!(vis, visit_ident, fields);
+                }
+                ExprKind::Yield(kind) => {
+                    match kind {
+                        YieldKind::Postfix(expr) => {
+                            try_visit!(vis.visit_expr(expr));
+                        }
+                        YieldKind::Prefix(expr) => {
+                            visit_opt!(vis, visit_expr, expr);
+                        }
+                    }
+                }
+                ExprKind::Try(subexpression) => try_visit!(vis.visit_expr(subexpression)),
+                ExprKind::TryBlock(body) => try_visit!(vis.visit_block(body)),
+                ExprKind::Lit(_token) => {}
+                ExprKind::IncludedBytes(_bytes) => {}
+                ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
+                    try_visit!(vis.visit_expr(expr));
+                    visit_opt!(vis, visit_ty, ty);
+                }
+                ExprKind::Err(_guar) => {}
+                ExprKind::Dummy => {}
+            }
 
-pub fn walk_field_def<'a, V: Visitor<'a>>(visitor: &mut V, field: &'a FieldDef) -> V::Result {
-    let FieldDef { attrs, id: _, span: _, vis, ident, ty, is_placeholder: _, safety: _, default } =
-        field;
-    walk_list!(visitor, visit_attribute, attrs);
-    try_visit!(visitor.visit_vis(vis));
-    visit_opt!(visitor, visit_ident, ident);
-    try_visit!(visitor.visit_ty(ty));
-    visit_opt!(visitor, visit_anon_const, &*default);
-    V::Result::output()
-}
+            visit_span(vis, span)
+        }
 
-pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) -> V::Result {
-    let Stmt { id: _, kind, span: _ } = statement;
-    match kind {
-        StmtKind::Let(local) => try_visit!(visitor.visit_local(local)),
-        StmtKind::Item(item) => try_visit!(visitor.visit_item(item)),
-        StmtKind::Expr(expr) | StmtKind::Semi(expr) => try_visit!(visitor.visit_expr(expr)),
-        StmtKind::Empty => {}
-        StmtKind::MacCall(mac) => {
-            let MacCallStmt { mac, attrs, style: _, tokens: _ } = &**mac;
-            walk_list!(visitor, visit_attribute, attrs);
-            try_visit!(visitor.visit_mac_call(mac));
+        pub fn walk_param<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, param: &$($lt)? $($mut)? Param) -> V::Result {
+            let Param { attrs, ty, pat, id, span, is_placeholder: _ } = param;
+            try_visit!(visit_id(vis, id));
+            walk_list!(vis, visit_attribute, attrs);
+            try_visit!(vis.visit_pat(pat));
+            try_visit!(vis.visit_ty(ty));
+            visit_span(vis, span)
         }
-    }
-    V::Result::output()
-}
 
-pub fn walk_mac<'a, V: Visitor<'a>>(visitor: &mut V, mac: &'a MacCall) -> V::Result {
-    let MacCall { path, args: _ } = mac;
-    visitor.visit_path(path)
-}
+        pub fn walk_arm<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, arm: &$($lt)? $($mut)? Arm) -> V::Result {
+            let Arm { attrs, pat, guard, body, span, id, is_placeholder: _ } = arm;
+            try_visit!(visit_id(vis, id));
+            walk_list!(vis, visit_attribute, attrs);
+            try_visit!(vis.visit_pat(pat));
+            visit_opt!(vis, visit_expr, guard);
+            visit_opt!(vis, visit_expr, body);
+            visit_span(vis, span)
+        }
 
-pub fn walk_inline_asm<'a, V: Visitor<'a>>(visitor: &mut V, asm: &'a InlineAsm) -> V::Result {
-    let InlineAsm {
-        asm_macro: _,
-        template: _,
-        template_strs: _,
-        operands,
-        clobber_abis: _,
-        options: _,
-        line_spans: _,
-    } = asm;
-    for (op, _span) in operands {
-        match op {
-            InlineAsmOperand::In { expr, reg: _ }
-            | InlineAsmOperand::Out { expr: Some(expr), reg: _, late: _ }
-            | InlineAsmOperand::InOut { expr, reg: _, late: _ } => {
-                try_visit!(visitor.visit_expr(expr))
-            }
-            InlineAsmOperand::Out { expr: None, reg: _, late: _ } => {}
-            InlineAsmOperand::SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
-                try_visit!(visitor.visit_expr(in_expr));
-                visit_opt!(visitor, visit_expr, out_expr);
-            }
-            InlineAsmOperand::Const { anon_const } => {
-                try_visit!(visitor.visit_anon_const(anon_const))
+        pub fn walk_vis<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, visibility: &$($lt)? $($mut)? Visibility) -> V::Result {
+            let Visibility { kind, span, tokens: _ } = visibility;
+            match kind {
+                VisibilityKind::Restricted { path, id, shorthand: _ } => {
+                    try_visit!(visit_id(vis, id));
+                    try_visit!(vis.visit_path(path));
+                }
+                VisibilityKind::Public | VisibilityKind::Inherited => {}
             }
-            InlineAsmOperand::Sym { sym } => try_visit!(visitor.visit_inline_asm_sym(sym)),
-            InlineAsmOperand::Label { block } => try_visit!(visitor.visit_block(block)),
+            visit_span(vis, span)
         }
-    }
-    V::Result::output()
-}
 
-pub fn walk_inline_asm_sym<'a, V: Visitor<'a>>(
-    visitor: &mut V,
-    InlineAsmSym { id, qself, path }: &'a InlineAsmSym,
-) -> V::Result {
-    try_visit!(visitor.visit_qself(qself));
-    try_visit!(visitor.visit_id(*id));
-    visitor.visit_path(path)
-}
-
-pub fn walk_format_args<'a, V: Visitor<'a>>(visitor: &mut V, fmt: &'a FormatArgs) -> V::Result {
-    let FormatArgs { span: _, template: _, arguments, uncooked_fmt_str: _ } = fmt;
-    for FormatArgument { kind, expr } in arguments.all_args() {
-        match kind {
-            FormatArgumentKind::Named(ident) | FormatArgumentKind::Captured(ident) => {
-                try_visit!(visitor.visit_ident(ident))
+        pub fn walk_attribute<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, attr: &$($lt)? $($mut)? Attribute) -> V::Result {
+            let Attribute { kind, id: _, style: _, span } = attr;
+            match kind {
+                AttrKind::Normal(normal) => {
+                    let NormalAttr { item, tokens: _ } = &$($mut)?**normal;
+                    let AttrItem { unsafety: _, path, args, tokens: _ } = item;
+                    try_visit!(vis.visit_path(path));
+                    try_visit!(walk_attr_args(vis, args));
+                }
+                AttrKind::DocComment(_kind, _sym) => {}
             }
-            FormatArgumentKind::Normal => {}
+            visit_span(vis, span)
         }
-        try_visit!(visitor.visit_expr(expr));
-    }
-    V::Result::output()
-}
 
-pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V::Result {
-    let Expr { id, kind, span, attrs, tokens: _ } = expression;
-    walk_list!(visitor, visit_attribute, attrs);
-    match kind {
-        ExprKind::Array(subexpressions) => {
-            walk_list!(visitor, visit_expr, subexpressions);
-        }
-        ExprKind::ConstBlock(anon_const) => try_visit!(visitor.visit_anon_const(anon_const)),
-        ExprKind::Repeat(element, count) => {
-            try_visit!(visitor.visit_expr(element));
-            try_visit!(visitor.visit_anon_const(count));
-        }
-        ExprKind::Struct(se) => {
-            let StructExpr { qself, path, fields, rest } = &**se;
-            try_visit!(visitor.visit_qself(qself));
-            try_visit!(visitor.visit_id(*id));
-            try_visit!(visitor.visit_path(path));
-            walk_list!(visitor, visit_expr_field, fields);
-            match rest {
-                StructRest::Base(expr) => try_visit!(visitor.visit_expr(expr)),
-                StructRest::Rest(_span) => {}
-                StructRest::None => {}
+        pub fn walk_attr_args<$($lt,)? V: $Visitor$(<$lt>)?>(vis: &mut V, args: &$($lt)? $($mut)? AttrArgs) -> V::Result {
+            match args {
+                AttrArgs::Empty => {}
+                AttrArgs::Delimited(args) => try_visit!(visit_delim_args(vis, args)),
+                AttrArgs::Eq { eq_span, expr } => {
+                    try_visit!(vis.visit_expr(expr));
+                    try_visit!(visit_span(vis, eq_span));
+                }
             }
+            V::Result::output()
         }
-        ExprKind::Tup(subexpressions) => {
-            walk_list!(visitor, visit_expr, subexpressions);
-        }
-        ExprKind::Call(callee_expression, arguments) => {
-            try_visit!(visitor.visit_expr(callee_expression));
-            walk_list!(visitor, visit_expr, arguments);
-        }
-        ExprKind::MethodCall(box MethodCall { seg, receiver, args, span: _ }) => {
-            try_visit!(visitor.visit_expr(receiver));
-            try_visit!(visitor.visit_path_segment(seg));
-            walk_list!(visitor, visit_expr, args);
-        }
-        ExprKind::Binary(_op, left_expression, right_expression) => {
-            try_visit!(visitor.visit_expr(left_expression));
-            try_visit!(visitor.visit_expr(right_expression));
-        }
-        ExprKind::AddrOf(_kind, _mutbl, subexpression) => {
-            try_visit!(visitor.visit_expr(subexpression));
-        }
-        ExprKind::Unary(_op, subexpression) => {
-            try_visit!(visitor.visit_expr(subexpression));
-        }
-        ExprKind::Cast(subexpression, typ) | ExprKind::Type(subexpression, typ) => {
-            try_visit!(visitor.visit_expr(subexpression));
-            try_visit!(visitor.visit_ty(typ));
-        }
-        ExprKind::Let(pat, expr, _span, _recovered) => {
-            try_visit!(visitor.visit_pat(pat));
-            try_visit!(visitor.visit_expr(expr));
-        }
-        ExprKind::If(head_expression, if_block, optional_else) => {
-            try_visit!(visitor.visit_expr(head_expression));
-            try_visit!(visitor.visit_block(if_block));
-            visit_opt!(visitor, visit_expr, optional_else);
-        }
-        ExprKind::While(subexpression, block, opt_label) => {
-            visit_opt!(visitor, visit_label, opt_label);
-            try_visit!(visitor.visit_expr(subexpression));
-            try_visit!(visitor.visit_block(block));
-        }
-        ExprKind::ForLoop { pat, iter, body, label, kind: _ } => {
-            visit_opt!(visitor, visit_label, label);
-            try_visit!(visitor.visit_pat(pat));
-            try_visit!(visitor.visit_expr(iter));
-            try_visit!(visitor.visit_block(body));
-        }
-        ExprKind::Loop(block, opt_label, _span) => {
-            visit_opt!(visitor, visit_label, opt_label);
-            try_visit!(visitor.visit_block(block));
-        }
-        ExprKind::Match(subexpression, arms, _kind) => {
-            try_visit!(visitor.visit_expr(subexpression));
-            walk_list!(visitor, visit_arm, arms);
-        }
-        ExprKind::Closure(box Closure {
-            binder,
-            capture_clause,
-            coroutine_kind,
-            constness: _,
-            movability: _,
-            fn_decl,
-            body,
-            fn_decl_span: _,
-            fn_arg_span: _,
-        }) => {
-            try_visit!(visitor.visit_capture_by(capture_clause));
-            try_visit!(visitor.visit_fn(
-                FnKind::Closure(binder, coroutine_kind, fn_decl, body),
-                *span,
-                *id
-            ));
-        }
-        ExprKind::Block(block, opt_label) => {
-            visit_opt!(visitor, visit_label, opt_label);
-            try_visit!(visitor.visit_block(block));
-        }
-        ExprKind::Gen(_capt, body, _kind, _decl_span) => try_visit!(visitor.visit_block(body)),
-        ExprKind::Await(expr, _span) => try_visit!(visitor.visit_expr(expr)),
-        ExprKind::Use(expr, _span) => try_visit!(visitor.visit_expr(expr)),
-        ExprKind::Assign(lhs, rhs, _span) => {
-            try_visit!(visitor.visit_expr(lhs));
-            try_visit!(visitor.visit_expr(rhs));
-        }
-        ExprKind::AssignOp(_op, left_expression, right_expression) => {
-            try_visit!(visitor.visit_expr(left_expression));
-            try_visit!(visitor.visit_expr(right_expression));
-        }
-        ExprKind::Field(subexpression, ident) => {
-            try_visit!(visitor.visit_expr(subexpression));
-            try_visit!(visitor.visit_ident(ident));
-        }
-        ExprKind::Index(main_expression, index_expression, _span) => {
-            try_visit!(visitor.visit_expr(main_expression));
-            try_visit!(visitor.visit_expr(index_expression));
-        }
-        ExprKind::Range(start, end, _limit) => {
-            visit_opt!(visitor, visit_expr, start);
-            visit_opt!(visitor, visit_expr, end);
-        }
-        ExprKind::Underscore => {}
-        ExprKind::Path(maybe_qself, path) => {
-            try_visit!(visitor.visit_qself(maybe_qself));
-            try_visit!(visitor.visit_id(*id));
-            try_visit!(visitor.visit_path(path));
-        }
-        ExprKind::Break(opt_label, opt_expr) => {
-            visit_opt!(visitor, visit_label, opt_label);
-            visit_opt!(visitor, visit_expr, opt_expr);
-        }
-        ExprKind::Continue(opt_label) => {
-            visit_opt!(visitor, visit_label, opt_label);
-        }
-        ExprKind::Ret(optional_expression) => {
-            visit_opt!(visitor, visit_expr, optional_expression);
-        }
-        ExprKind::Yeet(optional_expression) => {
-            visit_opt!(visitor, visit_expr, optional_expression);
-        }
-        ExprKind::Become(expr) => try_visit!(visitor.visit_expr(expr)),
-        ExprKind::MacCall(mac) => try_visit!(visitor.visit_mac_call(mac)),
-        ExprKind::Paren(subexpression) => try_visit!(visitor.visit_expr(subexpression)),
-        ExprKind::InlineAsm(asm) => try_visit!(visitor.visit_inline_asm(asm)),
-        ExprKind::FormatArgs(f) => try_visit!(visitor.visit_format_args(f)),
-        ExprKind::OffsetOf(container, fields) => {
-            try_visit!(visitor.visit_ty(container));
-            walk_list!(visitor, visit_ident, fields.iter());
-        }
-        ExprKind::Yield(kind) => {
-            visit_opt!(visitor, visit_expr, kind.expr());
-        }
-        ExprKind::Try(subexpression) => try_visit!(visitor.visit_expr(subexpression)),
-        ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)),
-        ExprKind::Lit(_token) => {}
-        ExprKind::IncludedBytes(_bytes) => {}
-        ExprKind::UnsafeBinderCast(_kind, expr, ty) => {
-            try_visit!(visitor.visit_expr(expr));
-            visit_opt!(visitor, visit_ty, ty);
-        }
-        ExprKind::Err(_guar) => {}
-        ExprKind::Dummy => {}
-    }
-
-    V::Result::output()
+    };
 }
 
-pub fn walk_param<'a, V: Visitor<'a>>(visitor: &mut V, param: &'a Param) -> V::Result {
-    let Param { attrs, ty, pat, id: _, span: _, is_placeholder: _ } = param;
-    walk_list!(visitor, visit_attribute, attrs);
-    try_visit!(visitor.visit_pat(pat));
-    try_visit!(visitor.visit_ty(ty));
-    V::Result::output()
+common_visitor_and_walkers!(Visitor<'a>);
+
+macro_rules! generate_list_visit_fns {
+    ($($name:ident, $Ty:ty, $visit_fn:ident$(, $param:ident: $ParamTy:ty)*;)+) => {
+        $(
+            fn $name<'a, V: Visitor<'a>>(
+                vis: &mut V,
+                values: &'a ThinVec<$Ty>,
+                $(
+                    $param: $ParamTy,
+                )*
+            ) -> V::Result {
+                walk_list!(vis, $visit_fn, values$(,$param)*);
+                V::Result::output()
+            }
+        )+
+    }
 }
 
-pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) -> V::Result {
-    let Arm { attrs, pat, guard, body, span: _, id: _, is_placeholder: _ } = arm;
-    walk_list!(visitor, visit_attribute, attrs);
-    try_visit!(visitor.visit_pat(pat));
-    visit_opt!(visitor, visit_expr, guard);
-    visit_opt!(visitor, visit_expr, body);
-    V::Result::output()
+generate_list_visit_fns! {
+    visit_items, P<Item>, visit_item;
+    visit_foreign_items, P<ForeignItem>, visit_foreign_item;
+    visit_generic_params, GenericParam, visit_generic_param;
+    visit_stmts, Stmt, visit_stmt;
+    visit_exprs, P<Expr>, visit_expr;
+    visit_expr_fields, ExprField, visit_expr_field;
+    visit_pat_fields, PatField, visit_pat_field;
+    visit_variants, Variant, visit_variant;
+    visit_assoc_items, P<AssocItem>, visit_assoc_item, ctxt: AssocCtxt;
+    visit_where_predicates, WherePredicate, visit_where_predicate;
+    visit_params, Param, visit_param;
+    visit_field_defs, FieldDef, visit_field_def;
+    visit_arms, Arm, visit_arm;
 }
 
-pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) -> V::Result {
-    let Visibility { kind, span: _, tokens: _ } = vis;
-    match kind {
-        VisibilityKind::Restricted { path, id, shorthand: _ } => {
-            try_visit!(visitor.visit_id(*id));
-            try_visit!(visitor.visit_path(path));
-        }
-        VisibilityKind::Public | VisibilityKind::Inherited => {}
-    }
-    V::Result::output()
+#[expect(rustc::pass_by_value)] // needed for symmetry with mut_visit
+fn visit_nested_use_tree<'a, V: Visitor<'a>>(
+    vis: &mut V,
+    nested_tree: &'a UseTree,
+    &nested_id: &NodeId,
+) -> V::Result {
+    vis.visit_nested_use_tree(nested_tree, nested_id)
 }
 
-pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) -> V::Result {
-    let Attribute { kind, id: _, style: _, span: _ } = attr;
+pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) -> V::Result {
+    let Stmt { id: _, kind, span: _ } = statement;
     match kind {
-        AttrKind::Normal(normal) => {
-            let NormalAttr { item, tokens: _ } = &**normal;
-            let AttrItem { unsafety: _, path, args, tokens: _ } = item;
-            try_visit!(visitor.visit_path(path));
-            try_visit!(walk_attr_args(visitor, args));
+        StmtKind::Let(local) => try_visit!(visitor.visit_local(local)),
+        StmtKind::Item(item) => try_visit!(visitor.visit_item(item)),
+        StmtKind::Expr(expr) | StmtKind::Semi(expr) => try_visit!(visitor.visit_expr(expr)),
+        StmtKind::Empty => {}
+        StmtKind::MacCall(mac) => {
+            let MacCallStmt { mac, attrs, style: _, tokens: _ } = &**mac;
+            walk_list!(visitor, visit_attribute, attrs);
+            try_visit!(visitor.visit_mac_call(mac));
         }
-        AttrKind::DocComment(_kind, _sym) => {}
-    }
-    V::Result::output()
-}
-
-pub fn walk_attr_args<'a, V: Visitor<'a>>(visitor: &mut V, args: &'a AttrArgs) -> V::Result {
-    match args {
-        AttrArgs::Empty => {}
-        AttrArgs::Delimited(_args) => {}
-        AttrArgs::Eq { expr, .. } => try_visit!(visitor.visit_expr(expr)),
     }
     V::Result::output()
 }
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index d2d1285b075..845e4d5e5d0 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -57,14 +57,6 @@ impl OptimizeAttr {
     }
 }
 
-#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic, PrintAttribute)]
-pub enum DiagnosticAttribute {
-    // tidy-alphabetical-start
-    DoNotRecommend,
-    OnUnimplemented,
-    // tidy-alphabetical-end
-}
-
 #[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone, HashStable_Generic, PrintAttribute)]
 pub enum ReprAttr {
     ReprInt(IntType),
@@ -160,40 +152,52 @@ impl Deprecation {
 #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
 pub enum AttributeKind {
     // tidy-alphabetical-start
+    /// Represents `#[rustc_allow_const_fn_unstable]`.
     AllowConstFnUnstable(ThinVec<Symbol>),
+
+    /// Represents `#[allow_internal_unstable]`.
     AllowInternalUnstable(ThinVec<(Symbol, Span)>),
+
+    /// Represents `#[rustc_default_body_unstable]`.
     BodyStability {
         stability: DefaultBodyStability,
         /// Span of the `#[rustc_default_body_unstable(...)]` attribute
         span: Span,
     },
+
+    /// Represents `#[rustc_confusables]`.
     Confusables {
         symbols: ThinVec<Symbol>,
         // FIXME(jdonszelmann): remove when target validation code is moved
         first_span: Span,
     },
+
+    /// Represents `#[rustc_const_stable]` and `#[rustc_const_unstable]`.
     ConstStability {
         stability: PartialConstStability,
         /// Span of the `#[rustc_const_stable(...)]` or `#[rustc_const_unstable(...)]` attribute
         span: Span,
     },
+
+    /// Represents `#[rustc_const_stable_indirect]`.
     ConstStabilityIndirect,
-    Deprecation {
-        deprecation: Deprecation,
-        span: Span,
-    },
-    Diagnostic(DiagnosticAttribute),
-    DocComment {
-        style: AttrStyle,
-        kind: CommentKind,
-        span: Span,
-        comment: Symbol,
-    },
+
+    /// Represents [`#[deprecated]`](https://doc.rust-lang.org/stable/reference/attributes/diagnostics.html#the-deprecated-attribute).
+    Deprecation { deprecation: Deprecation, span: Span },
+
+    /// Represents [`#[doc]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html).
+    DocComment { style: AttrStyle, kind: CommentKind, span: Span, comment: Symbol },
+
+    /// Represents `#[rustc_macro_transparency]`.
     MacroTransparency(Transparency),
+
+    /// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations).
     Repr(ThinVec<(ReprAttr, Span)>),
+
+    /// Represents `#[stable]`, `#[unstable]` and `#[rustc_allowed_through_unstable_modules]`.
     Stability {
         stability: Stability,
-        /// Span of the `#[stable(...)]` or `#[unstable(...)]` attribute
+        /// Span of the attribute.
         span: Span,
     },
     // tidy-alphabetical-end
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 443c2eace55..27fd09745ff 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -5,6 +5,7 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, PatchableFunctionEntry};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::config::{BranchProtection, FunctionReturn, OptLevel, PAuthKey, PacRet};
+use rustc_symbol_mangling::mangle_internal_symbol;
 use rustc_target::spec::{FramePointer, SanitizerSet, StackProbeType, StackProtector};
 use smallvec::SmallVec;
 
@@ -256,11 +257,11 @@ fn probestack_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
         StackProbeType::Inline => "inline-asm",
         // Flag our internal `__rust_probestack` function as the stack probe symbol.
         // This is defined in the `compiler-builtins` crate for each architecture.
-        StackProbeType::Call => "__rust_probestack",
+        StackProbeType::Call => &mangle_internal_symbol(cx.tcx, "__rust_probestack"),
         // Pick from the two above based on the LLVM version.
         StackProbeType::InlineOrCall { min_llvm_version_for_inline } => {
             if llvm_util::get_version() < min_llvm_version_for_inline {
-                "__rust_probestack"
+                &mangle_internal_symbol(cx.tcx, "__rust_probestack")
             } else {
                 "inline-asm"
             }
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index 9719d405259..4f252f3ccd4 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -356,10 +356,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
             hir::ConstContext::ConstFn => true,
             _ => {
                 // For indirect places, we are not creating a new permanent borrow, it's just as
-                // transient as the already existing one. For reborrowing references this is handled
-                // at the top of `visit_rvalue`, but for raw pointers we handle it here.
-                // Pointers/references to `static mut` and cases where the `*` is not the first
-                // projection also end up here.
+                // transient as the already existing one.
                 // Locals with StorageDead do not live beyond the evaluation and can
                 // thus safely be borrowed without being able to be leaked to the final
                 // value of the constant.
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index 1dd96297d1f..f0f958d069e 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -227,12 +227,11 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
 
     // Keep interning as long as there are things to intern.
     // We show errors if there are dangling pointers, or mutable pointers in immutable contexts
-    // (i.e., everything except for `static mut`). When these errors affect references, it is
-    // unfortunate that we show these errors here and not during validation, since validation can
-    // show much nicer errors. However, we do need these checks to be run on all pointers, including
-    // raw pointers, so we cannot rely on validation to catch them -- and since interning runs
-    // before validation, and interning doesn't know the type of anything, this means we can't show
-    // better errors. Maybe we should consider doing validation before interning in the future.
+    // (i.e., everything except for `static mut`). We only return these errors as a `Result`
+    // so that the caller can run validation, and subsequently only report interning errors
+    // if validation fails. Validation has the better error messages so we prefer those, but
+    // interning has better coverage since it "sees" *all* pointers, including raw pointers and
+    // references stored in unions.
     while let Some(prov) = todo.pop() {
         trace!(?prov);
         let alloc_id = prov.alloc_id();
@@ -279,12 +278,12 @@ pub fn intern_const_alloc_recursive<'tcx, M: CompileTimeMachine<'tcx, const_eval
             // when there is memory there that someone might expect to be mutable, but we make it immutable.
             let dangling = !is_already_global && !ecx.memory.alloc_map.contains_key(&alloc_id);
             if !dangling {
-                // Found a mutable reference inside a const where inner allocations should be
+                // Found a mutable pointer inside a const where inner allocations should be
                 // immutable.
                 if !ecx.tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you {
                     span_bug!(
                         ecx.tcx.span,
-                        "the static const safety checks accepted mutable references they should not have accepted"
+                        "the static const safety checks accepted a mutable pointer they should not have accepted"
                     );
                 }
                 // Prefer dangling pointer errors over mutable pointer errors
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index f26c7c1ba0b..08b7a362083 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -62,6 +62,7 @@ expand_feature_not_allowed =
 expand_feature_removed =
     feature has been removed
     .label = feature has been removed
+    .note = removed in {$removed_rustc_version} (you are using {$current_rustc_version}){$pull_note}
     .reason = {$reason}
 
 expand_glob_delegation_outside_impls =
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index c50ab5959e2..9a359e9b031 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -80,9 +80,20 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
 
             // If the enabled feature has been removed, issue an error.
             if let Some(f) = REMOVED_LANG_FEATURES.iter().find(|f| name == f.feature.name) {
+                let pull_note = if let Some(pull) = f.pull {
+                    format!(
+                        "; see <https://github.com/rust-lang/rust/pull/{}> for more information",
+                        pull
+                    )
+                } else {
+                    "".to_owned()
+                };
                 sess.dcx().emit_err(FeatureRemoved {
                     span: mi.span(),
                     reason: f.reason.map(|reason| FeatureRemovedReason { reason }),
+                    removed_rustc_version: f.feature.since,
+                    current_rustc_version: sess.cfg_version,
+                    pull_note,
                 });
                 continue;
             }
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index 89bdc7b6dfa..ec0af67c046 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -154,12 +154,16 @@ pub(crate) struct HelperAttributeNameInvalid {
 
 #[derive(Diagnostic)]
 #[diag(expand_feature_removed, code = E0557)]
+#[note]
 pub(crate) struct FeatureRemoved<'a> {
     #[primary_span]
     #[label]
     pub span: Span,
     #[subdiagnostic]
     pub reason: Option<FeatureRemovedReason<'a>>,
+    pub removed_rustc_version: &'a str,
+    pub current_rustc_version: &'a str,
+    pub pull_note: String,
 }
 
 #[derive(Subdiagnostic)]
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 10c5cb194f4..b1c185220f4 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -259,6 +259,8 @@ declare_features! (
     /// Allows some increased flexibility in the name resolution rules,
     /// especially around globs and shadowing (RFC 1560).
     (accepted, item_like_imports, "1.15.0", Some(35120)),
+    // Allows using the `kl` and `widekl` target features and the associated intrinsics
+    (accepted, keylocker_x86, "CURRENT_RUSTC_VERSION", Some(134813)),
     /// Allows `'a: { break 'a; }`.
     (accepted, label_break_value, "1.65.0", Some(48594)),
     /// Allows `let...else` statements.
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 013e1d5d0fa..9738f169595 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -1,5 +1,7 @@
 //! List of the removed feature gates.
 
+use std::num::{NonZero, NonZeroU32};
+
 use rustc_span::sym;
 
 use super::{Feature, to_nonzero};
@@ -7,11 +9,21 @@ use super::{Feature, to_nonzero};
 pub struct RemovedFeature {
     pub feature: Feature,
     pub reason: Option<&'static str>,
+    pub pull: Option<NonZero<u32>>,
+}
+
+macro_rules! opt_nonzero_u32 {
+    () => {
+        None
+    };
+    ($val:expr) => {
+        Some(NonZeroU32::new($val).unwrap())
+    };
 }
 
 macro_rules! declare_features {
     ($(
-        $(#[doc = $doc:tt])* (removed, $feature:ident, $ver:expr, $issue:expr, $reason:expr),
+        $(#[doc = $doc:tt])* (removed, $feature:ident, $ver:expr, $issue:expr, $reason:expr $(, $pull:expr)?),
     )+) => {
         /// Formerly unstable features that have now been removed.
         pub static REMOVED_LANG_FEATURES: &[RemovedFeature] = &[
@@ -21,7 +33,8 @@ macro_rules! declare_features {
                     since: $ver,
                     issue: to_nonzero($issue),
                 },
-                reason: $reason
+                reason: $reason,
+                pull:  opt_nonzero_u32!($($pull)?),
             }),+
         ];
     };
@@ -40,64 +53,64 @@ declare_features! (
     // version they got originally added in.)
 
     /// Allows using the `amdgpu-kernel` ABI.
-    (removed, abi_amdgpu_kernel, "1.77.0", Some(51575), None),
-    (removed, advanced_slice_patterns, "1.0.0", Some(62254),
-     Some("merged into `#![feature(slice_patterns)]`")),
+    (removed, abi_amdgpu_kernel, "1.77.0", Some(51575), None, 120495),
+    (removed, advanced_slice_patterns, "1.42.0", Some(62254),
+     Some("merged into `#![feature(slice_patterns)]`"), 67712),
     (removed, allocator, "1.0.0", None, None),
     /// Allows a test to fail without failing the whole suite.
-    (removed, allow_fail, "1.19.0", Some(46488), Some("removed due to no clear use cases")),
+    (removed, allow_fail, "1.60.0", Some(46488), Some("removed due to no clear use cases"), 93416),
     (removed, await_macro, "1.38.0", Some(50547),
-     Some("subsumed by `.await` syntax")),
+     Some("subsumed by `.await` syntax"), 62293),
     /// Allows using the `box $expr` syntax.
-    (removed, box_syntax, "1.70.0", Some(49733), Some("replaced with `#[rustc_box]`")),
+    (removed, box_syntax, "1.70.0", Some(49733), Some("replaced with `#[rustc_box]`"), 108471),
     /// Allows capturing disjoint fields in a closure/coroutine (RFC 2229).
-    (removed, capture_disjoint_fields, "1.49.0", Some(53488), Some("stabilized in Rust 2021")),
+    (removed, capture_disjoint_fields, "1.69.0", Some(53488), Some("stabilized in Rust 2021"), 108550),
     /// Allows comparing raw pointers during const eval.
     (removed, const_compare_raw_pointers, "1.46.0", Some(53020),
-     Some("cannot be allowed in const eval in any meaningful way")),
+     Some("cannot be allowed in const eval in any meaningful way"), 73398),
     /// Allows limiting the evaluation steps of const expressions
-    (removed, const_eval_limit, "1.43.0", Some(67217), Some("removed the limit entirely")),
+    (removed, const_eval_limit, "1.72.0", Some(67217), Some("removed the limit entirely"), 103877),
     /// Allows non-trivial generic constants which have to be manually propagated upwards.
-    (removed, const_evaluatable_checked, "1.48.0", Some(76560), Some("renamed to `generic_const_exprs`")),
+    (removed, const_evaluatable_checked, "1.56.0", Some(76560), Some("renamed to `generic_const_exprs`"), 88369),
     /// Allows the definition of `const` functions with some advanced features.
     (removed, const_fn, "1.54.0", Some(57563),
-     Some("split into finer-grained feature gates")),
+     Some("split into finer-grained feature gates"), 85109),
     /// Allows const generic types (e.g. `struct Foo<const N: usize>(...);`).
-    (removed, const_generics, "1.34.0", Some(44580),
-     Some("removed in favor of `#![feature(adt_const_params)]` and `#![feature(generic_const_exprs)]`")),
+    (removed, const_generics, "1.56.0", Some(44580),
+     Some("removed in favor of `#![feature(adt_const_params)]` and `#![feature(generic_const_exprs)]`"), 88369),
     /// Allows `[x; N]` where `x` is a constant (RFC 2203).
-    (removed, const_in_array_repeat_expressions,  "1.37.0", Some(49147),
-     Some("removed due to causing promotable bugs")),
+    (removed, const_in_array_repeat_expressions,  "1.51.0", Some(49147),
+     Some("removed due to causing promotable bugs"), 80404),
     /// Allows casting raw pointers to `usize` during const eval.
     (removed, const_raw_ptr_to_usize_cast, "1.55.0", Some(51910),
-     Some("at compile-time, pointers do not have an integer value, so these casts cannot be properly supported")),
+     Some("at compile-time, pointers do not have an integer value, so these casts cannot be properly supported"), 87020),
     /// Allows `T: ?const Trait` syntax in bounds.
-    (removed, const_trait_bound_opt_out, "1.42.0", Some(67794),
-     Some("Removed in favor of `~const` bound in #![feature(const_trait_impl)]")),
+    (removed, const_trait_bound_opt_out, "1.56.0", Some(67794),
+     Some("Removed in favor of `~const` bound in #![feature(const_trait_impl)]"), 88328),
     /// Allows using `crate` as visibility modifier, synonymous with `pub(crate)`.
-    (removed, crate_visibility_modifier, "1.63.0", Some(53120), Some("removed in favor of `pub(crate)`")),
+    (removed, crate_visibility_modifier, "1.63.0", Some(53120), Some("removed in favor of `pub(crate)`"), 97254),
     /// Allows using custom attributes (RFC 572).
     (removed, custom_attribute, "1.0.0", Some(29642),
-     Some("removed in favor of `#![register_tool]` and `#![register_attr]`")),
+     Some("removed in favor of `#![register_tool]` and `#![register_attr]`"), 66070),
     /// Allows the use of `#[derive(Anything)]` as sugar for `#[derive_Anything]`.
     (removed, custom_derive, "1.32.0", Some(29644),
      Some("subsumed by `#[proc_macro_derive]`")),
     /// Allows default type parameters to influence type inference.
     (removed, default_type_parameter_fallback, "1.82.0", Some(27336),
-     Some("never properly implemented; requires significant design work")),
+     Some("never properly implemented; requires significant design work"), 127655),
     /// Allows deriving traits as per `SmartPointer` specification
-    (removed, derive_smart_pointer, "1.79.0", Some(123430), Some("replaced by `CoercePointee`")),
+    (removed, derive_smart_pointer, "1.84.0", Some(123430), Some("replaced by `CoercePointee`"), 131284),
     /// Allows using `#[doc(keyword = "...")]`.
-    (removed, doc_keyword, "1.28.0", Some(51315),
-     Some("merged into `#![feature(rustdoc_internals)]`")),
+    (removed, doc_keyword, "1.58.0", Some(51315),
+     Some("merged into `#![feature(rustdoc_internals)]`"), 90420),
     /// Allows using `doc(primitive)` without a future-incompat warning.
-    (removed, doc_primitive, "1.56.0", Some(88070),
-     Some("merged into `#![feature(rustdoc_internals)]`")),
+    (removed, doc_primitive, "1.58.0", Some(88070),
+     Some("merged into `#![feature(rustdoc_internals)]`"), 90420),
     /// Allows `#[doc(spotlight)]`.
     /// The attribute was renamed to `#[doc(notable_trait)]`
     /// and the feature to `doc_notable_trait`.
-    (removed, doc_spotlight, "1.22.0", Some(45040),
-     Some("renamed to `doc_notable_trait`")),
+    (removed, doc_spotlight, "1.53.0", Some(45040),
+     Some("renamed to `doc_notable_trait`"), 80965),
     /// Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238).
     (removed, dropck_parametricity, "1.38.0", Some(28498), None),
     /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn compatible[^1].
@@ -107,161 +120,162 @@ declare_features! (
     /// Renamed from `object_safe_for_dispatch`.
     ///
     /// [^1]: Formerly known as "object safe".
-    (removed, dyn_compatible_for_dispatch, "1.83.0", Some(43561),
-     Some("removed, not used heavily and represented additional complexity in dyn compatibility")),
+    (removed, dyn_compatible_for_dispatch, "1.87.0", Some(43561),
+     Some("removed, not used heavily and represented additional complexity in dyn compatibility"), 136522),
     /// Uses generic effect parameters for ~const bounds
     (removed, effects, "1.84.0", Some(102090),
-     Some("removed, redundant with `#![feature(const_trait_impl)]`")),
+     Some("removed, redundant with `#![feature(const_trait_impl)]`"), 132479),
     /// Allows defining `existential type`s.
     (removed, existential_type, "1.38.0", Some(63063),
      Some("removed in favor of `#![feature(type_alias_impl_trait)]`")),
     /// Paths of the form: `extern::foo::bar`
     (removed, extern_in_paths, "1.33.0", Some(55600),
-     Some("subsumed by `::foo::bar` paths")),
+     Some("subsumed by `::foo::bar` paths"), 57572),
     /// Allows `#[doc(include = "some-file")]`.
     (removed, external_doc, "1.54.0", Some(44732),
-     Some("use #[doc = include_str!(\"filename\")] instead, which handles macro invocations")),
+     Some("use #[doc = include_str!(\"filename\")] instead, which handles macro invocations"), 85457),
     /// Allows using `#[ffi_returns_twice]` on foreign functions.
     (removed, ffi_returns_twice, "1.78.0", Some(58314),
-     Some("being investigated by the ffi-unwind project group")),
+     Some("being investigated by the ffi-unwind project group"), 120502),
     /// Allows generators to be cloned.
-    (removed, generator_clone, "1.65.0", Some(95360), Some("renamed to `coroutine_clone`")),
+    (removed, generator_clone, "1.75.0", Some(95360), Some("renamed to `coroutine_clone`"), 116958),
     /// Allows defining generators.
-    (removed, generators, "1.21.0", Some(43122), Some("renamed to `coroutines`")),
+    (removed, generators, "1.75.0", Some(43122), Some("renamed to `coroutines`"), 116958),
     /// An extension to the `generic_associated_types` feature, allowing incomplete features.
     (removed, generic_associated_types_extended, "1.85.0", Some(95451),
         Some(
             "feature needs overhaul and reimplementation pending \
             better implied higher-ranked implied bounds support"
-        )
+        ),
+        133768
     ),
     (removed, import_shadowing, "1.0.0", None, None),
     /// Allows in-band quantification of lifetime bindings (e.g., `fn foo(x: &'a u8) -> &'a u8`).
-    (removed, in_band_lifetimes, "1.23.0", Some(44524),
-     Some("removed due to unsolved ergonomic questions and added lifetime resolution complexity")),
+    (removed, in_band_lifetimes, "1.61.0", Some(44524),
+     Some("removed due to unsolved ergonomic questions and added lifetime resolution complexity"), 93845),
     /// Allows inferring `'static` outlives requirements (RFC 2093).
     (removed, infer_static_outlives_requirements, "1.63.0", Some(54185),
-     Some("removed as it caused some confusion and discussion was inactive for years")),
+     Some("removed as it caused some confusion and discussion was inactive for years"), 97875),
     /// Allow anonymous constants from an inline `const` block in pattern position
     (removed, inline_const_pat, "1.88.0", Some(76001),
-     Some("removed due to implementation concerns as it requires significant refactorings")),
+     Some("removed due to implementation concerns as it requires significant refactorings"), 138492),
     /// Lazily evaluate constants. This allows constants to depend on type parameters.
-    (removed, lazy_normalization_consts, "1.46.0", Some(72219), Some("superseded by `generic_const_exprs`")),
+    (removed, lazy_normalization_consts, "1.56.0", Some(72219), Some("superseded by `generic_const_exprs`"), 88369),
     /// Changes `impl Trait` to capture all lifetimes in scope.
-    (removed, lifetime_capture_rules_2024, "1.76.0", None, Some("unnecessary -- use edition 2024 instead")),
+    (removed, lifetime_capture_rules_2024, "1.87.0", None, Some("unnecessary -- use edition 2024 instead"), 136787),
     /// Allows using the `#[link_args]` attribute.
     (removed, link_args, "1.53.0", Some(29596),
      Some("removed in favor of using `-C link-arg=ARG` on command line, \
-           which is available from cargo build scripts with `cargo:rustc-link-arg` now")),
+           which is available from cargo build scripts with `cargo:rustc-link-arg` now"), 83820),
     (removed, macro_reexport, "1.0.0", Some(29638),
-     Some("subsumed by `pub use`")),
+     Some("subsumed by `pub use`"), 49982),
     /// Allows using `#[main]` to replace the entrypoint `#[lang = "start"]` calls.
-    (removed, main, "1.53.0", Some(29634), None),
+    (removed, main, "1.53.0", Some(29634), None, 84217),
     (removed, managed_boxes, "1.0.0", None, None),
     /// Allows the use of type alias impl trait in function return positions
     (removed, min_type_alias_impl_trait, "1.56.0", Some(63063),
-     Some("removed in favor of full type_alias_impl_trait")),
+     Some("removed in favor of full type_alias_impl_trait"), 87564),
     /// Make `mut` not reset the binding mode on edition >= 2024.
-    (removed, mut_preserve_binding_mode_2024, "1.79.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024`")),
+    (removed, mut_preserve_binding_mode_2024, "1.80.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024`"), 125168),
     (removed, needs_allocator, "1.4.0", Some(27389),
      Some("subsumed by `#![feature(allocator_internals)]`")),
     /// Allows use of unary negate on unsigned integers, e.g., -e for e: u8
     (removed, negate_unsigned, "1.0.0", Some(29645), None),
     /// Allows `#[no_coverage]` on functions.
     /// The feature was renamed to `coverage_attribute` and the attribute to `#[coverage(on|off)]`
-    (removed, no_coverage, "1.74.0", Some(84605), Some("renamed to `coverage_attribute`")),
+    (removed, no_coverage, "1.74.0", Some(84605), Some("renamed to `coverage_attribute`"), 114656),
     /// Allows `#[no_debug]`.
-    (removed, no_debug, "1.43.0", Some(29721), Some("removed due to lack of demand")),
+    (removed, no_debug, "1.43.0", Some(29721), Some("removed due to lack of demand"), 69667),
     /// Note: this feature was previously recorded in a separate
     /// `STABLE_REMOVED` list because it, uniquely, was once stable but was
     /// then removed. But there was no utility storing it separately, so now
     /// it's in this list.
-    (removed, no_stack_check, "1.0.0", None, None),
+    (removed, no_stack_check, "1.0.0", None, None, 40110),
     /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn compatible (object safe).
     /// Renamed to `dyn_compatible_for_dispatch`.
     (removed, object_safe_for_dispatch, "1.83.0", Some(43561),
-     Some("renamed to `dyn_compatible_for_dispatch`")),
+     Some("renamed to `dyn_compatible_for_dispatch`"), 131511),
     /// Allows using `#[on_unimplemented(..)]` on traits.
     /// (Moved to `rustc_attrs`.)
-    (removed, on_unimplemented, "1.40.0", None, None),
+    (removed, on_unimplemented, "1.40.0", None, None, 65794),
     /// A way to temporarily opt out of opt-in copy. This will *never* be accepted.
-    (removed, opt_out_copy, "1.0.0", None, None),
+    (removed, opt_out_copy, "1.0.0", None, None, 20740),
     /// Allows features specific to OIBIT (now called auto traits).
     /// Renamed to `auto_traits`.
-    (removed, optin_builtin_traits, "1.0.0", Some(13231),
-     Some("renamed to `auto_traits`")),
+    (removed, optin_builtin_traits, "1.50.0", Some(13231),
+     Some("renamed to `auto_traits`"), 79336),
     /// Allows overlapping impls of marker traits.
     (removed, overlapping_marker_traits, "1.42.0", Some(29864),
-     Some("removed in favor of `#![feature(marker_trait_attr)]`")),
+     Some("removed in favor of `#![feature(marker_trait_attr)]`"), 68544),
     (removed, panic_implementation, "1.28.0", Some(44489),
-     Some("subsumed by `#[panic_handler]`")),
+     Some("subsumed by `#[panic_handler]`"), 53619),
     /// Allows `extern "platform-intrinsic" { ... }`.
-    (removed, platform_intrinsics, "1.4.0", Some(27731),
-     Some("SIMD intrinsics use the regular intrinsics ABI now")),
+    (removed, platform_intrinsics, "1.78.0", Some(27731),
+     Some("SIMD intrinsics use the regular intrinsics ABI now"), 121516),
     /// Allows using `#![plugin(myplugin)]`.
     (removed, plugin, "1.75.0", Some(29597),
-     Some("plugins are no longer supported")),
+     Some("plugins are no longer supported"), 116412),
     /// Allows using `#[plugin_registrar]` on functions.
-    (removed, plugin_registrar, "1.54.0", Some(29597),
-     Some("plugins are no longer supported")),
+    (removed, plugin_registrar, "1.75.0", Some(29597),
+     Some("plugins are no longer supported"), 116412),
     /// Allows exhaustive integer pattern matching with `usize::MAX`/`isize::MIN`/`isize::MAX`.
-    (removed, precise_pointer_size_matching, "1.32.0", Some(56354),
-     Some("removed in favor of half-open ranges")),
+    (removed, precise_pointer_size_matching, "1.76.0", Some(56354),
+     Some("removed in favor of half-open ranges"), 118598),
     (removed, pref_align_of, "CURRENT_RUSTC_VERSION", Some(91971),
      Some("removed due to marginal use and inducing compiler complications")),
     (removed, proc_macro_expr, "1.27.0", Some(54727),
-     Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
+     Some("subsumed by `#![feature(proc_macro_hygiene)]`"), 52121),
     (removed, proc_macro_gen, "1.27.0", Some(54727),
-     Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
+     Some("subsumed by `#![feature(proc_macro_hygiene)]`"), 52121),
     (removed, proc_macro_mod, "1.27.0", Some(54727),
-     Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
+     Some("subsumed by `#![feature(proc_macro_hygiene)]`"), 52121),
     (removed, proc_macro_non_items, "1.27.0", Some(54727),
-     Some("subsumed by `#![feature(proc_macro_hygiene)]`")),
+     Some("subsumed by `#![feature(proc_macro_hygiene)]`"), 52121),
     (removed, pub_macro_rules, "1.53.0", Some(78855),
      Some("removed due to being incomplete, in particular it does not work across crates")),
     (removed, pushpop_unsafe, "1.2.0", None, None),
     (removed, quad_precision_float, "1.0.0", None, None),
     (removed, quote, "1.33.0", Some(29601), None),
-    (removed, ref_pat_everywhere, "1.79.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024")),
+    (removed, ref_pat_everywhere, "1.80.0", Some(123076), Some("superseded by `ref_pat_eat_one_layer_2024"), 125168),
     (removed, reflect, "1.0.0", Some(27749), None),
     /// Allows using the `#[register_attr]` attribute.
     (removed, register_attr, "1.65.0", Some(66080),
-     Some("removed in favor of `#![register_tool]`")),
+     Some("removed in favor of `#![register_tool]`"), 66070),
     (removed, rust_2018_preview, "1.76.0", None,
      Some("2018 Edition preview is no longer relevant")),
     /// Allows using the macros:
     /// + `__diagnostic_used`
     /// + `__register_diagnostic`
     /// +`__build_diagnostic_array`
-    (removed, rustc_diagnostic_macros, "1.38.0", None, None),
+    (removed, rustc_diagnostic_macros, "1.38.0", None, None, 64139),
     /// Allows identifying crates that contain sanitizer runtimes.
-    (removed, sanitizer_runtime, "1.17.0", None, None),
+    (removed, sanitizer_runtime, "1.17.0", None, None, 65241),
     (removed, simd, "1.0.0", Some(27731), Some("removed in favor of `#[repr(simd)]`")),
     /// Allows using `#[start]` on a function indicating that it is the program entrypoint.
-    (removed, start, "1.0.0", Some(29633), Some("not portable enough and never RFC'd")),
+    (removed, start, "1.86.0", Some(29633), Some("not portable enough and never RFC'd"), 134299),
     /// Allows `#[link(kind = "static-nobundle", ...)]`.
-    (removed, static_nobundle, "1.16.0", Some(37403),
-     Some(r#"subsumed by `#[link(kind = "static", modifiers = "-bundle", ...)]`"#)),
+    (removed, static_nobundle, "1.63.0", Some(37403),
+     Some(r#"subsumed by `#[link(kind = "static", modifiers = "-bundle", ...)]`"#), 95818),
     (removed, struct_inherit, "1.0.0", None, None),
     (removed, test_removed_feature, "1.0.0", None, None),
     /// Allows using items which are missing stability attributes
     (removed, unmarked_api, "1.0.0", None, None),
     /// Allows unnamed fields of struct and union type
-    (removed, unnamed_fields, "1.83.0", Some(49804), Some("feature needs redesign")),
+    (removed, unnamed_fields, "1.83.0", Some(49804), Some("feature needs redesign"), 131045),
     (removed, unsafe_no_drop_flag, "1.0.0", None, None),
     (removed, unsized_tuple_coercion, "1.87.0", Some(42877),
-     Some("The feature restricts possible layouts for tuples, and this restriction is not worth it.")),
+     Some("The feature restricts possible layouts for tuples, and this restriction is not worth it."), 137728),
     /// Allows `union` fields that don't implement `Copy` as long as they don't have any drop glue.
-    (removed, untagged_unions, "1.13.0", Some(55149),
-     Some("unions with `Copy` and `ManuallyDrop` fields are stable; there is no intent to stabilize more")),
+    (removed, untagged_unions, "1.64.0", Some(55149),
+     Some("unions with `Copy` and `ManuallyDrop` fields are stable; there is no intent to stabilize more"), 97995),
     /// Allows `#[unwind(..)]`.
     ///
     /// Permits specifying whether a function should permit unwinding or abort on unwind.
-    (removed, unwind_attributes, "1.56.0", Some(58760), Some("use the C-unwind ABI instead")),
+    (removed, unwind_attributes, "1.56.0", Some(58760), Some("use the C-unwind ABI instead"), 86155),
     (removed, visible_private_types, "1.0.0", None, None),
     /// Allows `extern "wasm" fn`
     (removed, wasm_abi, "1.81.0", Some(83788),
-     Some("non-standard wasm ABI is no longer supported")),
+     Some("non-standard wasm ABI is no longer supported"), 127605),
     // !!!!    !!!!    !!!!    !!!!   !!!!    !!!!    !!!!    !!!!    !!!!    !!!!    !!!!
     // Features are listed in alphabetical order. Tidy will fail if you don't keep it this way.
     // !!!!    !!!!    !!!!    !!!!   !!!!    !!!!    !!!!    !!!!    !!!!    !!!!    !!!!
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 9447deeecbb..594021d78d2 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -546,8 +546,6 @@ declare_features! (
     (incomplete, inherent_associated_types, "1.52.0", Some(8995)),
     /// Allows using `pointer` and `reference` in intra-doc links
     (unstable, intra_doc_pointers, "1.51.0", Some(80896)),
-    // Allows using the `kl` and `widekl` target features and the associated intrinsics
-    (unstable, keylocker_x86, "1.86.0", Some(134813)),
     // Allows setting the threshold for the `large_assignments` lint.
     (unstable, large_assignments, "1.52.0", Some(83518)),
     /// Allow to have type alias types for inter-crate use.
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 064b42413f0..60ca0155bdd 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -37,22 +37,23 @@ use {rustc_attr_data_structures as attrs, rustc_hir as hir};
 use super::compare_impl_item::check_type_bounds;
 use super::*;
 
+fn add_abi_diag_help<T: EmissionGuarantee>(abi: ExternAbi, diag: &mut Diag<'_, T>) {
+    if let ExternAbi::Cdecl { unwind } = abi {
+        let c_abi = ExternAbi::C { unwind };
+        diag.help(format!("use `extern {c_abi}` instead",));
+    } else if let ExternAbi::Stdcall { unwind } = abi {
+        let c_abi = ExternAbi::C { unwind };
+        let system_abi = ExternAbi::System { unwind };
+        diag.help(format!(
+            "if you need `extern {abi}` on win32 and `extern {c_abi}` everywhere else, \
+                use `extern {system_abi}`"
+        ));
+    }
+}
+
 pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi) {
     // FIXME: this should be checked earlier, e.g. in `rustc_ast_lowering`, to fix
     // things like #86232.
-    fn add_help<T: EmissionGuarantee>(abi: ExternAbi, diag: &mut Diag<'_, T>) {
-        if let ExternAbi::Cdecl { unwind } = abi {
-            let c_abi = ExternAbi::C { unwind };
-            diag.help(format!("use `extern {c_abi}` instead",));
-        } else if let ExternAbi::Stdcall { unwind } = abi {
-            let c_abi = ExternAbi::C { unwind };
-            let system_abi = ExternAbi::System { unwind };
-            diag.help(format!(
-                "if you need `extern {abi}` on win32 and `extern {c_abi}` everywhere else, \
-                use `extern {system_abi}`"
-            ));
-        }
-    }
 
     match AbiMap::from_target(&tcx.sess.target).canonize_abi(abi, false) {
         AbiMapping::Direct(..) => (),
@@ -63,13 +64,13 @@ pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi
                 E0570,
                 "`{abi}` is not a supported ABI for the current target",
             );
-            add_help(abi, &mut err);
+            add_abi_diag_help(abi, &mut err);
             err.emit();
         }
         AbiMapping::Deprecated(..) => {
             tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| {
                 lint.primary_message("use of calling convention not supported on this target");
-                add_help(abi, lint);
+                add_abi_diag_help(abi, lint);
             });
         }
     }
@@ -80,7 +81,16 @@ pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ex
     // in `check_abi` above.
     match AbiMap::from_target(&tcx.sess.target).canonize_abi(abi, false) {
         AbiMapping::Direct(..) => (),
-        AbiMapping::Deprecated(..) | AbiMapping::Invalid => {
+        // This is not a redundant match arm: these ABIs started linting after introducing
+        // UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS already existed and we want to
+        // avoid expanding the scope of that lint so it can move to a hard error sooner.
+        AbiMapping::Deprecated(..) => {
+            tcx.node_span_lint(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| {
+                lint.primary_message("use of calling convention not supported on this target");
+                add_abi_diag_help(abi, lint);
+            });
+        }
+        AbiMapping::Invalid => {
             tcx.node_span_lint(UNSUPPORTED_FN_PTR_CALLING_CONVENTIONS, hir_id, span, |lint| {
                 lint.primary_message(format!(
                     "the calling convention {abi} is not supported on this target"
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index bb068f3821d..f2f975a6968 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -1531,8 +1531,6 @@ pub enum CastKind {
     ///
     /// MIR is well-formed if the input and output types have different sizes,
     /// but running a transmute between differently-sized types is UB.
-    ///
-    /// Allowed only in [`MirPhase::Runtime`]; Earlier it's a [`TerminatorKind::Call`].
     Transmute,
 }
 
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index fd91508cc11..7dcdd7999f2 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -1308,37 +1308,27 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
                         }
                     }
                     CastKind::Transmute => {
-                        if let MirPhase::Runtime(..) = self.body.phase {
-                            // Unlike `mem::transmute`, a MIR `Transmute` is well-formed
-                            // for any two `Sized` types, just potentially UB to run.
-
-                            if !self
-                                .tcx
-                                .normalize_erasing_regions(self.typing_env, op_ty)
-                                .is_sized(self.tcx, self.typing_env)
-                            {
-                                self.fail(
-                                    location,
-                                    format!("Cannot transmute from non-`Sized` type {op_ty}"),
-                                );
-                            }
-                            if !self
-                                .tcx
-                                .normalize_erasing_regions(self.typing_env, *target_type)
-                                .is_sized(self.tcx, self.typing_env)
-                            {
-                                self.fail(
-                                    location,
-                                    format!("Cannot transmute to non-`Sized` type {target_type:?}"),
-                                );
-                            }
-                        } else {
+                        // Unlike `mem::transmute`, a MIR `Transmute` is well-formed
+                        // for any two `Sized` types, just potentially UB to run.
+
+                        if !self
+                            .tcx
+                            .normalize_erasing_regions(self.typing_env, op_ty)
+                            .is_sized(self.tcx, self.typing_env)
+                        {
                             self.fail(
                                 location,
-                                format!(
-                                    "Transmute is not supported in non-runtime phase {:?}.",
-                                    self.body.phase
-                                ),
+                                format!("Cannot transmute from non-`Sized` type {op_ty}"),
+                            );
+                        }
+                        if !self
+                            .tcx
+                            .normalize_erasing_regions(self.typing_env, *target_type)
+                            .is_sized(self.tcx, self.typing_env)
+                        {
+                            self.fail(
+                                location,
+                                format!("Cannot transmute to non-`Sized` type {target_type:?}"),
                             );
                         }
                     }
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index dc29b03083f..4e2be8ff0b8 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -132,7 +132,22 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         target,
                         attrs,
                     ),
-                _ => {
+                Attribute::Parsed(AttributeKind::AllowConstFnUnstable { .. }) => {
+                    self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target)
+                }
+                Attribute::Parsed(AttributeKind::Deprecation { .. }) => {
+                    self.check_deprecated(hir_id, attr, span, target)
+                }
+                Attribute::Parsed(AttributeKind::DocComment { .. }) => { /* `#[doc]` is actually a lot more than just doc comments, so is checked below*/
+                }
+                Attribute::Parsed(AttributeKind::Repr(_)) => { /* handled below this loop and elsewhere */
+                }
+                Attribute::Parsed(
+                    AttributeKind::BodyStability { .. }
+                    | AttributeKind::ConstStabilityIndirect
+                    | AttributeKind::MacroTransparency(_),
+                ) => { /* do nothing  */ }
+                Attribute::Unparsed(_) => {
                     match attr.path().as_slice() {
                         [sym::diagnostic, sym::do_not_recommend, ..] => {
                             self.check_do_not_recommend(attr.span(), hir_id, target, attr, item)
@@ -169,9 +184,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                             self.check_rustc_layout_scalar_valid_range(attr, span, target)
                         }
                         [sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target),
-                        [sym::rustc_allow_const_fn_unstable, ..] => {
-                            self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target)
-                        }
                         [sym::rustc_std_internal_symbol, ..] => {
                             self.check_rustc_std_internal_symbol(attr, span, target)
                         }
@@ -229,7 +241,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         [sym::link_name, ..] => self.check_link_name(hir_id, attr, span, target),
                         [sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target),
                         [sym::no_mangle, ..] => self.check_no_mangle(hir_id, attr, span, target),
-                        [sym::deprecated, ..] => self.check_deprecated(hir_id, attr, span, target),
                         [sym::macro_use, ..] | [sym::macro_escape, ..] => {
                             self.check_macro_use(hir_id, attr, target)
                         }
@@ -283,7 +294,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                             | sym::pointee // FIXME(derive_coerce_pointee)
                             | sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section)
                             | sym::used // handled elsewhere to restrict to static items
-                            | sym::repr // handled elsewhere to restrict to type decls items
                             | sym::instruction_set // broken on stable!!!
                             | sym::windows_subsystem // broken on stable!!!
                             | sym::patchable_function_entry // FIXME(patchable_function_entry)
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index d48a599f544..5d1182fce48 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -443,7 +443,7 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     ("fma", Stable, &["avx"]),
     ("fxsr", Stable, &[]),
     ("gfni", Stable, &["sse2"]),
-    ("kl", Unstable(sym::keylocker_x86), &["sse2"]),
+    ("kl", Stable, &["sse2"]),
     ("lahfsahf", Unstable(sym::lahfsahf_target_feature), &[]),
     ("lzcnt", Stable, &[]),
     ("movbe", Stable, &[]),
@@ -471,7 +471,7 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     ("tbm", Unstable(sym::tbm_target_feature), &[]),
     ("vaes", Stable, &["avx2", "aes"]),
     ("vpclmulqdq", Stable, &["avx", "pclmulqdq"]),
-    ("widekl", Unstable(sym::keylocker_x86), &["kl"]),
+    ("widekl", Stable, &["kl"]),
     ("x87", Unstable(sym::x87_target_feature), &[]),
     ("xop", Unstable(sym::xop_target_feature), &[/*"fma4", */ "avx", "sse4a"]),
     ("xsave", Stable, &[]),
diff --git a/library/compiler-builtins/compiler-builtins/src/lib.rs b/library/compiler-builtins/compiler-builtins/src/lib.rs
index 6a6b28067e8..6549d4cef9e 100644
--- a/library/compiler-builtins/compiler-builtins/src/lib.rs
+++ b/library/compiler-builtins/compiler-builtins/src/lib.rs
@@ -8,6 +8,7 @@
 #![feature(linkage)]
 #![feature(naked_functions)]
 #![feature(repr_simd)]
+#![feature(rustc_attrs)]
 #![cfg_attr(f16_enabled, feature(f16))]
 #![cfg_attr(f128_enabled, feature(f128))]
 #![no_builtins]
diff --git a/library/compiler-builtins/compiler-builtins/src/probestack.rs b/library/compiler-builtins/compiler-builtins/src/probestack.rs
index c9070cf55c6..1441fd73b8d 100644
--- a/library/compiler-builtins/compiler-builtins/src/probestack.rs
+++ b/library/compiler-builtins/compiler-builtins/src/probestack.rs
@@ -49,304 +49,198 @@
 // We only define stack probing for these architectures today.
 #![cfg(any(target_arch = "x86_64", target_arch = "x86"))]
 
-// SAFETY: defined in this module.
-// FIXME(extern_custom): the ABI is not correct.
-unsafe extern "C" {
-    pub fn __rust_probestack();
-}
-
-// A wrapper for our implementation of __rust_probestack, which allows us to
-// keep the assembly inline while controlling all CFI directives in the assembly
-// emitted for the function.
-//
-// This is the ELF version.
-#[cfg(not(any(target_vendor = "apple", target_os = "uefi")))]
-macro_rules! define_rust_probestack {
-    ($body: expr) => {
-        concat!(
-            "
-            .pushsection .text.__rust_probestack
-            .globl __rust_probestack
-            .type  __rust_probestack, @function
-            .hidden __rust_probestack
-        __rust_probestack:
-            ",
-            $body,
-            "
-            .size __rust_probestack, . - __rust_probestack
-            .popsection
-            "
-        )
-    };
-}
-
-#[cfg(all(target_os = "uefi", target_arch = "x86_64"))]
-macro_rules! define_rust_probestack {
-    ($body: expr) => {
-        concat!(
-            "
-            .globl __rust_probestack
-        __rust_probestack:
-            ",
-            $body
-        )
-    };
-}
-
-// Same as above, but for Mach-O. Note that the triple underscore
-// is deliberate
-#[cfg(target_vendor = "apple")]
-macro_rules! define_rust_probestack {
-    ($body: expr) => {
-        concat!(
-            "
-            .globl ___rust_probestack
-        ___rust_probestack:
-            ",
-            $body
-        )
-    };
-}
-
-// In UEFI x86 arch, triple underscore is deliberate.
-#[cfg(all(target_os = "uefi", target_arch = "x86"))]
-macro_rules! define_rust_probestack {
-    ($body: expr) => {
-        concat!(
-            "
-            .globl ___rust_probestack
-        ___rust_probestack:
-            ",
-            $body
-        )
-    };
-}
-
 // Our goal here is to touch each page between %rsp+8 and %rsp+8-%rax,
 // ensuring that if any pages are unmapped we'll make a page fault.
 //
+// FIXME(abi_custom): This function is unsafe because it uses a custom ABI,
+// it does not actually match `extern "C"`.
+//
 // The ABI here is that the stack frame size is located in `%rax`. Upon
 // return we're not supposed to modify `%rsp` or `%rax`.
-//
-// Any changes to this function should be replicated to the SGX version below.
-#[cfg(all(
-    target_arch = "x86_64",
-    not(all(target_env = "sgx", target_vendor = "fortanix"))
-))]
-core::arch::global_asm!(
-    define_rust_probestack!(
-        "
-    .cfi_startproc
-    pushq  %rbp
-    .cfi_adjust_cfa_offset 8
-    .cfi_offset %rbp, -16
-    movq   %rsp, %rbp
-    .cfi_def_cfa_register %rbp
-
-    mov    %rax,%r11        // duplicate %rax as we're clobbering %r11
-
-    // Main loop, taken in one page increments. We're decrementing rsp by
-    // a page each time until there's less than a page remaining. We're
-    // guaranteed that this function isn't called unless there's more than a
-    // page needed.
-    //
-    // Note that we're also testing against `8(%rsp)` to account for the 8
-    // bytes pushed on the stack orginally with our return address. Using
-    // `8(%rsp)` simulates us testing the stack pointer in the caller's
-    // context.
-
-    // It's usually called when %rax >= 0x1000, but that's not always true.
-    // Dynamic stack allocation, which is needed to implement unsized
-    // rvalues, triggers stackprobe even if %rax < 0x1000.
-    // Thus we have to check %r11 first to avoid segfault.
-    cmp    $0x1000,%r11
-    jna    3f
-2:
-    sub    $0x1000,%rsp
-    test   %rsp,8(%rsp)
-    sub    $0x1000,%r11
-    cmp    $0x1000,%r11
-    ja     2b
-
-3:
-    // Finish up the last remaining stack space requested, getting the last
-    // bits out of r11
-    sub    %r11,%rsp
-    test   %rsp,8(%rsp)
-
-    // Restore the stack pointer to what it previously was when entering
-    // this function. The caller will readjust the stack pointer after we
-    // return.
-    add    %rax,%rsp
-
-    leave
-    .cfi_def_cfa_register %rsp
-    .cfi_adjust_cfa_offset -8
-    ret
-    .cfi_endproc
-    "
-    ),
-    options(att_syntax)
-);
+#[cfg(target_arch = "x86_64")]
+#[unsafe(naked)]
+#[rustc_std_internal_symbol]
+pub unsafe extern "C" fn __rust_probestack() {
+    #[cfg(not(all(target_env = "sgx", target_vendor = "fortanix")))]
+    macro_rules! ret {
+        () => {
+            "ret"
+        };
+    }
+
+    #[cfg(all(target_env = "sgx", target_vendor = "fortanix"))]
+    macro_rules! ret {
+        // for this target, [manually patch for LVI].
+        //
+        // [manually patch for LVI]: https://software.intel.com/security-software-guidance/insights/deep-dive-load-value-injection#specialinstructions
+        () => {
+            "
+            pop %r11
+            lfence
+            jmp *%r11
+            "
+        };
+    }
 
-// This function is the same as above, except that some instructions are
-// [manually patched for LVI].
-//
-// [manually patched for LVI]: https://software.intel.com/security-software-guidance/insights/deep-dive-load-value-injection#specialinstructions
-#[cfg(all(
-    target_arch = "x86_64",
-    all(target_env = "sgx", target_vendor = "fortanix")
-))]
-core::arch::global_asm!(
-    define_rust_probestack!(
+    core::arch::naked_asm!(
         "
-    .cfi_startproc
-    pushq  %rbp
-    .cfi_adjust_cfa_offset 8
-    .cfi_offset %rbp, -16
-    movq   %rsp, %rbp
-    .cfi_def_cfa_register %rbp
-
-    mov    %rax,%r11        // duplicate %rax as we're clobbering %r11
-
-    // Main loop, taken in one page increments. We're decrementing rsp by
-    // a page each time until there's less than a page remaining. We're
-    // guaranteed that this function isn't called unless there's more than a
-    // page needed.
-    //
-    // Note that we're also testing against `8(%rsp)` to account for the 8
-    // bytes pushed on the stack orginally with our return address. Using
-    // `8(%rsp)` simulates us testing the stack pointer in the caller's
-    // context.
-
-    // It's usually called when %rax >= 0x1000, but that's not always true.
-    // Dynamic stack allocation, which is needed to implement unsized
-    // rvalues, triggers stackprobe even if %rax < 0x1000.
-    // Thus we have to check %r11 first to avoid segfault.
-    cmp    $0x1000,%r11
-    jna    3f
-2:
-    sub    $0x1000,%rsp
-    test   %rsp,8(%rsp)
-    sub    $0x1000,%r11
-    cmp    $0x1000,%r11
-    ja     2b
-
-3:
-    // Finish up the last remaining stack space requested, getting the last
-    // bits out of r11
-    sub    %r11,%rsp
-    test   %rsp,8(%rsp)
-
-    // Restore the stack pointer to what it previously was when entering
-    // this function. The caller will readjust the stack pointer after we
-    // return.
-    add    %rax,%rsp
-
-    leave
-    .cfi_def_cfa_register %rsp
-    .cfi_adjust_cfa_offset -8
-    pop %r11
-    lfence
-    jmp *%r11
-    .cfi_endproc
-    "
-    ),
-    options(att_syntax)
-);
+            .cfi_startproc
+            pushq  %rbp
+            .cfi_adjust_cfa_offset 8
+            .cfi_offset %rbp, -16
+            movq   %rsp, %rbp
+            .cfi_def_cfa_register %rbp
+
+            mov    %rax,%r11        // duplicate %rax as we're clobbering %r11
+
+            // Main loop, taken in one page increments. We're decrementing rsp by
+            // a page each time until there's less than a page remaining. We're
+            // guaranteed that this function isn't called unless there's more than a
+            // page needed.
+            //
+            // Note that we're also testing against `8(%rsp)` to account for the 8
+            // bytes pushed on the stack orginally with our return address. Using
+            // `8(%rsp)` simulates us testing the stack pointer in the caller's
+            // context.
+
+            // It's usually called when %rax >= 0x1000, but that's not always true.
+            // Dynamic stack allocation, which is needed to implement unsized
+            // rvalues, triggers stackprobe even if %rax < 0x1000.
+            // Thus we have to check %r11 first to avoid segfault.
+            cmp    $0x1000,%r11
+            jna    3f
+        2:
+            sub    $0x1000,%rsp
+            test   %rsp,8(%rsp)
+            sub    $0x1000,%r11
+            cmp    $0x1000,%r11
+            ja     2b
+
+        3:
+            // Finish up the last remaining stack space requested, getting the last
+            // bits out of r11
+            sub    %r11,%rsp
+            test   %rsp,8(%rsp)
+
+            // Restore the stack pointer to what it previously was when entering
+            // this function. The caller will readjust the stack pointer after we
+            // return.
+            add    %rax,%rsp
+
+            leave
+            .cfi_def_cfa_register %rsp
+            .cfi_adjust_cfa_offset -8
+    ",
+        ret!(),
+        "
+            .cfi_endproc
+    ",
+        options(att_syntax)
+    )
+}
 
 #[cfg(all(target_arch = "x86", not(target_os = "uefi")))]
 // This is the same as x86_64 above, only translated for 32-bit sizes. Note
 // that on Unix we're expected to restore everything as it was, this
 // function basically can't tamper with anything.
 //
+// FIXME(abi_custom): This function is unsafe because it uses a custom ABI,
+// it does not actually match `extern "C"`.
+//
 // The ABI here is the same as x86_64, except everything is 32-bits large.
-core::arch::global_asm!(
-    define_rust_probestack!(
+#[unsafe(naked)]
+#[rustc_std_internal_symbol]
+pub unsafe extern "C" fn __rust_probestack() {
+    core::arch::naked_asm!(
         "
-    .cfi_startproc
-    push   %ebp
-    .cfi_adjust_cfa_offset 4
-    .cfi_offset %ebp, -8
-    mov    %esp, %ebp
-    .cfi_def_cfa_register %ebp
-    push   %ecx
-    mov    %eax,%ecx
-
-    cmp    $0x1000,%ecx
-    jna    3f
-2:
-    sub    $0x1000,%esp
-    test   %esp,8(%esp)
-    sub    $0x1000,%ecx
-    cmp    $0x1000,%ecx
-    ja     2b
-
-3:
-    sub    %ecx,%esp
-    test   %esp,8(%esp)
-
-    add    %eax,%esp
-    pop    %ecx
-    leave
-    .cfi_def_cfa_register %esp
-    .cfi_adjust_cfa_offset -4
-    ret
-    .cfi_endproc
-    "
-    ),
-    options(att_syntax)
-);
+            .cfi_startproc
+            push   %ebp
+            .cfi_adjust_cfa_offset 4
+            .cfi_offset %ebp, -8
+            mov    %esp, %ebp
+            .cfi_def_cfa_register %ebp
+            push   %ecx
+            mov    %eax,%ecx
+
+            cmp    $0x1000,%ecx
+            jna    3f
+        2:
+            sub    $0x1000,%esp
+            test   %esp,8(%esp)
+            sub    $0x1000,%ecx
+            cmp    $0x1000,%ecx
+            ja     2b
+
+        3:
+            sub    %ecx,%esp
+            test   %esp,8(%esp)
+
+            add    %eax,%esp
+            pop    %ecx
+            leave
+            .cfi_def_cfa_register %esp
+            .cfi_adjust_cfa_offset -4
+            ret
+            .cfi_endproc
+    ",
+        options(att_syntax)
+    )
+}
 
 #[cfg(all(target_arch = "x86", target_os = "uefi"))]
 // UEFI target is windows like target. LLVM will do _chkstk things like windows.
 // probestack function will also do things like _chkstk in MSVC.
 // So we need to sub %ax %sp in probestack when arch is x86.
 //
+// FIXME(abi_custom): This function is unsafe because it uses a custom ABI,
+// it does not actually match `extern "C"`.
+//
 // REF: Rust commit(74e80468347)
 // rust\src\llvm-project\llvm\lib\Target\X86\X86FrameLowering.cpp: 805
 // Comments in LLVM:
 //   MSVC x32's _chkstk and cygwin/mingw's _alloca adjust %esp themselves.
 //   MSVC x64's __chkstk and cygwin/mingw's ___chkstk_ms do not adjust %rsp
 //   themselves.
-core::arch::global_asm!(
-    define_rust_probestack!(
+#[unsafe(naked)]
+#[rustc_std_internal_symbol]
+pub unsafe extern "C" fn __rust_probestack() {
+    core::arch::naked_asm!(
         "
-    .cfi_startproc
-    push   %ebp
-    .cfi_adjust_cfa_offset 4
-    .cfi_offset %ebp, -8
-    mov    %esp, %ebp
-    .cfi_def_cfa_register %ebp
-    push   %ecx
-    push   %edx
-    mov    %eax,%ecx
-
-    cmp    $0x1000,%ecx
-    jna    3f
-2:
-    sub    $0x1000,%esp
-    test   %esp,8(%esp)
-    sub    $0x1000,%ecx
-    cmp    $0x1000,%ecx
-    ja     2b
-
-3:
-    sub    %ecx,%esp
-    test   %esp,8(%esp)
-    mov    4(%ebp),%edx
-    mov    %edx, 12(%esp)
-    add    %eax,%esp
-    pop    %edx
-    pop    %ecx
-    leave
-
-    sub   %eax, %esp
-    .cfi_def_cfa_register %esp
-    .cfi_adjust_cfa_offset -4
-    ret
-    .cfi_endproc
-    "
-    ),
-    options(att_syntax)
-);
+            .cfi_startproc
+            push   %ebp
+            .cfi_adjust_cfa_offset 4
+            .cfi_offset %ebp, -8
+            mov    %esp, %ebp
+            .cfi_def_cfa_register %ebp
+            push   %ecx
+            push   %edx
+            mov    %eax,%ecx
+
+            cmp    $0x1000,%ecx
+            jna    3f
+        2:
+            sub    $0x1000,%esp
+            test   %esp,8(%esp)
+            sub    $0x1000,%ecx
+            cmp    $0x1000,%ecx
+            ja     2b
+
+        3:
+            sub    %ecx,%esp
+            test   %esp,8(%esp)
+            mov    4(%ebp),%edx
+            mov    %edx, 12(%esp)
+            add    %eax,%esp
+            pop    %edx
+            pop    %ecx
+            leave
+
+            sub   %eax, %esp
+            .cfi_def_cfa_register %esp
+            .cfi_adjust_cfa_offset -4
+            ret
+            .cfi_endproc
+    ",
+        options(att_syntax)
+    )
+}
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index fc98ae9ff3f..88855831788 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -190,7 +190,6 @@
 #![feature(aarch64_unstable_target_feature)]
 #![feature(arm_target_feature)]
 #![feature(hexagon_target_feature)]
-#![feature(keylocker_x86)]
 #![feature(loongarch_target_feature)]
 #![feature(mips_target_feature)]
 #![feature(powerpc_target_feature)]
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index d5efb03cfbc..b21845a1c16 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -1273,6 +1273,19 @@ pub(crate) mod builtin {
     /// first macro invocation leading up to the invocation of the `file!`
     /// macro.
     ///
+    /// The file name is derived from the crate root's source path passed to the Rust compiler
+    /// and the sequence the compiler takes to get from the crate root to the
+    /// module containing `file!`, modified by any flags passed to the Rust compiler (e.g.
+    /// `--remap-path-prefix`).  If the crate's source path is relative, the initial base
+    /// directory will be the working directory of the Rust compiler.  For example, if the source
+    /// path passed to the compiler is `./src/lib.rs` which has a `mod foo;` with a source path of
+    /// `src/foo/mod.rs`, then calling `file!` inside `mod foo;` will return `./src/foo/mod.rs`.
+    ///
+    /// Future compiler options might make further changes to the behavior of `file!`,
+    /// including potentially making it entirely empty. Code (e.g. test libraries)
+    /// relying on `file!` producing an openable file path would be incompatible
+    /// with such options, and might wish to recommend not using those options.
+    ///
     /// # Examples
     ///
     /// ```
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index a1dab23ea7b..9366cb36c6e 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -5,24 +5,7 @@ use crate::mem::{self, SizedTypeProperties};
 use crate::slice::{self, SliceIndex};
 
 impl<T: ?Sized> *const T {
-    /// Returns `true` if the pointer is null.
-    ///
-    /// Note that unsized types have many possible null pointers, as only the
-    /// raw data pointer is considered, not their length, vtable, etc.
-    /// Therefore, two pointers that are null may still not compare equal to
-    /// each other.
-    ///
-    /// # Panics during const evaluation
-    ///
-    /// If this method is used during const evaluation, and `self` is a pointer
-    /// that is offset beyond the bounds of the memory it initially pointed to,
-    /// then there might not be enough information to determine whether the
-    /// pointer is null. This is because the absolute address in memory is not
-    /// known at compile time. If the nullness of the pointer cannot be
-    /// determined, this method will panic.
-    ///
-    /// In-bounds pointers are never null, so the method will never panic for
-    /// such pointers.
+    #[doc = include_str!("docs/is_null.md")]
     ///
     /// # Examples
     ///
@@ -1550,50 +1533,7 @@ impl<T> *const [T] {
         unsafe { index.get_unchecked(self) }
     }
 
-    /// Returns `None` if the pointer is null, or else returns a shared slice to
-    /// the value wrapped in `Some`. In contrast to [`as_ref`], this does not require
-    /// that the value has to be initialized.
-    ///
-    /// [`as_ref`]: #method.as_ref
-    ///
-    /// # Safety
-    ///
-    /// When calling this method, you have to ensure that *either* the pointer is null *or*
-    /// all of the following is true:
-    ///
-    /// * The pointer must be [valid] for reads for `ptr.len() * size_of::<T>()` many bytes,
-    ///   and it must be properly aligned. This means in particular:
-    ///
-    ///     * The entire memory range of this slice must be contained within a single [allocation]!
-    ///       Slices can never span across multiple allocations.
-    ///
-    ///     * The pointer must be aligned even for zero-length slices. One
-    ///       reason for this is that enum layout optimizations may rely on references
-    ///       (including slices of any length) being aligned and non-null to distinguish
-    ///       them from other data. You can obtain a pointer that is usable as `data`
-    ///       for zero-length slices using [`NonNull::dangling()`].
-    ///
-    /// * The total size `ptr.len() * size_of::<T>()` of the slice must be no larger than `isize::MAX`.
-    ///   See the safety documentation of [`pointer::offset`].
-    ///
-    /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
-    ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
-    ///   In particular, while this reference exists, the memory the pointer points to must
-    ///   not get mutated (except inside `UnsafeCell`).
-    ///
-    /// This applies even if the result of this method is unused!
-    ///
-    /// See also [`slice::from_raw_parts`][].
-    ///
-    /// [valid]: crate::ptr#safety
-    /// [allocation]: crate::ptr#allocation
-    ///
-    /// # Panics during const evaluation
-    ///
-    /// This method will panic during const evaluation if the pointer cannot be
-    /// determined to be null or not. See [`is_null`] for more information.
-    ///
-    /// [`is_null`]: #method.is_null
+    #[doc = include_str!("docs/as_uninit_slice.md")]
     #[inline]
     #[unstable(feature = "ptr_as_uninit", issue = "75402")]
     pub const unsafe fn as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit<T>]> {
diff --git a/library/core/src/ptr/docs/as_uninit_slice.md b/library/core/src/ptr/docs/as_uninit_slice.md
new file mode 100644
index 00000000000..c80c0405883
--- /dev/null
+++ b/library/core/src/ptr/docs/as_uninit_slice.md
@@ -0,0 +1,44 @@
+Returns `None` if the pointer is null, or else returns a shared slice to
+the value wrapped in `Some`. In contrast to [`as_ref`], this does not require
+that the value has to be initialized.
+
+[`as_ref`]: #method.as_ref
+
+# Safety
+
+When calling this method, you have to ensure that *either* the pointer is null *or*
+all of the following is true:
+
+* The pointer must be [valid] for reads for `ptr.len() * size_of::<T>()` many bytes,
+and it must be properly aligned. This means in particular:
+
+* The entire memory range of this slice must be contained within a single [allocation]!
+Slices can never span across multiple allocations.
+
+* The pointer must be aligned even for zero-length slices. One
+reason for this is that enum layout optimizations may rely on references
+(including slices of any length) being aligned and non-null to distinguish
+them from other data. You can obtain a pointer that is usable as `data`
+for zero-length slices using [`NonNull::dangling()`].
+
+* The total size `ptr.len() * size_of::<T>()` of the slice must be no larger than `isize::MAX`.
+See the safety documentation of [`pointer::offset`].
+
+* You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
+arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
+In particular, while this reference exists, the memory the pointer points to must
+not get mutated (except inside `UnsafeCell`).
+
+This applies even if the result of this method is unused!
+
+See also [`slice::from_raw_parts`][].
+
+[valid]: crate::ptr#safety
+[allocation]: crate::ptr#allocation
+
+# Panics during const evaluation
+
+This method will panic during const evaluation if the pointer cannot be
+determined to be null or not. See [`is_null`] for more information.
+
+[`is_null`]: #method.is_null
diff --git a/library/core/src/ptr/docs/is_null.md b/library/core/src/ptr/docs/is_null.md
new file mode 100644
index 00000000000..7368ab9b576
--- /dev/null
+++ b/library/core/src/ptr/docs/is_null.md
@@ -0,0 +1,18 @@
+Returns `true` if the pointer is null.
+
+Note that unsized types have many possible null pointers, as only the
+raw data pointer is considered, not their length, vtable, etc.
+Therefore, two pointers that are null may still not compare equal to
+each other.
+
+# Panics during const evaluation
+
+If this method is used during const evaluation, and `self` is a pointer
+that is offset beyond the bounds of the memory it initially pointed to,
+then there might not be enough information to determine whether the
+pointer is null. This is because the absolute address in memory is not
+known at compile time. If the nullness of the pointer cannot be
+determined, this method will panic.
+
+In-bounds pointers are never null, so the method will never panic for
+such pointers.
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index 968f033bf59..efe1031b79c 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -5,24 +5,7 @@ use crate::mem::{self, SizedTypeProperties};
 use crate::slice::{self, SliceIndex};
 
 impl<T: ?Sized> *mut T {
-    /// Returns `true` if the pointer is null.
-    ///
-    /// Note that unsized types have many possible null pointers, as only the
-    /// raw data pointer is considered, not their length, vtable, etc.
-    /// Therefore, two pointers that are null may still not compare equal to
-    /// each other.
-    ///
-    /// # Panics during const evaluation
-    ///
-    /// If this method is used during const evaluation, and `self` is a pointer
-    /// that is offset beyond the bounds of the memory it initially pointed to,
-    /// then there might not be enough information to determine whether the
-    /// pointer is null. This is because the absolute address in memory is not
-    /// known at compile time. If the nullness of the pointer cannot be
-    /// determined, this method will panic.
-    ///
-    /// In-bounds pointers are never null, so the method will never panic for
-    /// such pointers.
+    #[doc = include_str!("docs/is_null.md")]
     ///
     /// # Examples
     ///
@@ -1906,53 +1889,10 @@ impl<T> *mut [T] {
         unsafe { index.get_unchecked_mut(self) }
     }
 
-    /// Returns `None` if the pointer is null, or else returns a shared slice to
-    /// the value wrapped in `Some`. In contrast to [`as_ref`], this does not require
-    /// that the value has to be initialized.
-    ///
-    /// For the mutable counterpart see [`as_uninit_slice_mut`].
-    ///
-    /// [`as_ref`]: pointer#method.as_ref-1
-    /// [`as_uninit_slice_mut`]: #method.as_uninit_slice_mut
-    ///
-    /// # Safety
-    ///
-    /// When calling this method, you have to ensure that *either* the pointer is null *or*
-    /// all of the following is true:
-    ///
-    /// * The pointer must be [valid] for reads for `ptr.len() * size_of::<T>()` many bytes,
-    ///   and it must be properly aligned. This means in particular:
-    ///
-    ///     * The entire memory range of this slice must be contained within a single [allocation]!
-    ///       Slices can never span across multiple allocations.
-    ///
-    ///     * The pointer must be aligned even for zero-length slices. One
-    ///       reason for this is that enum layout optimizations may rely on references
-    ///       (including slices of any length) being aligned and non-null to distinguish
-    ///       them from other data. You can obtain a pointer that is usable as `data`
-    ///       for zero-length slices using [`NonNull::dangling()`].
-    ///
-    /// * The total size `ptr.len() * size_of::<T>()` of the slice must be no larger than `isize::MAX`.
-    ///   See the safety documentation of [`pointer::offset`].
-    ///
-    /// * You must enforce Rust's aliasing rules, since the returned lifetime `'a` is
-    ///   arbitrarily chosen and does not necessarily reflect the actual lifetime of the data.
-    ///   In particular, while this reference exists, the memory the pointer points to must
-    ///   not get mutated (except inside `UnsafeCell`).
-    ///
-    /// This applies even if the result of this method is unused!
-    ///
-    /// See also [`slice::from_raw_parts`][].
-    ///
-    /// [valid]: crate::ptr#safety
-    /// [allocation]: crate::ptr#allocation
+    #[doc = include_str!("docs/as_uninit_slice.md")]
     ///
-    /// # Panics during const evaluation
-    ///
-    /// This method will panic during const evaluation if the pointer cannot be
-    /// determined to be null or not. See [`is_null`] for more information.
-    ///
-    /// [`is_null`]: #method.is_null-1
+    /// # See Also
+    /// For the mutable counterpart see [`as_uninit_slice_mut`](pointer::as_uninit_slice_mut).
     #[inline]
     #[unstable(feature = "ptr_as_uninit", issue = "75402")]
     pub const unsafe fn as_uninit_slice<'a>(self) -> Option<&'a [MaybeUninit<T>]> {
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 4f7e1440880..c26bbad087a 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -21,6 +21,7 @@ use crate::{fmt, hint, ptr, range, slice};
     issue = "none",
     reason = "exposed from core to be reused in std; use the memchr crate"
 )]
+#[doc(hidden)]
 /// Pure Rust memchr implementation, taken from rust-memchr
 pub mod memchr;
 
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 20c82b64bcc..a9a24681e7c 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -917,6 +917,19 @@ pub trait Read {
     /// # }
     /// ```
     ///
+    /// # Usage Notes
+    ///
+    /// `read_to_end` attempts to read a source until EOF, but many sources are continuous streams
+    /// that do not send EOF. In these cases, `read_to_end` will block indefinitely. Standard input
+    /// is one such stream which may be finite if piped, but is typically continuous. For example,
+    /// `cat file | my-rust-program` will correctly terminate with an `EOF` upon closure of cat.
+    /// Reading user input or running programs that remain open indefinitely will never terminate
+    /// the stream with `EOF` (e.g. `yes | my-rust-program`).
+    ///
+    /// Using `.lines()` with a [`BufReader`] or using [`read`] can provide a better solution
+    ///
+    ///[`read`]: Read::read
+    ///
     /// [`Vec::try_reserve`]: crate::vec::Vec::try_reserve
     #[stable(feature = "rust1", since = "1.0.0")]
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<usize> {
@@ -960,6 +973,19 @@ pub trait Read {
     /// (See also the [`std::fs::read_to_string`] convenience function for
     /// reading from a file.)
     ///
+    /// # Usage Notes
+    ///
+    /// `read_to_string` attempts to read a source until EOF, but many sources are continuous streams
+    /// that do not send EOF. In these cases, `read_to_string` will block indefinitely. Standard input
+    /// is one such stream which may be finite if piped, but is typically continuous. For example,
+    /// `cat file | my-rust-program` will correctly terminate with an `EOF` upon closure of cat.
+    /// Reading user input or running programs that remain open indefinitely will never terminate
+    /// the stream with `EOF` (e.g. `yes | my-rust-program`).
+    ///
+    /// Using `.lines()` with a [`BufReader`] or using [`read`] can provide a better solution
+    ///
+    ///[`read`]: Read::read
+    ///
     /// [`std::fs::read_to_string`]: crate::fs::read_to_string
     #[stable(feature = "rust1", since = "1.0.0")]
     fn read_to_string(&mut self, buf: &mut String) -> Result<usize> {
@@ -1262,6 +1288,20 @@ pub trait Read {
 ///     Ok(())
 /// }
 /// ```
+///
+/// # Usage Notes
+///
+/// `read_to_string` attempts to read a source until EOF, but many sources are continuous streams
+/// that do not send EOF. In these cases, `read_to_string` will block indefinitely. Standard input
+/// is one such stream which may be finite if piped, but is typically continuous. For example,
+/// `cat file | my-rust-program` will correctly terminate with an `EOF` upon closure of cat.
+/// Reading user input or running programs that remain open indefinitely will never terminate
+/// the stream with `EOF` (e.g. `yes | my-rust-program`).
+///
+/// Using `.lines()` with a [`BufReader`] or using [`read`] can provide a better solution
+///
+///[`read`]: Read::read
+///
 #[stable(feature = "io_read_to_string", since = "1.65.0")]
 pub fn read_to_string<R: Read>(mut reader: R) -> Result<String> {
     let mut buf = String::new();
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 587fca80374..7aa9e6cc2b5 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -1681,7 +1681,8 @@ impl Step for Extended {
             cmd.run(builder);
         }
 
-        if target.is_windows() {
+        // FIXME(mati865): `gnullvm` here is temporary, remove it once it can host itself
+        if target.is_windows() && !target.contains("gnullvm") {
             let exe = tmp.join("exe");
             let _ = fs::remove_dir_all(&exe);
 
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 9861637d8c8..717accb399a 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -23,7 +23,6 @@ use crate::core::builder::{
     Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step, cargo_profile_var,
 };
 use crate::core::config::{DebuginfoLevel, RustcLto, TargetSelection};
-use crate::utils::channel::GitInfo;
 use crate::utils::exec::{BootstrapCommand, command};
 use crate::utils::helpers::{add_dylib_path, exe, t};
 use crate::{Compiler, FileType, Kind, Mode, gha};
@@ -278,7 +277,7 @@ pub fn prepare_tool_cargo(
         cargo.env("CFG_VER_DESCRIPTION", description);
     }
 
-    let info = GitInfo::new(builder.config.omit_git_hash, &dir);
+    let info = builder.config.git_info(builder.config.omit_git_hash, &dir);
     if let Some(sha) = info.sha() {
         cargo.env("CFG_COMMIT_HASH", sha);
     }
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
index cf7f962d026..c6cfdb69356 100644
--- a/src/bootstrap/src/core/builder/cargo.rs
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -551,7 +551,7 @@ impl Builder<'_> {
         let libdir = self.rustc_libdir(compiler);
 
         let sysroot_str = sysroot.as_os_str().to_str().expect("sysroot should be UTF-8");
-        if self.is_verbose() && !matches!(self.config.dry_run, DryRun::SelfCheck) {
+        if self.is_verbose() && !matches!(self.config.get_dry_run(), DryRun::SelfCheck) {
             println!("using sysroot {sysroot_str}");
         }
 
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index 19b79bfe818..8b1520de3a8 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -22,6 +22,7 @@ use crate::core::config::flags::Subcommand;
 use crate::core::config::{DryRun, TargetSelection};
 use crate::utils::cache::Cache;
 use crate::utils::exec::{BootstrapCommand, command};
+use crate::utils::execution_context::ExecutionContext;
 use crate::utils::helpers::{self, LldThreads, add_dylib_path, exe, libdir, linker_args, t};
 use crate::{Build, Crate, trace};
 
@@ -442,13 +443,15 @@ impl StepDescription {
 
     fn is_excluded(&self, builder: &Builder<'_>, pathset: &PathSet) -> bool {
         if builder.config.skip.iter().any(|e| pathset.has(e, builder.kind)) {
-            if !matches!(builder.config.dry_run, DryRun::SelfCheck) {
+            if !matches!(builder.config.get_dry_run(), DryRun::SelfCheck) {
                 println!("Skipping {pathset:?} because it is excluded");
             }
             return true;
         }
 
-        if !builder.config.skip.is_empty() && !matches!(builder.config.dry_run, DryRun::SelfCheck) {
+        if !builder.config.skip.is_empty()
+            && !matches!(builder.config.get_dry_run(), DryRun::SelfCheck)
+        {
             builder.verbose(|| {
                 println!(
                     "{:?} not skipped for {:?} -- not in {:?}",
@@ -1633,4 +1636,14 @@ impl<'a> Builder<'a> {
             self.info(&format!("{err}\n"));
         }
     }
+
+    pub fn exec_ctx(&self) -> &ExecutionContext {
+        &self.config.exec_ctx
+    }
+}
+
+impl<'a> AsRef<ExecutionContext> for Builder<'a> {
+    fn as_ref(&self) -> &ExecutionContext {
+        self.exec_ctx()
+    }
 }
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index baa22fc7f72..a264d772c56 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -22,7 +22,7 @@ fn configure_with_args(cmd: &[String], host: &[&str], target: &[&str]) -> Config
     let mut config = Config::parse(Flags::parse(cmd));
     // don't save toolstates
     config.save_toolstates = None;
-    config.dry_run = DryRun::SelfCheck;
+    config.set_dry_run(DryRun::SelfCheck);
 
     // Ignore most submodules, since we don't need them for a dry run, and the
     // tests run much faster without them.
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 824b159c326..7f52697e6c7 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -24,7 +24,7 @@ use std::{cmp, env, fs};
 
 use build_helper::ci::CiEnv;
 use build_helper::exit;
-use build_helper::git::{GitConfig, PathFreshness, check_path_modifications, output_result};
+use build_helper::git::{GitConfig, PathFreshness, check_path_modifications};
 use serde::Deserialize;
 #[cfg(feature = "tracing")]
 use tracing::{instrument, span};
@@ -47,8 +47,10 @@ use crate::core::config::{
 };
 use crate::core::download::is_download_ci_available;
 use crate::utils::channel;
+use crate::utils::exec::command;
+use crate::utils::execution_context::ExecutionContext;
 use crate::utils::helpers::exe;
-use crate::{Command, GitInfo, OnceLock, TargetSelection, check_ci_llvm, helpers, output, t};
+use crate::{GitInfo, OnceLock, TargetSelection, check_ci_llvm, helpers, t};
 
 /// Each path from this function is considered "allowed" in the `download-rustc="if-unchanged"` logic.
 /// This means they can be modified and changes to these paths should never trigger a compiler build
@@ -142,7 +144,6 @@ pub struct Config {
     pub jobs: Option<u32>,
     pub cmd: Subcommand,
     pub incremental: bool,
-    pub dry_run: DryRun,
     pub dump_bootstrap_shims: bool,
     /// Arguments appearing after `--` to be forwarded to tools,
     /// e.g. `--fix-broken` or test arguments.
@@ -317,6 +318,8 @@ pub struct Config {
     /// This is mostly for RA as building the stage1 compiler to check the library tree
     /// on each code change might be too much for some computers.
     pub skip_std_check_if_no_download_rustc: bool,
+
+    pub exec_ctx: ExecutionContext,
 }
 
 impl Config {
@@ -373,6 +376,14 @@ impl Config {
         }
     }
 
+    pub fn set_dry_run(&mut self, dry_run: DryRun) {
+        self.exec_ctx.set_dry_run(dry_run);
+    }
+
+    pub fn get_dry_run(&self) -> &DryRun {
+        self.exec_ctx.get_dry_run()
+    }
+
     #[cfg_attr(
         feature = "tracing",
         instrument(target = "CONFIG_HANDLING", level = "trace", name = "Config::parse", skip_all)
@@ -395,6 +406,11 @@ impl Config {
         get_toml: impl Fn(&Path) -> Result<TomlConfig, toml::de::Error>,
     ) -> Config {
         let mut config = Config::default_opts();
+        let mut exec_ctx = ExecutionContext::new();
+        exec_ctx.set_verbose(flags.verbose);
+        exec_ctx.set_fail_fast(flags.cmd.fail_fast());
+
+        config.exec_ctx = exec_ctx;
 
         // Set flags.
         config.paths = std::mem::take(&mut flags.paths);
@@ -423,7 +439,7 @@ impl Config {
         config.on_fail = flags.on_fail;
         config.cmd = flags.cmd;
         config.incremental = flags.incremental;
-        config.dry_run = if flags.dry_run { DryRun::UserSelected } else { DryRun::Disabled };
+        config.set_dry_run(if flags.dry_run { DryRun::UserSelected } else { DryRun::Disabled });
         config.dump_bootstrap_shims = flags.dump_bootstrap_shims;
         config.keep_stage = flags.keep_stage;
         config.keep_stage_std = flags.keep_stage_std;
@@ -453,14 +469,9 @@ impl Config {
             // has already been (kinda-cross-)compiled to Windows land, we require a normal Windows path.
             cmd.arg("rev-parse").arg("--show-cdup");
             // Discard stderr because we expect this to fail when building from a tarball.
-            let output = cmd
-                .as_command_mut()
-                .stderr(std::process::Stdio::null())
-                .output()
-                .ok()
-                .and_then(|output| if output.status.success() { Some(output) } else { None });
-            if let Some(output) = output {
-                let git_root_relative = String::from_utf8(output.stdout).unwrap();
+            let output = cmd.allow_failure().run_capture_stdout(&config);
+            if output.is_success() {
+                let git_root_relative = output.stdout();
                 // We need to canonicalize this path to make sure it uses backslashes instead of forward slashes,
                 // and to resolve any relative components.
                 let git_root = env::current_dir()
@@ -555,7 +566,7 @@ impl Config {
             build.cargo = build.cargo.take().or(std::env::var_os("CARGO").map(|p| p.into()));
         }
 
-        if GitInfo::new(false, &config.src).is_from_tarball() && toml.profile.is_none() {
+        if config.git_info(false, &config.src).is_from_tarball() && toml.profile.is_none() {
             toml.profile = Some("dist".into());
         }
 
@@ -762,7 +773,12 @@ impl Config {
         };
 
         config.initial_sysroot = t!(PathBuf::from_str(
-            output(Command::new(&config.initial_rustc).args(["--print", "sysroot"])).trim()
+            command(&config.initial_rustc)
+                .args(["--print", "sysroot"])
+                .run_always()
+                .run_capture_stdout(&config)
+                .stdout()
+                .trim()
         ));
 
         config.initial_cargo_clippy = cargo_clippy;
@@ -858,19 +874,21 @@ impl Config {
         let default = config.channel == "dev";
         config.omit_git_hash = toml.rust.as_ref().and_then(|r| r.omit_git_hash).unwrap_or(default);
 
-        config.rust_info = GitInfo::new(config.omit_git_hash, &config.src);
-        config.cargo_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/cargo"));
+        config.rust_info = config.git_info(config.omit_git_hash, &config.src);
+        config.cargo_info =
+            config.git_info(config.omit_git_hash, &config.src.join("src/tools/cargo"));
         config.rust_analyzer_info =
-            GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rust-analyzer"));
+            config.git_info(config.omit_git_hash, &config.src.join("src/tools/rust-analyzer"));
         config.clippy_info =
-            GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/clippy"));
-        config.miri_info = GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/miri"));
+            config.git_info(config.omit_git_hash, &config.src.join("src/tools/clippy"));
+        config.miri_info =
+            config.git_info(config.omit_git_hash, &config.src.join("src/tools/miri"));
         config.rustfmt_info =
-            GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/rustfmt"));
+            config.git_info(config.omit_git_hash, &config.src.join("src/tools/rustfmt"));
         config.enzyme_info =
-            GitInfo::new(config.omit_git_hash, &config.src.join("src/tools/enzyme"));
-        config.in_tree_llvm_info = GitInfo::new(false, &config.src.join("src/llvm-project"));
-        config.in_tree_gcc_info = GitInfo::new(false, &config.src.join("src/gcc"));
+            config.git_info(config.omit_git_hash, &config.src.join("src/tools/enzyme"));
+        config.in_tree_llvm_info = config.git_info(false, &config.src.join("src/llvm-project"));
+        config.in_tree_gcc_info = config.git_info(false, &config.src.join("src/gcc"));
 
         config.vendor = vendor.unwrap_or(
             config.rust_info.is_from_tarball()
@@ -1030,28 +1048,13 @@ impl Config {
     }
 
     pub fn dry_run(&self) -> bool {
-        match self.dry_run {
-            DryRun::Disabled => false,
-            DryRun::SelfCheck | DryRun::UserSelected => true,
-        }
+        self.exec_ctx.dry_run()
     }
 
     pub fn is_explicit_stage(&self) -> bool {
         self.explicit_stage_from_cli || self.explicit_stage_from_config
     }
 
-    /// Runs a command, printing out nice contextual information if it fails.
-    /// Exits if the command failed to execute at all, otherwise returns its
-    /// `status.success()`.
-    #[deprecated = "use `Builder::try_run` instead where possible"]
-    pub(crate) fn try_run(&self, cmd: &mut Command) -> Result<(), ()> {
-        if self.dry_run() {
-            return Ok(());
-        }
-        self.verbose(|| println!("running: {cmd:?}"));
-        build_helper::util::try_run(cmd, self.is_verbose())
-    }
-
     pub(crate) fn test_args(&self) -> Vec<&str> {
         let mut test_args = match self.cmd {
             Subcommand::Test { ref test_args, .. }
@@ -1085,7 +1088,7 @@ impl Config {
 
         let mut git = helpers::git(Some(&self.src));
         git.arg("show").arg(format!("{commit}:{}", file.to_str().unwrap()));
-        output(git.as_command_mut())
+        git.run_capture_stdout(self).stdout()
     }
 
     /// Bootstrap embeds a version number into the name of shared libraries it uploads in CI.
@@ -1273,9 +1276,7 @@ impl Config {
 
     /// Runs a function if verbosity is greater than 0
     pub fn verbose(&self, f: impl Fn()) {
-        if self.is_verbose() {
-            f()
-        }
+        self.exec_ctx.verbose(f);
     }
 
     pub fn any_sanitizers_to_build(&self) -> bool {
@@ -1337,7 +1338,7 @@ impl Config {
 
         // NOTE: The check for the empty directory is here because when running x.py the first time,
         // the submodule won't be checked out. Check it out now so we can build it.
-        if !GitInfo::new(false, &absolute_path).is_managed_git_subrepository()
+        if !self.git_info(false, &absolute_path).is_managed_git_subrepository()
             && !helpers::dir_is_empty(&absolute_path)
         {
             return;
@@ -1356,16 +1357,16 @@ impl Config {
         };
 
         // Determine commit checked out in submodule.
-        let checked_out_hash = output(submodule_git().args(["rev-parse", "HEAD"]).as_command_mut());
+        let checked_out_hash =
+            submodule_git().args(["rev-parse", "HEAD"]).run_capture_stdout(self).stdout();
         let checked_out_hash = checked_out_hash.trim_end();
         // Determine commit that the submodule *should* have.
-        let recorded = output(
-            helpers::git(Some(&self.src))
-                .run_always()
-                .args(["ls-tree", "HEAD"])
-                .arg(relative_path)
-                .as_command_mut(),
-        );
+        let recorded = helpers::git(Some(&self.src))
+            .run_always()
+            .args(["ls-tree", "HEAD"])
+            .arg(relative_path)
+            .run_capture_stdout(self)
+            .stdout();
 
         let actual_hash = recorded
             .split_whitespace()
@@ -1389,20 +1390,18 @@ impl Config {
         let update = |progress: bool| {
             // Git is buggy and will try to fetch submodules from the tracking branch for *this* repository,
             // even though that has no relation to the upstream for the submodule.
-            let current_branch = output_result(
-                helpers::git(Some(&self.src))
-                    .allow_failure()
-                    .run_always()
-                    .args(["symbolic-ref", "--short", "HEAD"])
-                    .as_command_mut(),
-            )
-            .map(|b| b.trim().to_owned());
+            let current_branch = helpers::git(Some(&self.src))
+                .allow_failure()
+                .run_always()
+                .args(["symbolic-ref", "--short", "HEAD"])
+                .run_capture(self);
 
             let mut git = helpers::git(Some(&self.src)).allow_failure();
             git.run_always();
-            if let Ok(branch) = current_branch {
+            if current_branch.is_success() {
                 // If there is a tag named after the current branch, git will try to disambiguate by prepending `heads/` to the branch name.
                 // This syntax isn't accepted by `branch.{branch}`. Strip it.
+                let branch = current_branch.stdout();
                 let branch = branch.strip_prefix("heads/").unwrap_or(&branch);
                 git.arg("-c").arg(format!("branch.{branch}.remote=origin"));
             }
@@ -1448,7 +1447,8 @@ impl Config {
             return;
         }
 
-        let stage0_output = output(Command::new(program_path).arg("--version"));
+        let stage0_output =
+            command(program_path).arg("--version").run_capture_stdout(self).stdout();
         let mut stage0_output = stage0_output.lines().next().unwrap().split(' ');
 
         let stage0_name = stage0_output.next().unwrap();
@@ -1754,4 +1754,18 @@ impl Config {
             _ => !self.is_system_llvm(target),
         }
     }
+
+    pub fn exec_ctx(&self) -> &ExecutionContext {
+        &self.exec_ctx
+    }
+
+    pub fn git_info(&self, omit_git_hash: bool, dir: &Path) -> GitInfo {
+        GitInfo::new(omit_git_hash, dir, self)
+    }
+}
+
+impl AsRef<ExecutionContext> for Config {
+    fn as_ref(&self) -> &ExecutionContext {
+        &self.exec_ctx
+    }
 }
diff --git a/src/bootstrap/src/core/config/flags.rs b/src/bootstrap/src/core/config/flags.rs
index 30617f58d43..bc4fa73a362 100644
--- a/src/bootstrap/src/core/config/flags.rs
+++ b/src/bootstrap/src/core/config/flags.rs
@@ -209,7 +209,8 @@ impl Flags {
             HelpVerboseOnly::try_parse_from(normalize_args(args))
         {
             println!("NOTE: updating submodules before printing available paths");
-            let config = Config::parse(Self::parse(&[String::from("build")]));
+            let flags = Self::parse(&[String::from("build")]);
+            let config = Config::parse(flags);
             let build = Build::new(config);
             let paths = Builder::get_help(&build, subcommand);
             if let Some(s) = paths {
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index ba00b405c61..f349b9a87ed 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -3,7 +3,6 @@ use std::ffi::OsString;
 use std::fs::{self, File};
 use std::io::{BufRead, BufReader, BufWriter, ErrorKind, Write};
 use std::path::{Path, PathBuf};
-use std::process::{Command, Stdio};
 use std::sync::OnceLock;
 
 use xz2::bufread::XzDecoder;
@@ -16,14 +15,7 @@ use crate::{Config, t};
 
 static SHOULD_FIX_BINS_AND_DYLIBS: OnceLock<bool> = OnceLock::new();
 
-/// `Config::try_run` wrapper for this module to avoid warnings on `try_run`, since we don't have access to a `builder` yet.
-fn try_run(config: &Config, cmd: &mut Command) -> Result<(), ()> {
-    #[expect(deprecated)]
-    config.try_run(cmd)
-}
-
-fn extract_curl_version(out: &[u8]) -> semver::Version {
-    let out = String::from_utf8_lossy(out);
+fn extract_curl_version(out: String) -> semver::Version {
     // The output should look like this: "curl <major>.<minor>.<patch> ..."
     out.lines()
         .next()
@@ -32,18 +24,21 @@ fn extract_curl_version(out: &[u8]) -> semver::Version {
         .unwrap_or(semver::Version::new(1, 0, 0))
 }
 
-fn curl_version() -> semver::Version {
-    let mut curl = Command::new("curl");
+fn curl_version(config: &Config) -> semver::Version {
+    let mut curl = command("curl");
     curl.arg("-V");
-    let Ok(out) = curl.output() else { return semver::Version::new(1, 0, 0) };
-    let out = out.stdout;
-    extract_curl_version(&out)
+    let curl = curl.run_capture_stdout(config);
+    if curl.is_failure() {
+        return semver::Version::new(1, 0, 0);
+    }
+    let output = curl.stdout();
+    extract_curl_version(output)
 }
 
 /// Generic helpers that are useful anywhere in bootstrap.
 impl Config {
     pub fn is_verbose(&self) -> bool {
-        self.verbose > 0
+        self.exec_ctx.is_verbose()
     }
 
     pub(crate) fn create<P: AsRef<Path>>(&self, path: P, s: &str) {
@@ -85,20 +80,14 @@ impl Config {
     /// on NixOS
     fn should_fix_bins_and_dylibs(&self) -> bool {
         let val = *SHOULD_FIX_BINS_AND_DYLIBS.get_or_init(|| {
-            match Command::new("uname").arg("-s").stderr(Stdio::inherit()).output() {
-                Err(_) => return false,
-                Ok(output) if !output.status.success() => return false,
-                Ok(output) => {
-                    let mut os_name = output.stdout;
-                    if os_name.last() == Some(&b'\n') {
-                        os_name.pop();
-                    }
-                    if os_name != b"Linux" {
-                        return false;
-                    }
-                }
+            let uname = command("uname").allow_failure().arg("-s").run_capture_stdout(self);
+            if uname.is_failure() {
+                return false;
+            }
+            let output = uname.stdout();
+            if !output.starts_with("Linux") {
+                return false;
             }
-
             // If the user has asked binaries to be patched for Nix, then
             // don't check for NixOS or `/lib`.
             // NOTE: this intentionally comes after the Linux check:
@@ -173,23 +162,18 @@ impl Config {
                 ];
             }
             ";
-            nix_build_succeeded = try_run(
-                self,
-                Command::new("nix-build").args([
-                    Path::new("-E"),
-                    Path::new(NIX_EXPR),
-                    Path::new("-o"),
-                    &nix_deps_dir,
-                ]),
-            )
-            .is_ok();
+            nix_build_succeeded = command("nix-build")
+                .allow_failure()
+                .args([Path::new("-E"), Path::new(NIX_EXPR), Path::new("-o"), &nix_deps_dir])
+                .run_capture_stdout(self)
+                .is_success();
             nix_deps_dir
         });
         if !nix_build_succeeded {
             return;
         }
 
-        let mut patchelf = Command::new(nix_deps_dir.join("bin/patchelf"));
+        let mut patchelf = command(nix_deps_dir.join("bin/patchelf"));
         patchelf.args(&[
             OsString::from("--add-rpath"),
             OsString::from(t!(fs::canonicalize(nix_deps_dir)).join("lib")),
@@ -200,8 +184,8 @@ impl Config {
             let dynamic_linker = t!(fs::read_to_string(dynamic_linker_path));
             patchelf.args(["--set-interpreter", dynamic_linker.trim_end()]);
         }
-
-        let _ = try_run(self, patchelf.arg(fname));
+        patchelf.arg(fname);
+        let _ = patchelf.allow_failure().run_capture_stdout(self);
     }
 
     fn download_file(&self, url: &str, dest_path: &Path, help_on_error: &str) {
@@ -267,7 +251,7 @@ impl Config {
             curl.arg("--progress-bar");
         }
         // --retry-all-errors was added in 7.71.0, don't use it if curl is old.
-        if curl_version() >= semver::Version::new(7, 71, 0) {
+        if curl_version(self) >= semver::Version::new(7, 71, 0) {
             curl.arg("--retry-all-errors");
         }
         curl.arg(url);
@@ -275,7 +259,7 @@ impl Config {
             if self.build.contains("windows-msvc") {
                 eprintln!("Fallback to PowerShell");
                 for _ in 0..3 {
-                    if try_run(self, Command::new("PowerShell.exe").args([
+                    let powershell = command("PowerShell.exe").allow_failure().args([
                         "/nologo",
                         "-Command",
                         "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;",
@@ -283,9 +267,12 @@ impl Config {
                             "(New-Object System.Net.WebClient).DownloadFile('{}', '{}')",
                             url, tempfile.to_str().expect("invalid UTF-8 not supported with powershell downloads"),
                         ),
-                    ])).is_err() {
+                    ]).run_capture_stdout(self);
+
+                    if powershell.is_failure() {
                         return;
                     }
+
                     eprintln!("\nspurious failure, trying again");
                 }
             }
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index 59ae303e21e..b7bbd294f0e 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -364,7 +364,7 @@ than building it.
             // Cygwin. The Cygwin build does not have generators for Visual
             // Studio, so detect that here and error.
             let out =
-                command("cmake").arg("--help").run_always().run_capture_stdout(build).stdout();
+                command("cmake").arg("--help").run_always().run_capture_stdout(&build).stdout();
             if !out.contains("Visual Studio") {
                 panic!(
                     "
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 7db57889009..88d5d026820 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -32,6 +32,7 @@ use cc::Tool;
 use termcolor::{ColorChoice, StandardStream, WriteColor};
 use utils::build_stamp::BuildStamp;
 use utils::channel::GitInfo;
+use utils::execution_context::ExecutionContext;
 
 use crate::core::builder;
 use crate::core::builder::Kind;
@@ -198,7 +199,6 @@ pub struct Build {
     crates: HashMap<String, Crate>,
     crate_paths: HashMap<PathBuf, String>,
     is_sudo: bool,
-    delayed_failures: RefCell<Vec<String>>,
     prerelease_version: Cell<Option<u32>>,
 
     #[cfg(feature = "build-metrics")]
@@ -469,7 +469,6 @@ impl Build {
             crates: HashMap::new(),
             crate_paths: HashMap::new(),
             is_sudo,
-            delayed_failures: RefCell::new(Vec::new()),
             prerelease_version: Cell::new(None),
 
             #[cfg(feature = "build-metrics")]
@@ -629,7 +628,7 @@ impl Build {
             return;
         }
 
-        if GitInfo::new(false, Path::new(submodule)).is_managed_git_subrepository() {
+        if config.git_info(false, Path::new(submodule)).is_managed_git_subrepository() {
             config.update_submodule(submodule);
         }
     }
@@ -684,7 +683,7 @@ impl Build {
                 #[cfg(feature = "tracing")]
                 let _sanity_check_span =
                     span!(tracing::Level::DEBUG, "(1) executing dry-run sanity-check").entered();
-                self.config.dry_run = DryRun::SelfCheck;
+                self.config.set_dry_run(DryRun::SelfCheck);
                 let builder = builder::Builder::new(self);
                 builder.execute_cli();
             }
@@ -694,7 +693,7 @@ impl Build {
                 #[cfg(feature = "tracing")]
                 let _actual_run_span =
                     span!(tracing::Level::DEBUG, "(2) executing actual run").entered();
-                self.config.dry_run = DryRun::Disabled;
+                self.config.set_dry_run(DryRun::Disabled);
                 let builder = builder::Builder::new(self);
                 builder.execute_cli();
             }
@@ -710,14 +709,7 @@ impl Build {
         debug!("checking for postponed test failures from `test  --no-fail-fast`");
 
         // Check for postponed failures from `test --no-fail-fast`.
-        let failures = self.delayed_failures.borrow();
-        if !failures.is_empty() {
-            eprintln!("\n{} command(s) did not execute successfully:\n", failures.len());
-            for failure in failures.iter() {
-                eprintln!("  - {failure}\n");
-            }
-            exit!(1);
-        }
+        self.config.exec_ctx().report_failures_and_exit();
 
         #[cfg(feature = "build-metrics")]
         self.metrics.persist(self);
@@ -953,133 +945,6 @@ impl Build {
         })
     }
 
-    /// Execute a command and return its output.
-    /// Note: Ideally, you should use one of the BootstrapCommand::run* functions to
-    /// execute commands. They internally call this method.
-    #[track_caller]
-    fn run(
-        &self,
-        command: &mut BootstrapCommand,
-        stdout: OutputMode,
-        stderr: OutputMode,
-    ) -> CommandOutput {
-        command.mark_as_executed();
-        if self.config.dry_run() && !command.run_always {
-            return CommandOutput::default();
-        }
-
-        #[cfg(feature = "tracing")]
-        let _run_span = trace_cmd!(command);
-
-        let created_at = command.get_created_location();
-        let executed_at = std::panic::Location::caller();
-
-        self.verbose(|| {
-            println!("running: {command:?} (created at {created_at}, executed at {executed_at})")
-        });
-
-        let cmd = command.as_command_mut();
-        cmd.stdout(stdout.stdio());
-        cmd.stderr(stderr.stdio());
-
-        let output = cmd.output();
-
-        use std::fmt::Write;
-
-        let mut message = String::new();
-        let output: CommandOutput = match output {
-            // Command has succeeded
-            Ok(output) if output.status.success() => {
-                CommandOutput::from_output(output, stdout, stderr)
-            }
-            // Command has started, but then it failed
-            Ok(output) => {
-                writeln!(
-                    message,
-                    r#"
-Command {command:?} did not execute successfully.
-Expected success, got {}
-Created at: {created_at}
-Executed at: {executed_at}"#,
-                    output.status,
-                )
-                .unwrap();
-
-                let output: CommandOutput = CommandOutput::from_output(output, stdout, stderr);
-
-                // If the output mode is OutputMode::Capture, we can now print the output.
-                // If it is OutputMode::Print, then the output has already been printed to
-                // stdout/stderr, and we thus don't have anything captured to print anyway.
-                if stdout.captures() {
-                    writeln!(message, "\nSTDOUT ----\n{}", output.stdout().trim()).unwrap();
-                }
-                if stderr.captures() {
-                    writeln!(message, "\nSTDERR ----\n{}", output.stderr().trim()).unwrap();
-                }
-                output
-            }
-            // The command did not even start
-            Err(e) => {
-                writeln!(
-                    message,
-                    "\n\nCommand {command:?} did not execute successfully.\
-            \nIt was not possible to execute the command: {e:?}"
-                )
-                .unwrap();
-                CommandOutput::did_not_start(stdout, stderr)
-            }
-        };
-
-        let fail = |message: &str, output: CommandOutput| -> ! {
-            if self.is_verbose() {
-                println!("{message}");
-            } else {
-                let (stdout, stderr) = (output.stdout_if_present(), output.stderr_if_present());
-                // If the command captures output, the user would not see any indication that
-                // it has failed. In this case, print a more verbose error, since to provide more
-                // context.
-                if stdout.is_some() || stderr.is_some() {
-                    if let Some(stdout) =
-                        output.stdout_if_present().take_if(|s| !s.trim().is_empty())
-                    {
-                        println!("STDOUT:\n{stdout}\n");
-                    }
-                    if let Some(stderr) =
-                        output.stderr_if_present().take_if(|s| !s.trim().is_empty())
-                    {
-                        println!("STDERR:\n{stderr}\n");
-                    }
-                    println!("Command {command:?} has failed. Rerun with -v to see more details.");
-                } else {
-                    println!("Command has failed. Rerun with -v to see more details.");
-                }
-            }
-            exit!(1);
-        };
-
-        if !output.is_success() {
-            match command.failure_behavior {
-                BehaviorOnFailure::DelayFail => {
-                    if self.fail_fast {
-                        fail(&message, output);
-                    }
-
-                    let mut failures = self.delayed_failures.borrow_mut();
-                    failures.push(message);
-                }
-                BehaviorOnFailure::Exit => {
-                    fail(&message, output);
-                }
-                BehaviorOnFailure::Ignore => {
-                    // If failures are allowed, either the error has been printed already
-                    // (OutputMode::Print) or the user used a capture output mode and wants to
-                    // handle the error output on their own.
-                }
-            }
-        }
-        output
-    }
-
     /// Check if verbosity is greater than the `level`
     pub fn is_verbose_than(&self, level: usize) -> bool {
         self.verbosity > level
@@ -1093,7 +958,7 @@ Executed at: {executed_at}"#,
     }
 
     fn info(&self, msg: &str) {
-        match self.config.dry_run {
+        match self.config.get_dry_run() {
             DryRun::SelfCheck => (),
             DryRun::Disabled | DryRun::UserSelected => {
                 println!("{msg}");
@@ -1216,7 +1081,7 @@ Executed at: {executed_at}"#,
 
     #[track_caller]
     fn group(&self, msg: &str) -> Option<gha::Group> {
-        match self.config.dry_run {
+        match self.config.get_dry_run() {
             DryRun::SelfCheck => None,
             DryRun::Disabled | DryRun::UserSelected => Some(gha::group(msg)),
         }
@@ -2045,6 +1910,16 @@ to download LLVM rather than building it.
         stream.reset().unwrap();
         result
     }
+
+    pub fn exec_ctx(&self) -> &ExecutionContext {
+        &self.config.exec_ctx
+    }
+}
+
+impl AsRef<ExecutionContext> for Build {
+    fn as_ref(&self) -> &ExecutionContext {
+        &self.config.exec_ctx
+    }
 }
 
 #[cfg(unix)]
diff --git a/src/bootstrap/src/utils/channel.rs b/src/bootstrap/src/utils/channel.rs
index 4a9ecc7a4f8..38f250af42f 100644
--- a/src/bootstrap/src/utils/channel.rs
+++ b/src/bootstrap/src/utils/channel.rs
@@ -8,6 +8,7 @@
 use std::fs;
 use std::path::Path;
 
+use super::execution_context::ExecutionContext;
 use super::helpers;
 use crate::Build;
 use crate::utils::helpers::{start_process, t};
@@ -34,7 +35,7 @@ pub struct Info {
 }
 
 impl GitInfo {
-    pub fn new(omit_git_hash: bool, dir: &Path) -> GitInfo {
+    pub fn new(omit_git_hash: bool, dir: &Path, exec_ctx: impl AsRef<ExecutionContext>) -> GitInfo {
         // See if this even begins to look like a git dir
         if !dir.join(".git").exists() {
             match read_commit_info_file(dir) {
@@ -43,10 +44,12 @@ impl GitInfo {
             }
         }
 
-        // Make sure git commands work
-        match helpers::git(Some(dir)).arg("rev-parse").as_command_mut().output() {
-            Ok(ref out) if out.status.success() => {}
-            _ => return GitInfo::Absent,
+        let mut git_command = helpers::git(Some(dir));
+        git_command.arg("rev-parse");
+        let output = git_command.allow_failure().run_capture(exec_ctx);
+
+        if output.is_failure() {
+            return GitInfo::Absent;
         }
 
         // If we're ignoring the git info, we don't actually need to collect it, just make sure this
diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs
index 64e46f10563..f297300e34a 100644
--- a/src/bootstrap/src/utils/exec.rs
+++ b/src/bootstrap/src/utils/exec.rs
@@ -11,7 +11,7 @@ use std::process::{Command, CommandArgs, CommandEnvs, ExitStatus, Output, Stdio}
 use build_helper::ci::CiEnv;
 use build_helper::drop_bomb::DropBomb;
 
-use crate::Build;
+use super::execution_context::ExecutionContext;
 
 /// What should be done when the command fails.
 #[derive(Debug, Copy, Clone)]
@@ -125,7 +125,6 @@ impl BootstrapCommand {
         Self { failure_behavior: BehaviorOnFailure::DelayFail, ..self }
     }
 
-    #[expect(dead_code)]
     pub fn fail_fast(self) -> Self {
         Self { failure_behavior: BehaviorOnFailure::Exit, ..self }
     }
@@ -143,20 +142,20 @@ impl BootstrapCommand {
     /// Run the command, while printing stdout and stderr.
     /// Returns true if the command has succeeded.
     #[track_caller]
-    pub fn run(&mut self, builder: &Build) -> bool {
-        builder.run(self, OutputMode::Print, OutputMode::Print).is_success()
+    pub fn run(&mut self, exec_ctx: impl AsRef<ExecutionContext>) -> bool {
+        exec_ctx.as_ref().run(self, OutputMode::Print, OutputMode::Print).is_success()
     }
 
     /// Run the command, while capturing and returning all its output.
     #[track_caller]
-    pub fn run_capture(&mut self, builder: &Build) -> CommandOutput {
-        builder.run(self, OutputMode::Capture, OutputMode::Capture)
+    pub fn run_capture(&mut self, exec_ctx: impl AsRef<ExecutionContext>) -> CommandOutput {
+        exec_ctx.as_ref().run(self, OutputMode::Capture, OutputMode::Capture)
     }
 
     /// Run the command, while capturing and returning stdout, and printing stderr.
     #[track_caller]
-    pub fn run_capture_stdout(&mut self, builder: &Build) -> CommandOutput {
-        builder.run(self, OutputMode::Capture, OutputMode::Print)
+    pub fn run_capture_stdout(&mut self, exec_ctx: impl AsRef<ExecutionContext>) -> CommandOutput {
+        exec_ctx.as_ref().run(self, OutputMode::Capture, OutputMode::Print)
     }
 
     /// Provides access to the stdlib Command inside.
@@ -280,7 +279,6 @@ impl CommandOutput {
         !self.is_success()
     }
 
-    #[expect(dead_code)]
     pub fn status(&self) -> Option<ExitStatus> {
         match self.status {
             CommandStatus::Finished(status) => Some(status),
diff --git a/src/bootstrap/src/utils/execution_context.rs b/src/bootstrap/src/utils/execution_context.rs
new file mode 100644
index 00000000000..d12c02c161d
--- /dev/null
+++ b/src/bootstrap/src/utils/execution_context.rs
@@ -0,0 +1,202 @@
+//! Shared execution context for running bootstrap commands.
+//!
+//! This module provides the [`ExecutionContext`] type, which holds global configuration
+//! relevant during the execution of commands in bootstrap. This includes dry-run
+//! mode, verbosity level, and behavior on failure.
+use std::sync::{Arc, Mutex};
+
+use crate::core::config::DryRun;
+use crate::{BehaviorOnFailure, BootstrapCommand, CommandOutput, OutputMode, exit};
+
+#[derive(Clone, Default)]
+pub struct ExecutionContext {
+    dry_run: DryRun,
+    verbose: u8,
+    pub fail_fast: bool,
+    delayed_failures: Arc<Mutex<Vec<String>>>,
+}
+
+impl ExecutionContext {
+    pub fn new() -> Self {
+        ExecutionContext::default()
+    }
+
+    pub fn dry_run(&self) -> bool {
+        match self.dry_run {
+            DryRun::Disabled => false,
+            DryRun::SelfCheck | DryRun::UserSelected => true,
+        }
+    }
+
+    pub fn get_dry_run(&self) -> &DryRun {
+        &self.dry_run
+    }
+
+    pub fn verbose(&self, f: impl Fn()) {
+        if self.is_verbose() {
+            f()
+        }
+    }
+
+    pub fn is_verbose(&self) -> bool {
+        self.verbose > 0
+    }
+
+    pub fn fail_fast(&self) -> bool {
+        self.fail_fast
+    }
+
+    pub fn set_dry_run(&mut self, value: DryRun) {
+        self.dry_run = value;
+    }
+
+    pub fn set_verbose(&mut self, value: u8) {
+        self.verbose = value;
+    }
+
+    pub fn set_fail_fast(&mut self, value: bool) {
+        self.fail_fast = value;
+    }
+
+    pub fn add_to_delay_failure(&self, message: String) {
+        self.delayed_failures.lock().unwrap().push(message);
+    }
+
+    pub fn report_failures_and_exit(&self) {
+        let failures = self.delayed_failures.lock().unwrap();
+        if failures.is_empty() {
+            return;
+        }
+        eprintln!("\n{} command(s) did not execute successfully:\n", failures.len());
+        for failure in &*failures {
+            eprintln!("  - {failure}");
+        }
+        exit!(1);
+    }
+
+    /// Execute a command and return its output.
+    /// Note: Ideally, you should use one of the BootstrapCommand::run* functions to
+    /// execute commands. They internally call this method.
+    #[track_caller]
+    pub fn run(
+        &self,
+        command: &mut BootstrapCommand,
+        stdout: OutputMode,
+        stderr: OutputMode,
+    ) -> CommandOutput {
+        command.mark_as_executed();
+        if self.dry_run() && !command.run_always {
+            return CommandOutput::default();
+        }
+
+        #[cfg(feature = "tracing")]
+        let _run_span = trace_cmd!(command);
+
+        let created_at = command.get_created_location();
+        let executed_at = std::panic::Location::caller();
+
+        self.verbose(|| {
+            println!("running: {command:?} (created at {created_at}, executed at {executed_at})")
+        });
+
+        let cmd = command.as_command_mut();
+        cmd.stdout(stdout.stdio());
+        cmd.stderr(stderr.stdio());
+
+        let output = cmd.output();
+
+        use std::fmt::Write;
+
+        let mut message = String::new();
+        let output: CommandOutput = match output {
+            // Command has succeeded
+            Ok(output) if output.status.success() => {
+                CommandOutput::from_output(output, stdout, stderr)
+            }
+            // Command has started, but then it failed
+            Ok(output) => {
+                writeln!(
+                    message,
+                    r#"
+Command {command:?} did not execute successfully.
+Expected success, got {}
+Created at: {created_at}
+Executed at: {executed_at}"#,
+                    output.status,
+                )
+                .unwrap();
+
+                let output: CommandOutput = CommandOutput::from_output(output, stdout, stderr);
+
+                // If the output mode is OutputMode::Capture, we can now print the output.
+                // If it is OutputMode::Print, then the output has already been printed to
+                // stdout/stderr, and we thus don't have anything captured to print anyway.
+                if stdout.captures() {
+                    writeln!(message, "\nSTDOUT ----\n{}", output.stdout().trim()).unwrap();
+                }
+                if stderr.captures() {
+                    writeln!(message, "\nSTDERR ----\n{}", output.stderr().trim()).unwrap();
+                }
+                output
+            }
+            // The command did not even start
+            Err(e) => {
+                writeln!(
+                    message,
+                    "\n\nCommand {command:?} did not execute successfully.\
+            \nIt was not possible to execute the command: {e:?}"
+                )
+                .unwrap();
+                CommandOutput::did_not_start(stdout, stderr)
+            }
+        };
+
+        let fail = |message: &str, output: CommandOutput| -> ! {
+            if self.is_verbose() {
+                println!("{message}");
+            } else {
+                let (stdout, stderr) = (output.stdout_if_present(), output.stderr_if_present());
+                // If the command captures output, the user would not see any indication that
+                // it has failed. In this case, print a more verbose error, since to provide more
+                // context.
+                if stdout.is_some() || stderr.is_some() {
+                    if let Some(stdout) =
+                        output.stdout_if_present().take_if(|s| !s.trim().is_empty())
+                    {
+                        println!("STDOUT:\n{stdout}\n");
+                    }
+                    if let Some(stderr) =
+                        output.stderr_if_present().take_if(|s| !s.trim().is_empty())
+                    {
+                        println!("STDERR:\n{stderr}\n");
+                    }
+                    println!("Command {command:?} has failed. Rerun with -v to see more details.");
+                } else {
+                    println!("Command has failed. Rerun with -v to see more details.");
+                }
+            }
+            exit!(1);
+        };
+
+        if !output.is_success() {
+            match command.failure_behavior {
+                BehaviorOnFailure::DelayFail => {
+                    if self.fail_fast {
+                        fail(&message, output);
+                    }
+
+                    self.add_to_delay_failure(message);
+                }
+                BehaviorOnFailure::Exit => {
+                    fail(&message, output);
+                }
+                BehaviorOnFailure::Ignore => {
+                    // If failures are allowed, either the error has been printed already
+                    // (OutputMode::Print) or the user used a capture output mode and wants to
+                    // handle the error output on their own.
+                }
+            }
+        }
+        output
+    }
+}
diff --git a/src/bootstrap/src/utils/mod.rs b/src/bootstrap/src/utils/mod.rs
index 169fcec303e..5a0b90801e7 100644
--- a/src/bootstrap/src/utils/mod.rs
+++ b/src/bootstrap/src/utils/mod.rs
@@ -8,6 +8,7 @@ pub(crate) mod cc_detect;
 pub(crate) mod change_tracker;
 pub(crate) mod channel;
 pub(crate) mod exec;
+pub(crate) mod execution_context;
 pub(crate) mod helpers;
 pub(crate) mod job;
 pub(crate) mod render_tests;
diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs
index 418f3ff975d..77e645a9e3c 100644
--- a/src/bootstrap/src/utils/render_tests.rs
+++ b/src/bootstrap/src/utils/render_tests.rs
@@ -43,8 +43,7 @@ pub(crate) fn try_run_tests(
         if builder.fail_fast {
             crate::exit!(1);
         } else {
-            let mut failures = builder.delayed_failures.borrow_mut();
-            failures.push(format!("{cmd:?}"));
+            builder.config.exec_ctx().add_to_delay_failure(format!("{cmd:?}"));
             false
         }
     } else {
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index e2e2ad9ac3b..559e4867bbb 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -33,7 +33,7 @@ All tier 1 targets with host tools support the full standard library.
 target | notes
 -------|-------
 [`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+)
-`aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1, glibc 2.17+)
+`aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1+, glibc 2.17+)
 `i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment]
 `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+, Pentium 4) [^x86_32-floats-return-ABI]
 [`x86_64-apple-darwin`](platform-support/apple-darwin.md) | 64-bit macOS (10.12+, Sierra+)
@@ -91,20 +91,20 @@ target | notes
 `aarch64-pc-windows-msvc` | ARM64 Windows MSVC
 `aarch64-unknown-linux-musl` | ARM64 Linux with musl 1.2.3
 [`aarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ARM64 OpenHarmony
-`arm-unknown-linux-gnueabi` | Armv6 Linux (kernel 3.2, glibc 2.17)
-`arm-unknown-linux-gnueabihf` | Armv6 Linux, hardfloat (kernel 3.2, glibc 2.17)
-`armv7-unknown-linux-gnueabihf` | Armv7-A Linux, hardfloat (kernel 3.2, glibc 2.17)
+`arm-unknown-linux-gnueabi` | Armv6 Linux (kernel 3.2+, glibc 2.17)
+`arm-unknown-linux-gnueabihf` | Armv6 Linux, hardfloat (kernel 3.2+, glibc 2.17)
+`armv7-unknown-linux-gnueabihf` | Armv7-A Linux, hardfloat (kernel 3.2+, glibc 2.17)
 [`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | Armv7-A OpenHarmony
-[`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36)
-[`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, musl 1.2.5)
+[`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19+, glibc 2.36)
+[`loongarch64-unknown-linux-musl`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19+, musl 1.2.5)
 [`i686-pc-windows-gnu`](platform-support/windows-gnu.md) | 32-bit MinGW (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] [^win32-msvc-alignment]
-`powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2, glibc 2.17)
-`powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2, glibc 2.17)
-[`powerpc64le-unknown-linux-gnu`](platform-support/powerpc64le-unknown-linux-gnu.md) | PPC64LE Linux (kernel 3.10, glibc 2.17)
-[`powerpc64le-unknown-linux-musl`](platform-support/powerpc64le-unknown-linux-musl.md) | PPC64LE Linux (kernel 4.19, musl 1.2.3)
-[`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20, glibc 2.29)
-[`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20, musl 1.2.3)
-[`s390x-unknown-linux-gnu`](platform-support/s390x-unknown-linux-gnu.md) | S390x Linux (kernel 3.2, glibc 2.17)
+`powerpc-unknown-linux-gnu` | PowerPC Linux (kernel 3.2+, glibc 2.17)
+`powerpc64-unknown-linux-gnu` | PPC64 Linux (kernel 3.2+, glibc 2.17)
+[`powerpc64le-unknown-linux-gnu`](platform-support/powerpc64le-unknown-linux-gnu.md) | PPC64LE Linux (kernel 3.10+, glibc 2.17)
+[`powerpc64le-unknown-linux-musl`](platform-support/powerpc64le-unknown-linux-musl.md) | PPC64LE Linux (kernel 4.19+, musl 1.2.3)
+[`riscv64gc-unknown-linux-gnu`](platform-support/riscv64gc-unknown-linux-gnu.md) | RISC-V Linux (kernel 4.20+, glibc 2.29)
+[`riscv64gc-unknown-linux-musl`](platform-support/riscv64gc-unknown-linux-musl.md) | RISC-V Linux (kernel 4.20+, musl 1.2.3)
+[`s390x-unknown-linux-gnu`](platform-support/s390x-unknown-linux-gnu.md) | S390x Linux (kernel 3.2+, glibc 2.17)
 [`x86_64-unknown-freebsd`](platform-support/freebsd.md) | 64-bit x86 FreeBSD
 [`x86_64-unknown-illumos`](platform-support/illumos.md) | illumos
 `x86_64-unknown-linux-musl` | 64-bit Linux with musl 1.2.3
@@ -158,16 +158,16 @@ target | std | notes
 [`arm64ec-pc-windows-msvc`](platform-support/arm64ec-pc-windows-msvc.md) | ✓ | Arm64EC Windows MSVC
 [`armebv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian
 [`armebv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, Big Endian, hardfloat
-[`armv5te-unknown-linux-gnueabi`](platform-support/armv5te-unknown-linux-gnueabi.md) | ✓ | Armv5TE Linux (kernel 4.4, glibc 2.23)
+[`armv5te-unknown-linux-gnueabi`](platform-support/armv5te-unknown-linux-gnueabi.md) | ✓ | Armv5TE Linux (kernel 4.4+, glibc 2.23)
 `armv5te-unknown-linux-musleabi` | ✓ | Armv5TE Linux with musl 1.2.3
 [`armv7-linux-androideabi`](platform-support/android.md) | ✓ | Armv7-A Android
-`armv7-unknown-linux-gnueabi` | ✓ | Armv7-A Linux (kernel 4.15, glibc 2.27)
+`armv7-unknown-linux-gnueabi` | ✓ | Armv7-A Linux (kernel 4.15+, glibc 2.27)
 `armv7-unknown-linux-musleabi` | ✓ | Armv7-A Linux with musl 1.2.3
 `armv7-unknown-linux-musleabihf` | ✓ | Armv7-A Linux with musl 1.2.3, hardfloat
 [`armv7a-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare Armv7-A
 [`armv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R
 [`armv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, hardfloat
-`i586-unknown-linux-gnu` | ✓ | 32-bit Linux (kernel 3.2, glibc 2.17, original Pentium) [^x86_32-floats-x87]
+`i586-unknown-linux-gnu` | ✓ | 32-bit Linux (kernel 3.2+, glibc 2.17, original Pentium) [^x86_32-floats-x87]
 `i586-unknown-linux-musl` | ✓ | 32-bit Linux (musl 1.2.3, original Pentium) [^x86_32-floats-x87]
 [`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android ([Pentium 4 plus various extensions](https://developer.android.com/ndk/guides/abis.html#x86)) [^x86_32-floats-return-ABI]
 [`i686-pc-windows-gnullvm`](platform-support/windows-gnullvm.md) | ✓ | 32-bit x86 MinGW (Windows 10+, Pentium 4), LLVM ABI [^x86_32-floats-return-ABI]
@@ -184,13 +184,13 @@ target | std | notes
 [`riscv32imc-unknown-none-elf`](platform-support/riscv32-unknown-none-elf.md) | * | Bare RISC-V (RV32IMC ISA)
 `riscv64gc-unknown-none-elf` | * | Bare RISC-V (RV64IMAFDC ISA)
 `riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA)
-`sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4, glibc 2.23)
+`sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4+, glibc 2.23)
 [`thumbv6m-none-eabi`](platform-support/thumbv6m-none-eabi.md) | * | Bare Armv6-M
 [`thumbv7em-none-eabi`](platform-support/thumbv7em-none-eabi.md) | * | Bare Armv7E-M
 [`thumbv7em-none-eabihf`](platform-support/thumbv7em-none-eabi.md) | * | Bare Armv7E-M, hardfloat
 [`thumbv7m-none-eabi`](platform-support/thumbv7m-none-eabi.md) | * | Bare Armv7-M
 [`thumbv7neon-linux-androideabi`](platform-support/android.md) | ✓ | Thumb2-mode Armv7-A Android with NEON
-`thumbv7neon-unknown-linux-gnueabihf` | ✓ | Thumb2-mode Armv7-A Linux with NEON (kernel 4.4, glibc 2.23)
+`thumbv7neon-unknown-linux-gnueabihf` | ✓ | Thumb2-mode Armv7-A Linux with NEON (kernel 4.4+, glibc 2.23)
 [`thumbv8m.base-none-eabi`](platform-support/thumbv8m.base-none-eabi.md) | * | Bare Armv8-M Baseline
 [`thumbv8m.main-none-eabi`](platform-support/thumbv8m.main-none-eabi.md) | * | Bare Armv8-M Mainline
 [`thumbv8m.main-none-eabihf`](platform-support/thumbv8m.main-none-eabi.md) | * | Bare Armv8-M Mainline, hardfloat
@@ -206,7 +206,7 @@ target | std | notes
 [`x86_64-linux-android`](platform-support/android.md) | ✓ | 64-bit x86 Android
 [`x86_64-pc-windows-gnullvm`](platform-support/windows-gnullvm.md) | ✓ | 64-bit x86 MinGW (Windows 10+), LLVM ABI
 [`x86_64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | 64-bit x86 Fuchsia
-`x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15, glibc 2.27)
+`x86_64-unknown-linux-gnux32` | ✓ | 64-bit Linux (x32 ABI) (kernel 4.15+, glibc 2.27)
 [`x86_64-unknown-none`](platform-support/x86_64-unknown-none.md) | * | Freestanding/bare-metal x86_64, softfloat
 [`x86_64-unknown-redox`](platform-support/redox.md) | ✓ | Redox OS
 [`x86_64-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 64-bit UEFI
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index 138ac3c97f7..a91ea55bcae 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -11,7 +11,7 @@ use tracing::{debug, instrument};
 
 use crate::clean::{
     self, Lifetime, clean_generic_param_def, clean_middle_ty, clean_predicate,
-    clean_trait_ref_with_constraints, clean_ty_generics, simplify,
+    clean_trait_ref_with_constraints, clean_ty_generics_inner, simplify,
 };
 use crate::core::DocContext;
 
@@ -101,7 +101,7 @@ fn synthesize_auto_trait_impl<'tcx>(
             // Instead, we generate `impl !Send for Foo<T>`, which better
             // expresses the fact that `Foo<T>` never implements `Send`,
             // regardless of the choice of `T`.
-            let mut generics = clean_ty_generics(
+            let mut generics = clean_ty_generics_inner(
                 cx,
                 tcx.generics_of(item_def_id),
                 ty::GenericPredicates::default(),
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 89245fee515..c889f52b789 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -90,11 +90,7 @@ pub(crate) fn synthesize_blanket_impls(
                     stability: None,
                     kind: clean::ImplItem(Box::new(clean::Impl {
                         safety: hir::Safety::Safe,
-                        generics: clean_ty_generics(
-                            cx,
-                            tcx.generics_of(impl_def_id),
-                            tcx.explicit_predicates_of(impl_def_id),
-                        ),
+                        generics: clean_ty_generics(cx, impl_def_id),
                         // FIXME(eddyb) compute both `trait_` and `for_` from
                         // the post-inference `trait_ref`, as it's more accurate.
                         trait_: Some(clean_trait_ref_with_constraints(
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 55a116a018a..9b5491310b4 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -264,16 +264,13 @@ pub(crate) fn build_trait(cx: &mut DocContext<'_>, did: DefId) -> clean::Trait {
         .map(|item| clean_middle_assoc_item(item, cx))
         .collect();
 
-    let predicates = cx.tcx.predicates_of(did);
-    let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
-    let generics = filter_non_trait_generics(did, generics);
+    let generics = clean_ty_generics(cx, did);
     let (generics, supertrait_bounds) = separate_self_bounds(generics);
     clean::Trait { def_id: did, generics, items: trait_items, bounds: supertrait_bounds }
 }
 
 fn build_trait_alias(cx: &mut DocContext<'_>, did: DefId) -> clean::TraitAlias {
-    let predicates = cx.tcx.predicates_of(did);
-    let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
+    let generics = clean_ty_generics(cx, did);
     let (generics, bounds) = separate_self_bounds(generics);
     clean::TraitAlias { generics, bounds }
 }
@@ -281,8 +278,7 @@ fn build_trait_alias(cx: &mut DocContext<'_>, did: DefId) -> clean::TraitAlias {
 pub(super) fn build_function(cx: &mut DocContext<'_>, def_id: DefId) -> Box<clean::Function> {
     let sig = cx.tcx.fn_sig(def_id).instantiate_identity();
     // The generics need to be cleaned before the signature.
-    let mut generics =
-        clean_ty_generics(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id));
+    let mut generics = clean_ty_generics(cx, def_id);
     let bound_vars = clean_bound_vars(sig.bound_vars());
 
     // At the time of writing early & late-bound params are stored separately in rustc,
@@ -311,30 +307,26 @@ pub(super) fn build_function(cx: &mut DocContext<'_>, def_id: DefId) -> Box<clea
 }
 
 fn build_enum(cx: &mut DocContext<'_>, did: DefId) -> clean::Enum {
-    let predicates = cx.tcx.explicit_predicates_of(did);
-
     clean::Enum {
-        generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates),
+        generics: clean_ty_generics(cx, did),
         variants: cx.tcx.adt_def(did).variants().iter().map(|v| clean_variant_def(v, cx)).collect(),
     }
 }
 
 fn build_struct(cx: &mut DocContext<'_>, did: DefId) -> clean::Struct {
-    let predicates = cx.tcx.explicit_predicates_of(did);
     let variant = cx.tcx.adt_def(did).non_enum_variant();
 
     clean::Struct {
         ctor_kind: variant.ctor_kind(),
-        generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates),
+        generics: clean_ty_generics(cx, did),
         fields: variant.fields.iter().map(|x| clean_middle_field(x, cx)).collect(),
     }
 }
 
 fn build_union(cx: &mut DocContext<'_>, did: DefId) -> clean::Union {
-    let predicates = cx.tcx.explicit_predicates_of(did);
     let variant = cx.tcx.adt_def(did).non_enum_variant();
 
-    let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
+    let generics = clean_ty_generics(cx, did);
     let fields = variant.fields.iter().map(|x| clean_middle_field(x, cx)).collect();
     clean::Union { generics, fields }
 }
@@ -344,14 +336,13 @@ fn build_type_alias(
     did: DefId,
     ret: &mut Vec<Item>,
 ) -> Box<clean::TypeAlias> {
-    let predicates = cx.tcx.explicit_predicates_of(did);
     let ty = cx.tcx.type_of(did).instantiate_identity();
     let type_ = clean_middle_ty(ty::Binder::dummy(ty), cx, Some(did), None);
     let inner_type = clean_ty_alias_inner_type(ty, cx, ret);
 
     Box::new(clean::TypeAlias {
         type_,
-        generics: clean_ty_generics(cx, cx.tcx.generics_of(did), predicates),
+        generics: clean_ty_generics(cx, did),
         inner_type,
         item_type: None,
     })
@@ -483,7 +474,6 @@ pub(crate) fn build_impl(
     }
 
     let document_hidden = cx.render_options.document_hidden;
-    let predicates = tcx.explicit_predicates_of(did);
     let (trait_items, generics) = match impl_item {
         Some(impl_) => (
             impl_
@@ -549,9 +539,7 @@ pub(crate) fn build_impl(
                 })
                 .map(|item| clean_middle_assoc_item(item, cx))
                 .collect::<Vec<_>>(),
-            clean::enter_impl_trait(cx, |cx| {
-                clean_ty_generics(cx, tcx.generics_of(did), predicates)
-            }),
+            clean::enter_impl_trait(cx, |cx| clean_ty_generics(cx, did)),
         ),
     };
     let polarity = tcx.impl_polarity(did);
@@ -713,8 +701,7 @@ pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String {
 }
 
 fn build_const_item(cx: &mut DocContext<'_>, def_id: DefId) -> clean::Constant {
-    let mut generics =
-        clean_ty_generics(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id));
+    let mut generics = clean_ty_generics(cx, def_id);
     clean::simplify::move_bounds_to_generic_parameters(&mut generics);
     let ty = clean_middle_ty(
         ty::Binder::dummy(cx.tcx.type_of(def_id).instantiate_identity()),
@@ -761,44 +748,6 @@ fn build_macro(
     }
 }
 
-/// A trait's generics clause actually contains all of the predicates for all of
-/// its associated types as well. We specifically move these clauses to the
-/// associated types instead when displaying, so when we're generating the
-/// generics for the trait itself we need to be sure to remove them.
-/// We also need to remove the implied "recursive" Self: Trait bound.
-///
-/// The inverse of this filtering logic can be found in the `Clean`
-/// implementation for `AssociatedType`
-fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean::Generics {
-    for pred in &mut g.where_predicates {
-        if let clean::WherePredicate::BoundPredicate { ty: clean::SelfTy, ref mut bounds, .. } =
-            *pred
-        {
-            bounds.retain(|bound| match bound {
-                clean::GenericBound::TraitBound(clean::PolyTrait { trait_, .. }, _) => {
-                    trait_.def_id() != trait_did
-                }
-                _ => true,
-            });
-        }
-    }
-
-    g.where_predicates.retain(|pred| match pred {
-        clean::WherePredicate::BoundPredicate {
-            ty:
-                clean::QPath(box clean::QPathData {
-                    self_type: clean::Generic(_),
-                    trait_: Some(trait_),
-                    ..
-                }),
-            bounds,
-            ..
-        } => !bounds.is_empty() && trait_.def_id() != trait_did,
-        _ => true,
-    });
-    g
-}
-
 fn separate_self_bounds(mut g: clean::Generics) -> (clean::Generics, Vec<clean::GenericBound>) {
     let mut ty_bounds = Vec::new();
     g.where_predicates.retain(|pred| match *pred {
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 7658e7ad35f..db4bcdaeb6c 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -793,7 +793,11 @@ pub(crate) fn clean_generics<'tcx>(
     }
 }
 
-fn clean_ty_generics<'tcx>(
+fn clean_ty_generics<'tcx>(cx: &mut DocContext<'tcx>, def_id: DefId) -> Generics {
+    clean_ty_generics_inner(cx, cx.tcx.generics_of(def_id), cx.tcx.explicit_predicates_of(def_id))
+}
+
+fn clean_ty_generics_inner<'tcx>(
     cx: &mut DocContext<'tcx>,
     gens: &ty::Generics,
     preds: ty::GenericPredicates<'tcx>,
@@ -1297,11 +1301,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
                 None,
             );
 
-            let mut generics = clean_ty_generics(
-                cx,
-                tcx.generics_of(assoc_item.def_id),
-                tcx.explicit_predicates_of(assoc_item.def_id),
-            );
+            let mut generics = clean_ty_generics(cx, assoc_item.def_id);
             simplify::move_bounds_to_generic_parameters(&mut generics);
 
             match assoc_item.container {
@@ -1389,7 +1389,7 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
                 let bounds = tcx.explicit_item_bounds(assoc_item.def_id).iter_identity_copied();
                 predicates = tcx.arena.alloc_from_iter(bounds.chain(predicates.iter().copied()));
             }
-            let mut generics = clean_ty_generics(
+            let mut generics = clean_ty_generics_inner(
                 cx,
                 tcx.generics_of(assoc_item.def_id),
                 ty::GenericPredicates { parent: None, predicates },
diff --git a/tests/crashes/139825.rs b/tests/crashes/139825.rs
deleted file mode 100644
index 8c5b6b80f0b..00000000000
--- a/tests/crashes/139825.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-//@ known-bug: #139825
-//@compile-flags: --check-cfg=cfg(docsrs,test) --crate-type lib
-struct a
-where
-    for<#[cfg(b)] c> u8:;
diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr
index ea645780b0d..22dca00e3b2 100644
--- a/tests/ui/abi/unsupported.aarch64.stderr
+++ b/tests/ui/abi/unsupported.aarch64.stderr
@@ -114,7 +114,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
    = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
 
 error[E0570]: `"stdcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:117:1
+  --> $DIR/unsupported.rs:119:1
    |
 LL | extern "stdcall" {}
    | ^^^^^^^^^^^^^^^^^^^
@@ -122,24 +122,26 @@ LL | extern "stdcall" {}
    = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
 error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:121:1
+  --> $DIR/unsupported.rs:123:1
    |
 LL | extern "stdcall-unwind" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"`
 
-warning: the calling convention "cdecl" is not supported on this target
-  --> $DIR/unsupported.rs:129:17
+warning: use of calling convention not supported on this target
+  --> $DIR/unsupported.rs:131:17
    |
 LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
    |                 ^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C"` instead
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:134:1
+  --> $DIR/unsupported.rs:136:1
    |
 LL | extern "cdecl" {}
    | ^^^^^^^^^^^^^^^^^
@@ -147,10 +149,9 @@ LL | extern "cdecl" {}
    = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: use `extern "C"` instead
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:137:1
+  --> $DIR/unsupported.rs:139:1
    |
 LL | extern "cdecl-unwind" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -160,7 +161,7 @@ LL | extern "cdecl-unwind" {}
    = help: use `extern "C-unwind"` instead
 
 warning: the calling convention "vectorcall" is not supported on this target
-  --> $DIR/unsupported.rs:143:22
+  --> $DIR/unsupported.rs:145:22
    |
 LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -169,13 +170,13 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
    = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
 
 error[E0570]: `"vectorcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:148:1
+  --> $DIR/unsupported.rs:150:1
    |
 LL | extern "vectorcall" {}
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:151:21
+  --> $DIR/unsupported.rs:153:21
    |
 LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -184,7 +185,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
    = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
 
 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:159:22
+  --> $DIR/unsupported.rs:161:22
    |
 LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -193,7 +194,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
    = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
 
 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:164:1
+  --> $DIR/unsupported.rs:166:1
    |
 LL | extern "C-cmse-nonsecure-entry" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -255,7 +256,7 @@ LL | extern "stdcall" fn stdcall() {}
    = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:126:1
+  --> $DIR/unsupported.rs:128:1
    |
 LL | extern "cdecl" fn cdecl() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -265,13 +266,13 @@ LL | extern "cdecl" fn cdecl() {}
    = help: use `extern "C"` instead
 
 error[E0570]: `"vectorcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:141:1
+  --> $DIR/unsupported.rs:143:1
    |
 LL | extern "vectorcall" fn vectorcall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:157:1
+  --> $DIR/unsupported.rs:159:1
    |
 LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -368,19 +369,20 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
    = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
 
 Future breakage diagnostic:
-warning: the calling convention "cdecl" is not supported on this target
-  --> $DIR/unsupported.rs:129:17
+warning: use of calling convention not supported on this target
+  --> $DIR/unsupported.rs:131:17
    |
 LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
    |                 ^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C"` instead
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
 Future breakage diagnostic:
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:134:1
+  --> $DIR/unsupported.rs:136:1
    |
 LL | extern "cdecl" {}
    | ^^^^^^^^^^^^^^^^^
@@ -392,7 +394,7 @@ LL | extern "cdecl" {}
 
 Future breakage diagnostic:
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:137:1
+  --> $DIR/unsupported.rs:139:1
    |
 LL | extern "cdecl-unwind" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -404,7 +406,7 @@ LL | extern "cdecl-unwind" {}
 
 Future breakage diagnostic:
 warning: the calling convention "vectorcall" is not supported on this target
-  --> $DIR/unsupported.rs:143:22
+  --> $DIR/unsupported.rs:145:22
    |
 LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -415,7 +417,7 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
 
 Future breakage diagnostic:
 warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:151:21
+  --> $DIR/unsupported.rs:153:21
    |
 LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -426,7 +428,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
 
 Future breakage diagnostic:
 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:159:22
+  --> $DIR/unsupported.rs:161:22
    |
 LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -437,7 +439,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
 
 Future breakage diagnostic:
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:126:1
+  --> $DIR/unsupported.rs:128:1
    |
 LL | extern "cdecl" fn cdecl() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr
index 2c82e2951e2..0ac6d888f8d 100644
--- a/tests/ui/abi/unsupported.arm.stderr
+++ b/tests/ui/abi/unsupported.arm.stderr
@@ -99,7 +99,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
    = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
 
 error[E0570]: `"stdcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:117:1
+  --> $DIR/unsupported.rs:119:1
    |
 LL | extern "stdcall" {}
    | ^^^^^^^^^^^^^^^^^^^
@@ -107,24 +107,26 @@ LL | extern "stdcall" {}
    = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
 error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:121:1
+  --> $DIR/unsupported.rs:123:1
    |
 LL | extern "stdcall-unwind" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"`
 
-warning: the calling convention "cdecl" is not supported on this target
-  --> $DIR/unsupported.rs:129:17
+warning: use of calling convention not supported on this target
+  --> $DIR/unsupported.rs:131:17
    |
 LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
    |                 ^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C"` instead
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:134:1
+  --> $DIR/unsupported.rs:136:1
    |
 LL | extern "cdecl" {}
    | ^^^^^^^^^^^^^^^^^
@@ -132,10 +134,9 @@ LL | extern "cdecl" {}
    = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: use `extern "C"` instead
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:137:1
+  --> $DIR/unsupported.rs:139:1
    |
 LL | extern "cdecl-unwind" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -145,7 +146,7 @@ LL | extern "cdecl-unwind" {}
    = help: use `extern "C-unwind"` instead
 
 warning: the calling convention "vectorcall" is not supported on this target
-  --> $DIR/unsupported.rs:143:22
+  --> $DIR/unsupported.rs:145:22
    |
 LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -154,13 +155,13 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
    = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
 
 error[E0570]: `"vectorcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:148:1
+  --> $DIR/unsupported.rs:150:1
    |
 LL | extern "vectorcall" {}
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:151:21
+  --> $DIR/unsupported.rs:153:21
    |
 LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -169,7 +170,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
    = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
 
 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:159:22
+  --> $DIR/unsupported.rs:161:22
    |
 LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -178,7 +179,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
    = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
 
 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:164:1
+  --> $DIR/unsupported.rs:166:1
    |
 LL | extern "C-cmse-nonsecure-entry" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -234,7 +235,7 @@ LL | extern "stdcall" fn stdcall() {}
    = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:126:1
+  --> $DIR/unsupported.rs:128:1
    |
 LL | extern "cdecl" fn cdecl() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -244,13 +245,13 @@ LL | extern "cdecl" fn cdecl() {}
    = help: use `extern "C"` instead
 
 error[E0570]: `"vectorcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:141:1
+  --> $DIR/unsupported.rs:143:1
    |
 LL | extern "vectorcall" fn vectorcall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:157:1
+  --> $DIR/unsupported.rs:159:1
    |
 LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -336,19 +337,20 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
    = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
 
 Future breakage diagnostic:
-warning: the calling convention "cdecl" is not supported on this target
-  --> $DIR/unsupported.rs:129:17
+warning: use of calling convention not supported on this target
+  --> $DIR/unsupported.rs:131:17
    |
 LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
    |                 ^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C"` instead
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
 Future breakage diagnostic:
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:134:1
+  --> $DIR/unsupported.rs:136:1
    |
 LL | extern "cdecl" {}
    | ^^^^^^^^^^^^^^^^^
@@ -360,7 +362,7 @@ LL | extern "cdecl" {}
 
 Future breakage diagnostic:
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:137:1
+  --> $DIR/unsupported.rs:139:1
    |
 LL | extern "cdecl-unwind" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -372,7 +374,7 @@ LL | extern "cdecl-unwind" {}
 
 Future breakage diagnostic:
 warning: the calling convention "vectorcall" is not supported on this target
-  --> $DIR/unsupported.rs:143:22
+  --> $DIR/unsupported.rs:145:22
    |
 LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -383,7 +385,7 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
 
 Future breakage diagnostic:
 warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:151:21
+  --> $DIR/unsupported.rs:153:21
    |
 LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -394,7 +396,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
 
 Future breakage diagnostic:
 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:159:22
+  --> $DIR/unsupported.rs:161:22
    |
 LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -405,7 +407,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
 
 Future breakage diagnostic:
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:126:1
+  --> $DIR/unsupported.rs:128:1
    |
 LL | extern "cdecl" fn cdecl() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/abi/unsupported.i686.stderr b/tests/ui/abi/unsupported.i686.stderr
index d552f9a132c..4d903b435d8 100644
--- a/tests/ui/abi/unsupported.i686.stderr
+++ b/tests/ui/abi/unsupported.i686.stderr
@@ -75,7 +75,7 @@ LL | extern "riscv-interrupt-m" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:151:21
+  --> $DIR/unsupported.rs:153:21
    |
 LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -84,7 +84,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
    = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
 
 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:159:22
+  --> $DIR/unsupported.rs:161:22
    |
 LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -93,7 +93,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
    = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
 
 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:164:1
+  --> $DIR/unsupported.rs:166:1
    |
 LL | extern "C-cmse-nonsecure-entry" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -135,7 +135,7 @@ LL | extern "riscv-interrupt-m" fn riscv() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:157:1
+  --> $DIR/unsupported.rs:159:1
    |
 LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -200,7 +200,7 @@ LL | fn riscv_ptr(f: extern "riscv-interrupt-m" fn()) {
 
 Future breakage diagnostic:
 warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:151:21
+  --> $DIR/unsupported.rs:153:21
    |
 LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -211,7 +211,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
 
 Future breakage diagnostic:
 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:159:22
+  --> $DIR/unsupported.rs:161:22
    |
 LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/abi/unsupported.riscv32.stderr b/tests/ui/abi/unsupported.riscv32.stderr
index a0e2901c759..ad57a89e455 100644
--- a/tests/ui/abi/unsupported.riscv32.stderr
+++ b/tests/ui/abi/unsupported.riscv32.stderr
@@ -99,7 +99,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
    = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
 
 error[E0570]: `"stdcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:117:1
+  --> $DIR/unsupported.rs:119:1
    |
 LL | extern "stdcall" {}
    | ^^^^^^^^^^^^^^^^^^^
@@ -107,24 +107,26 @@ LL | extern "stdcall" {}
    = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
 error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:121:1
+  --> $DIR/unsupported.rs:123:1
    |
 LL | extern "stdcall-unwind" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"`
 
-warning: the calling convention "cdecl" is not supported on this target
-  --> $DIR/unsupported.rs:129:17
+warning: use of calling convention not supported on this target
+  --> $DIR/unsupported.rs:131:17
    |
 LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
    |                 ^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C"` instead
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:134:1
+  --> $DIR/unsupported.rs:136:1
    |
 LL | extern "cdecl" {}
    | ^^^^^^^^^^^^^^^^^
@@ -132,10 +134,9 @@ LL | extern "cdecl" {}
    = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: use `extern "C"` instead
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:137:1
+  --> $DIR/unsupported.rs:139:1
    |
 LL | extern "cdecl-unwind" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -145,7 +146,7 @@ LL | extern "cdecl-unwind" {}
    = help: use `extern "C-unwind"` instead
 
 warning: the calling convention "vectorcall" is not supported on this target
-  --> $DIR/unsupported.rs:143:22
+  --> $DIR/unsupported.rs:145:22
    |
 LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -154,13 +155,13 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
    = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
 
 error[E0570]: `"vectorcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:148:1
+  --> $DIR/unsupported.rs:150:1
    |
 LL | extern "vectorcall" {}
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:151:21
+  --> $DIR/unsupported.rs:153:21
    |
 LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -169,7 +170,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
    = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
 
 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:159:22
+  --> $DIR/unsupported.rs:161:22
    |
 LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -178,7 +179,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
    = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
 
 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:164:1
+  --> $DIR/unsupported.rs:166:1
    |
 LL | extern "C-cmse-nonsecure-entry" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -234,7 +235,7 @@ LL | extern "stdcall" fn stdcall() {}
    = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:126:1
+  --> $DIR/unsupported.rs:128:1
    |
 LL | extern "cdecl" fn cdecl() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -244,13 +245,13 @@ LL | extern "cdecl" fn cdecl() {}
    = help: use `extern "C"` instead
 
 error[E0570]: `"vectorcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:141:1
+  --> $DIR/unsupported.rs:143:1
    |
 LL | extern "vectorcall" fn vectorcall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:157:1
+  --> $DIR/unsupported.rs:159:1
    |
 LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -336,19 +337,20 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
    = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
 
 Future breakage diagnostic:
-warning: the calling convention "cdecl" is not supported on this target
-  --> $DIR/unsupported.rs:129:17
+warning: use of calling convention not supported on this target
+  --> $DIR/unsupported.rs:131:17
    |
 LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
    |                 ^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C"` instead
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
 Future breakage diagnostic:
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:134:1
+  --> $DIR/unsupported.rs:136:1
    |
 LL | extern "cdecl" {}
    | ^^^^^^^^^^^^^^^^^
@@ -360,7 +362,7 @@ LL | extern "cdecl" {}
 
 Future breakage diagnostic:
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:137:1
+  --> $DIR/unsupported.rs:139:1
    |
 LL | extern "cdecl-unwind" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -372,7 +374,7 @@ LL | extern "cdecl-unwind" {}
 
 Future breakage diagnostic:
 warning: the calling convention "vectorcall" is not supported on this target
-  --> $DIR/unsupported.rs:143:22
+  --> $DIR/unsupported.rs:145:22
    |
 LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -383,7 +385,7 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
 
 Future breakage diagnostic:
 warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:151:21
+  --> $DIR/unsupported.rs:153:21
    |
 LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -394,7 +396,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
 
 Future breakage diagnostic:
 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:159:22
+  --> $DIR/unsupported.rs:161:22
    |
 LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -405,7 +407,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
 
 Future breakage diagnostic:
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:126:1
+  --> $DIR/unsupported.rs:128:1
    |
 LL | extern "cdecl" fn cdecl() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/abi/unsupported.riscv64.stderr b/tests/ui/abi/unsupported.riscv64.stderr
index a0e2901c759..ad57a89e455 100644
--- a/tests/ui/abi/unsupported.riscv64.stderr
+++ b/tests/ui/abi/unsupported.riscv64.stderr
@@ -99,7 +99,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
    = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
 
 error[E0570]: `"stdcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:117:1
+  --> $DIR/unsupported.rs:119:1
    |
 LL | extern "stdcall" {}
    | ^^^^^^^^^^^^^^^^^^^
@@ -107,24 +107,26 @@ LL | extern "stdcall" {}
    = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
 error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:121:1
+  --> $DIR/unsupported.rs:123:1
    |
 LL | extern "stdcall-unwind" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"`
 
-warning: the calling convention "cdecl" is not supported on this target
-  --> $DIR/unsupported.rs:129:17
+warning: use of calling convention not supported on this target
+  --> $DIR/unsupported.rs:131:17
    |
 LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
    |                 ^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C"` instead
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:134:1
+  --> $DIR/unsupported.rs:136:1
    |
 LL | extern "cdecl" {}
    | ^^^^^^^^^^^^^^^^^
@@ -132,10 +134,9 @@ LL | extern "cdecl" {}
    = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: use `extern "C"` instead
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:137:1
+  --> $DIR/unsupported.rs:139:1
    |
 LL | extern "cdecl-unwind" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -145,7 +146,7 @@ LL | extern "cdecl-unwind" {}
    = help: use `extern "C-unwind"` instead
 
 warning: the calling convention "vectorcall" is not supported on this target
-  --> $DIR/unsupported.rs:143:22
+  --> $DIR/unsupported.rs:145:22
    |
 LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -154,13 +155,13 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
    = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
 
 error[E0570]: `"vectorcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:148:1
+  --> $DIR/unsupported.rs:150:1
    |
 LL | extern "vectorcall" {}
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:151:21
+  --> $DIR/unsupported.rs:153:21
    |
 LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -169,7 +170,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
    = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
 
 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:159:22
+  --> $DIR/unsupported.rs:161:22
    |
 LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -178,7 +179,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
    = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
 
 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:164:1
+  --> $DIR/unsupported.rs:166:1
    |
 LL | extern "C-cmse-nonsecure-entry" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -234,7 +235,7 @@ LL | extern "stdcall" fn stdcall() {}
    = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:126:1
+  --> $DIR/unsupported.rs:128:1
    |
 LL | extern "cdecl" fn cdecl() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -244,13 +245,13 @@ LL | extern "cdecl" fn cdecl() {}
    = help: use `extern "C"` instead
 
 error[E0570]: `"vectorcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:141:1
+  --> $DIR/unsupported.rs:143:1
    |
 LL | extern "vectorcall" fn vectorcall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:157:1
+  --> $DIR/unsupported.rs:159:1
    |
 LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -336,19 +337,20 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
    = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
 
 Future breakage diagnostic:
-warning: the calling convention "cdecl" is not supported on this target
-  --> $DIR/unsupported.rs:129:17
+warning: use of calling convention not supported on this target
+  --> $DIR/unsupported.rs:131:17
    |
 LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
    |                 ^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C"` instead
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
 Future breakage diagnostic:
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:134:1
+  --> $DIR/unsupported.rs:136:1
    |
 LL | extern "cdecl" {}
    | ^^^^^^^^^^^^^^^^^
@@ -360,7 +362,7 @@ LL | extern "cdecl" {}
 
 Future breakage diagnostic:
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:137:1
+  --> $DIR/unsupported.rs:139:1
    |
 LL | extern "cdecl-unwind" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -372,7 +374,7 @@ LL | extern "cdecl-unwind" {}
 
 Future breakage diagnostic:
 warning: the calling convention "vectorcall" is not supported on this target
-  --> $DIR/unsupported.rs:143:22
+  --> $DIR/unsupported.rs:145:22
    |
 LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -383,7 +385,7 @@ LL | fn vectorcall_ptr(f: extern "vectorcall" fn()) {
 
 Future breakage diagnostic:
 warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:151:21
+  --> $DIR/unsupported.rs:153:21
    |
 LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -394,7 +396,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
 
 Future breakage diagnostic:
 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:159:22
+  --> $DIR/unsupported.rs:161:22
    |
 LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -405,7 +407,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
 
 Future breakage diagnostic:
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:126:1
+  --> $DIR/unsupported.rs:128:1
    |
 LL | extern "cdecl" fn cdecl() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/abi/unsupported.rs b/tests/ui/abi/unsupported.rs
index 9ea22ca516b..43bdfe3ea24 100644
--- a/tests/ui/abi/unsupported.rs
+++ b/tests/ui/abi/unsupported.rs
@@ -110,8 +110,10 @@ extern "stdcall" fn stdcall() {}
 //[x64_win]~^^ WARN unsupported_calling_conventions
 //[x64_win]~^^^ WARN this was previously accepted
 fn stdcall_ptr(f: extern "stdcall" fn()) {
-    //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ WARN unsupported_fn_ptr_calling_conventions
-    //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^^ WARN this was previously accepted
+    //[x64_win]~^ WARN unsupported_calling_conventions
+    //[x64_win]~| WARN this was previously accepted
+    //[x64,arm,aarch64,riscv32,riscv64]~^^^ WARN unsupported_fn_ptr_calling_conventions
+    //[x64,arm,aarch64,riscv32,riscv64]~| WARN this was previously accepted
     f()
 }
 extern "stdcall" {}
@@ -127,7 +129,7 @@ extern "cdecl" fn cdecl() {}
 //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ WARN unsupported_calling_conventions
 //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^^ WARN this was previously accepted
 fn cdecl_ptr(f: extern "cdecl" fn()) {
-    //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ WARN unsupported_fn_ptr_calling_conventions
+    //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^ WARN unsupported_calling_conventions
     //[x64,x64_win,arm,aarch64,riscv32,riscv64]~^^ WARN this was previously accepted
     f()
 }
diff --git a/tests/ui/abi/unsupported.x64.stderr b/tests/ui/abi/unsupported.x64.stderr
index 732a5f84f50..f777fe86e24 100644
--- a/tests/ui/abi/unsupported.x64.stderr
+++ b/tests/ui/abi/unsupported.x64.stderr
@@ -99,7 +99,7 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
    = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
 
 error[E0570]: `"stdcall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:117:1
+  --> $DIR/unsupported.rs:119:1
    |
 LL | extern "stdcall" {}
    | ^^^^^^^^^^^^^^^^^^^
@@ -107,24 +107,26 @@ LL | extern "stdcall" {}
    = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
 error[E0570]: `"stdcall-unwind"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:121:1
+  --> $DIR/unsupported.rs:123:1
    |
 LL | extern "stdcall-unwind" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"`
 
-warning: the calling convention "cdecl" is not supported on this target
-  --> $DIR/unsupported.rs:129:17
+warning: use of calling convention not supported on this target
+  --> $DIR/unsupported.rs:131:17
    |
 LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
    |                 ^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C"` instead
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:134:1
+  --> $DIR/unsupported.rs:136:1
    |
 LL | extern "cdecl" {}
    | ^^^^^^^^^^^^^^^^^
@@ -132,10 +134,9 @@ LL | extern "cdecl" {}
    = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: use `extern "C"` instead
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:137:1
+  --> $DIR/unsupported.rs:139:1
    |
 LL | extern "cdecl-unwind" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -145,7 +146,7 @@ LL | extern "cdecl-unwind" {}
    = help: use `extern "C-unwind"` instead
 
 warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:151:21
+  --> $DIR/unsupported.rs:153:21
    |
 LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -154,7 +155,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
    = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
 
 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:159:22
+  --> $DIR/unsupported.rs:161:22
    |
 LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -163,7 +164,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
    = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
 
 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:164:1
+  --> $DIR/unsupported.rs:166:1
    |
 LL | extern "C-cmse-nonsecure-entry" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -219,7 +220,7 @@ LL | extern "stdcall" fn stdcall() {}
    = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:126:1
+  --> $DIR/unsupported.rs:128:1
    |
 LL | extern "cdecl" fn cdecl() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -229,7 +230,7 @@ LL | extern "cdecl" fn cdecl() {}
    = help: use `extern "C"` instead
 
 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:157:1
+  --> $DIR/unsupported.rs:159:1
    |
 LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -315,19 +316,20 @@ LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
    = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
 
 Future breakage diagnostic:
-warning: the calling convention "cdecl" is not supported on this target
-  --> $DIR/unsupported.rs:129:17
+warning: use of calling convention not supported on this target
+  --> $DIR/unsupported.rs:131:17
    |
 LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
    |                 ^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C"` instead
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
 Future breakage diagnostic:
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:134:1
+  --> $DIR/unsupported.rs:136:1
    |
 LL | extern "cdecl" {}
    | ^^^^^^^^^^^^^^^^^
@@ -339,7 +341,7 @@ LL | extern "cdecl" {}
 
 Future breakage diagnostic:
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:137:1
+  --> $DIR/unsupported.rs:139:1
    |
 LL | extern "cdecl-unwind" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -351,7 +353,7 @@ LL | extern "cdecl-unwind" {}
 
 Future breakage diagnostic:
 warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:151:21
+  --> $DIR/unsupported.rs:153:21
    |
 LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -362,7 +364,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
 
 Future breakage diagnostic:
 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:159:22
+  --> $DIR/unsupported.rs:161:22
    |
 LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -373,7 +375,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
 
 Future breakage diagnostic:
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:126:1
+  --> $DIR/unsupported.rs:128:1
    |
 LL | extern "cdecl" fn cdecl() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/abi/unsupported.x64_win.stderr b/tests/ui/abi/unsupported.x64_win.stderr
index 5597440d5d9..328f4c3b043 100644
--- a/tests/ui/abi/unsupported.x64_win.stderr
+++ b/tests/ui/abi/unsupported.x64_win.stderr
@@ -89,17 +89,19 @@ error[E0570]: `"thiscall"` is not a supported ABI for the current target
 LL | extern "thiscall" {}
    | ^^^^^^^^^^^^^^^^^^^^
 
-warning: the calling convention "stdcall" is not supported on this target
+warning: use of calling convention not supported on this target
   --> $DIR/unsupported.rs:112:19
    |
 LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
    |                   ^^^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:117:1
+  --> $DIR/unsupported.rs:119:1
    |
 LL | extern "stdcall" {}
    | ^^^^^^^^^^^^^^^^^^^
@@ -107,10 +109,9 @@ LL | extern "stdcall" {}
    = 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 #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:121:1
+  --> $DIR/unsupported.rs:123:1
    |
 LL | extern "stdcall-unwind" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -119,17 +120,18 @@ LL | extern "stdcall-unwind" {}
    = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
    = help: if you need `extern "stdcall-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-unwind"`
 
-warning: the calling convention "cdecl" is not supported on this target
-  --> $DIR/unsupported.rs:129:17
+warning: use of calling convention not supported on this target
+  --> $DIR/unsupported.rs:131:17
    |
 LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
    |                 ^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C"` instead
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:134:1
+  --> $DIR/unsupported.rs:136:1
    |
 LL | extern "cdecl" {}
    | ^^^^^^^^^^^^^^^^^
@@ -139,7 +141,7 @@ LL | extern "cdecl" {}
    = help: use `extern "C"` instead
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:137:1
+  --> $DIR/unsupported.rs:139:1
    |
 LL | extern "cdecl-unwind" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -149,7 +151,7 @@ LL | extern "cdecl-unwind" {}
    = help: use `extern "C-unwind"` instead
 
 warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:151:21
+  --> $DIR/unsupported.rs:153:21
    |
 LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -158,7 +160,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
    = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
 
 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:159:22
+  --> $DIR/unsupported.rs:161:22
    |
 LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -167,13 +169,13 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
    = note: for more information, see issue #130260 <https://github.com/rust-lang/rust/issues/130260>
 
 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:164:1
+  --> $DIR/unsupported.rs:166:1
    |
 LL | extern "C-cmse-nonsecure-entry" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:169:1
+  --> $DIR/unsupported.rs:171:1
    |
 LL | extern "cdecl" {}
    | ^^^^^^^^^^^^^^^^^
@@ -235,7 +237,7 @@ LL | extern "stdcall" fn stdcall() {}
    = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:126:1
+  --> $DIR/unsupported.rs:128:1
    |
 LL | extern "cdecl" fn cdecl() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -245,7 +247,7 @@ LL | extern "cdecl" fn cdecl() {}
    = help: use `extern "C"` instead
 
 error[E0570]: `"C-cmse-nonsecure-entry"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:157:1
+  --> $DIR/unsupported.rs:159:1
    |
 LL | extern "C-cmse-nonsecure-entry" fn cmse_entry() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -320,19 +322,20 @@ LL | fn thiscall_ptr(f: extern "thiscall" fn()) {
    = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
 
 Future breakage diagnostic:
-warning: the calling convention "stdcall" is not supported on this target
+warning: use of calling convention not supported on this target
   --> $DIR/unsupported.rs:112:19
    |
 LL | fn stdcall_ptr(f: extern "stdcall" fn()) {
    |                   ^^^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: if you need `extern "stdcall"` on win32 and `extern "C"` everywhere else, use `extern "system"`
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
 Future breakage diagnostic:
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:117:1
+  --> $DIR/unsupported.rs:119:1
    |
 LL | extern "stdcall" {}
    | ^^^^^^^^^^^^^^^^^^^
@@ -344,7 +347,7 @@ LL | extern "stdcall" {}
 
 Future breakage diagnostic:
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:121:1
+  --> $DIR/unsupported.rs:123:1
    |
 LL | extern "stdcall-unwind" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -355,19 +358,20 @@ LL | extern "stdcall-unwind" {}
    = note: `#[warn(unsupported_calling_conventions)]` on by default
 
 Future breakage diagnostic:
-warning: the calling convention "cdecl" is not supported on this target
-  --> $DIR/unsupported.rs:129:17
+warning: use of calling convention not supported on this target
+  --> $DIR/unsupported.rs:131:17
    |
 LL | fn cdecl_ptr(f: extern "cdecl" fn()) {
    |                 ^^^^^^^^^^^^^^^^^^^
    |
    = 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 #130260 <https://github.com/rust-lang/rust/issues/130260>
-   = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
+   = note: for more information, see issue #137018 <https://github.com/rust-lang/rust/issues/137018>
+   = help: use `extern "C"` instead
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
 
 Future breakage diagnostic:
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:134:1
+  --> $DIR/unsupported.rs:136:1
    |
 LL | extern "cdecl" {}
    | ^^^^^^^^^^^^^^^^^
@@ -379,7 +383,7 @@ LL | extern "cdecl" {}
 
 Future breakage diagnostic:
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:137:1
+  --> $DIR/unsupported.rs:139:1
    |
 LL | extern "cdecl-unwind" {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -391,7 +395,7 @@ LL | extern "cdecl-unwind" {}
 
 Future breakage diagnostic:
 warning: the calling convention "C-cmse-nonsecure-call" is not supported on this target
-  --> $DIR/unsupported.rs:151:21
+  --> $DIR/unsupported.rs:153:21
    |
 LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -402,7 +406,7 @@ LL | fn cmse_call_ptr(f: extern "C-cmse-nonsecure-call" fn()) {
 
 Future breakage diagnostic:
 warning: the calling convention "C-cmse-nonsecure-entry" is not supported on this target
-  --> $DIR/unsupported.rs:159:22
+  --> $DIR/unsupported.rs:161:22
    |
 LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -413,7 +417,7 @@ LL | fn cmse_entry_ptr(f: extern "C-cmse-nonsecure-entry" fn()) {
 
 Future breakage diagnostic:
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:169:1
+  --> $DIR/unsupported.rs:171:1
    |
 LL | extern "cdecl" {}
    | ^^^^^^^^^^^^^^^^^
@@ -437,7 +441,7 @@ LL | extern "stdcall" fn stdcall() {}
 
 Future breakage diagnostic:
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:126:1
+  --> $DIR/unsupported.rs:128:1
    |
 LL | extern "cdecl" fn cdecl() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/check-cfg/hrtb-crash.rs b/tests/ui/check-cfg/hrtb-crash.rs
new file mode 100644
index 00000000000..f2bce33f9f9
--- /dev/null
+++ b/tests/ui/check-cfg/hrtb-crash.rs
@@ -0,0 +1,7 @@
+// https://github.com/rust-lang/rust/issues/139825
+//@ compile-flags: --check-cfg=cfg(docsrs,test) --crate-type lib
+//@ check-pass
+struct A
+where
+    for<#[cfg(b)] c> u8:;
+//~^ WARN: unexpected `cfg` condition name
diff --git a/tests/ui/check-cfg/hrtb-crash.stderr b/tests/ui/check-cfg/hrtb-crash.stderr
new file mode 100644
index 00000000000..431cf9cf53e
--- /dev/null
+++ b/tests/ui/check-cfg/hrtb-crash.stderr
@@ -0,0 +1,13 @@
+warning: unexpected `cfg` condition name: `b`
+  --> $DIR/hrtb-crash.rs:6:15
+   |
+LL |     for<#[cfg(b)] c> u8:;
+   |               ^ help: found config with similar value: `target_feature = "b"`
+   |
+   = help: expected names are: `FALSE`, `docsrs`, and `test` and 31 more
+   = help: to expect this configuration use `--check-cfg=cfg(b)`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/deprecation/deprecated_no_stack_check.rs b/tests/ui/deprecation/deprecated_no_stack_check.rs
index 8e1f5bbf045..ef482098634 100644
--- a/tests/ui/deprecation/deprecated_no_stack_check.rs
+++ b/tests/ui/deprecation/deprecated_no_stack_check.rs
@@ -1,3 +1,5 @@
+//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION"
+
 #![deny(warnings)]
 #![feature(no_stack_check)]
 //~^ ERROR: feature has been removed [E0557]
diff --git a/tests/ui/deprecation/deprecated_no_stack_check.stderr b/tests/ui/deprecation/deprecated_no_stack_check.stderr
index d78ca20f10b..2d08b1b8db5 100644
--- a/tests/ui/deprecation/deprecated_no_stack_check.stderr
+++ b/tests/ui/deprecation/deprecated_no_stack_check.stderr
@@ -1,8 +1,10 @@
 error[E0557]: feature has been removed
-  --> $DIR/deprecated_no_stack_check.rs:2:12
+  --> $DIR/deprecated_no_stack_check.rs:4:12
    |
 LL | #![feature(no_stack_check)]
    |            ^^^^^^^^^^^^^^ feature has been removed
+   |
+   = note: removed in 1.0.0 (you are using $RUSTC_VERSION); see <https://github.com/rust-lang/rust/pull/40110> for more information
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/feature-gates/feature-gate-coverage-attribute.rs b/tests/ui/feature-gates/feature-gate-coverage-attribute.rs
index 0a463755f13..2cf4b76180e 100644
--- a/tests/ui/feature-gates/feature-gate-coverage-attribute.rs
+++ b/tests/ui/feature-gates/feature-gate-coverage-attribute.rs
@@ -1,3 +1,5 @@
+//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION"
+
 #![crate_type = "lib"]
 #![feature(no_coverage)] //~ ERROR feature has been removed [E0557]
 
diff --git a/tests/ui/feature-gates/feature-gate-coverage-attribute.stderr b/tests/ui/feature-gates/feature-gate-coverage-attribute.stderr
index 00e0f0afbde..8c23544698d 100644
--- a/tests/ui/feature-gates/feature-gate-coverage-attribute.stderr
+++ b/tests/ui/feature-gates/feature-gate-coverage-attribute.stderr
@@ -1,13 +1,14 @@
 error[E0557]: feature has been removed
-  --> $DIR/feature-gate-coverage-attribute.rs:2:12
+  --> $DIR/feature-gate-coverage-attribute.rs:4:12
    |
 LL | #![feature(no_coverage)]
    |            ^^^^^^^^^^^ feature has been removed
    |
+   = note: removed in 1.74.0 (you are using $RUSTC_VERSION); see <https://github.com/rust-lang/rust/pull/114656> for more information
    = note: renamed to `coverage_attribute`
 
 error[E0658]: the `#[coverage]` attribute is an experimental feature
-  --> $DIR/feature-gate-coverage-attribute.rs:10:1
+  --> $DIR/feature-gate-coverage-attribute.rs:12:1
    |
 LL | #[coverage(off)]
    | ^^^^^^^^^^^^^^^^
diff --git a/tests/ui/feature-gates/feature-gate-keylocker_x86.rs b/tests/ui/feature-gates/feature-gate-keylocker_x86.rs
deleted file mode 100644
index cef80ad41a8..00000000000
--- a/tests/ui/feature-gates/feature-gate-keylocker_x86.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//@ only-x86_64
-#[target_feature(enable = "kl")]
-//~^ ERROR: currently unstable
-unsafe fn foo() {}
-
-fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-keylocker_x86.stderr b/tests/ui/feature-gates/feature-gate-keylocker_x86.stderr
deleted file mode 100644
index ed814d3a3ce..00000000000
--- a/tests/ui/feature-gates/feature-gate-keylocker_x86.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0658]: the target feature `kl` is currently unstable
-  --> $DIR/feature-gate-keylocker_x86.rs:2:18
-   |
-LL | #[target_feature(enable = "kl")]
-   |                  ^^^^^^^^^^^^^
-   |
-   = note: see issue #134813 <https://github.com/rust-lang/rust/issues/134813> for more information
-   = help: add `#![feature(keylocker_x86)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/gated-bad-feature.rs b/tests/ui/feature-gates/gated-bad-feature.rs
index 51f2db5556e..3114f661dc5 100644
--- a/tests/ui/feature-gates/gated-bad-feature.rs
+++ b/tests/ui/feature-gates/gated-bad-feature.rs
@@ -1,3 +1,4 @@
+//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION"
 #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)]
 //~^ ERROR malformed `feature`
 //~| ERROR malformed `feature`
diff --git a/tests/ui/feature-gates/gated-bad-feature.stderr b/tests/ui/feature-gates/gated-bad-feature.stderr
index 2d01bdf3c1d..0e75dff14f8 100644
--- a/tests/ui/feature-gates/gated-bad-feature.stderr
+++ b/tests/ui/feature-gates/gated-bad-feature.stderr
@@ -1,41 +1,43 @@
 error[E0556]: malformed `feature` attribute input
-  --> $DIR/gated-bad-feature.rs:1:25
+  --> $DIR/gated-bad-feature.rs:2:25
    |
 LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)]
    |                         ^^^^^^^^ help: expected just one word: `foo`
 
 error[E0556]: malformed `feature` attribute input
-  --> $DIR/gated-bad-feature.rs:1:35
+  --> $DIR/gated-bad-feature.rs:2:35
    |
 LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)]
    |                                   ^^^^^^^^^^^ help: expected just one word: `foo`
 
 error[E0557]: feature has been removed
-  --> $DIR/gated-bad-feature.rs:8:12
+  --> $DIR/gated-bad-feature.rs:9:12
    |
 LL | #![feature(test_removed_feature)]
    |            ^^^^^^^^^^^^^^^^^^^^ feature has been removed
+   |
+   = note: removed in 1.0.0 (you are using $RUSTC_VERSION)
 
 error: malformed `feature` attribute input
-  --> $DIR/gated-bad-feature.rs:6:1
+  --> $DIR/gated-bad-feature.rs:7:1
    |
 LL | #![feature]
    | ^^^^^^^^^^^ help: must be of the form: `#![feature(name1, name2, ...)]`
 
 error: malformed `feature` attribute input
-  --> $DIR/gated-bad-feature.rs:7:1
+  --> $DIR/gated-bad-feature.rs:8:1
    |
 LL | #![feature = "foo"]
    | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![feature(name1, name2, ...)]`
 
 error[E0635]: unknown feature `foo_bar_baz`
-  --> $DIR/gated-bad-feature.rs:1:12
+  --> $DIR/gated-bad-feature.rs:2:12
    |
 LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)]
    |            ^^^^^^^^^^^
 
 error[E0635]: unknown feature `foo`
-  --> $DIR/gated-bad-feature.rs:1:48
+  --> $DIR/gated-bad-feature.rs:2:48
    |
 LL | #![feature(foo_bar_baz, foo(bar), foo = "baz", foo)]
    |                                                ^^^
diff --git a/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.rs b/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.rs
new file mode 100644
index 00000000000..ec6adb471ba
--- /dev/null
+++ b/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.rs
@@ -0,0 +1,6 @@
+//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION"
+
+#![feature(external_doc)] //~ ERROR feature has been removed
+#![doc(include("README.md"))] //~ ERROR unknown `doc` attribute `include`
+
+fn main(){}
diff --git a/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.stderr b/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.stderr
new file mode 100644
index 00000000000..43205c7360b
--- /dev/null
+++ b/tests/ui/feature-gates/removed-features-note-version-and-pr-issue-141619.stderr
@@ -0,0 +1,20 @@
+error[E0557]: feature has been removed
+  --> $DIR/removed-features-note-version-and-pr-issue-141619.rs:3:12
+   |
+LL | #![feature(external_doc)]
+   |            ^^^^^^^^^^^^ feature has been removed
+   |
+   = note: removed in 1.54.0 (you are using $RUSTC_VERSION); see <https://github.com/rust-lang/rust/pull/85457> for more information
+   = note: use #[doc = include_str!("filename")] instead, which handles macro invocations
+
+error: unknown `doc` attribute `include`
+  --> $DIR/removed-features-note-version-and-pr-issue-141619.rs:4:8
+   |
+LL | #![doc(include("README.md"))]
+   |        ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[deny(invalid_doc_attributes)]` on by default
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0557`.
diff --git a/tests/ui/macros/macro-reexport-removed.rs b/tests/ui/macros/macro-reexport-removed.rs
index 4a054686d77..c1267f14cd8 100644
--- a/tests/ui/macros/macro-reexport-removed.rs
+++ b/tests/ui/macros/macro-reexport-removed.rs
@@ -1,4 +1,5 @@
 //@ aux-build:two_macros.rs
+//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION"
 
 #![feature(macro_reexport)] //~ ERROR feature has been removed
 
diff --git a/tests/ui/macros/macro-reexport-removed.stderr b/tests/ui/macros/macro-reexport-removed.stderr
index 475a586ddc0..d4940eeb775 100644
--- a/tests/ui/macros/macro-reexport-removed.stderr
+++ b/tests/ui/macros/macro-reexport-removed.stderr
@@ -1,13 +1,14 @@
 error[E0557]: feature has been removed
-  --> $DIR/macro-reexport-removed.rs:3:12
+  --> $DIR/macro-reexport-removed.rs:4:12
    |
 LL | #![feature(macro_reexport)]
    |            ^^^^^^^^^^^^^^ feature has been removed
    |
+   = note: removed in 1.0.0 (you are using $RUSTC_VERSION); see <https://github.com/rust-lang/rust/pull/49982> for more information
    = note: subsumed by `pub use`
 
 error: cannot find attribute `macro_reexport` in this scope
-  --> $DIR/macro-reexport-removed.rs:5:3
+  --> $DIR/macro-reexport-removed.rs:6:3
    |
 LL | #[macro_reexport(macro_one)]
    |   ^^^^^^^^^^^^^^ help: a built-in attribute with a similar name exists: `macro_export`
diff --git a/tests/ui/rustdoc/renamed-features-rustdoc_internals.rs b/tests/ui/rustdoc/renamed-features-rustdoc_internals.rs
index 739c624d0c6..2257130280d 100644
--- a/tests/ui/rustdoc/renamed-features-rustdoc_internals.rs
+++ b/tests/ui/rustdoc/renamed-features-rustdoc_internals.rs
@@ -1,3 +1,5 @@
+//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION"
+
 #![feature(doc_keyword)] //~ ERROR
 #![feature(doc_primitive)] //~ ERROR
 #![crate_type = "lib"]
diff --git a/tests/ui/rustdoc/renamed-features-rustdoc_internals.stderr b/tests/ui/rustdoc/renamed-features-rustdoc_internals.stderr
index d0979ce97ac..9c664da8ee6 100644
--- a/tests/ui/rustdoc/renamed-features-rustdoc_internals.stderr
+++ b/tests/ui/rustdoc/renamed-features-rustdoc_internals.stderr
@@ -1,17 +1,19 @@
 error[E0557]: feature has been removed
-  --> $DIR/renamed-features-rustdoc_internals.rs:1:12
+  --> $DIR/renamed-features-rustdoc_internals.rs:3:12
    |
 LL | #![feature(doc_keyword)]
    |            ^^^^^^^^^^^ feature has been removed
    |
+   = note: removed in 1.58.0 (you are using $RUSTC_VERSION); see <https://github.com/rust-lang/rust/pull/90420> for more information
    = note: merged into `#![feature(rustdoc_internals)]`
 
 error[E0557]: feature has been removed
-  --> $DIR/renamed-features-rustdoc_internals.rs:2:12
+  --> $DIR/renamed-features-rustdoc_internals.rs:4:12
    |
 LL | #![feature(doc_primitive)]
    |            ^^^^^^^^^^^^^ feature has been removed
    |
+   = note: removed in 1.58.0 (you are using $RUSTC_VERSION); see <https://github.com/rust-lang/rust/pull/90420> for more information
    = note: merged into `#![feature(rustdoc_internals)]`
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs b/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs
index f90ff91aff4..b563b78f78a 100644
--- a/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs
+++ b/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.rs
@@ -6,6 +6,7 @@
 // Regression test for issue #125877.
 
 //@ compile-flags: -Znext-solver
+//@ normalize-stderr: "you are using [0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?( \([^)]*\))?" -> "you are using $$RUSTC_VERSION"
 
 #![feature(const_trait_impl, effects)]
 //~^ ERROR feature has been removed
diff --git a/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.stderr b/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.stderr
index d45c4cba1f8..a04f98e68a6 100644
--- a/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.stderr
+++ b/tests/ui/traits/const-traits/const-trait-impl-parameter-mismatch.stderr
@@ -1,13 +1,14 @@
 error[E0557]: feature has been removed
-  --> $DIR/const-trait-impl-parameter-mismatch.rs:10:30
+  --> $DIR/const-trait-impl-parameter-mismatch.rs:11:30
    |
 LL | #![feature(const_trait_impl, effects)]
    |                              ^^^^^^^ feature has been removed
    |
+   = note: removed in 1.84.0 (you are using $RUSTC_VERSION); see <https://github.com/rust-lang/rust/pull/132479> for more information
    = note: removed, redundant with `#![feature(const_trait_impl)]`
 
 error[E0049]: associated function `compute` has 0 type parameters but its trait declaration has 1 type parameter
-  --> $DIR/const-trait-impl-parameter-mismatch.rs:19:16
+  --> $DIR/const-trait-impl-parameter-mismatch.rs:20:16
    |
 LL |     fn compute<T: ~const Aux>() -> u32;
    |                - expected 1 type parameter
diff --git a/tests/ui/type/pattern_types/matching.rs b/tests/ui/type/pattern_types/matching.rs
index b8463a8e822..21f89b3b673 100644
--- a/tests/ui/type/pattern_types/matching.rs
+++ b/tests/ui/type/pattern_types/matching.rs
@@ -1,6 +1,7 @@
 #![feature(pattern_types, pattern_type_macro, structural_match)]
 
 //@ check-pass
+//@ compile-flags: -Zvalidate-mir
 
 use std::marker::StructuralPartialEq;
 use std::pat::pattern_type;