about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml8
-rw-r--r--Cargo.lock267
-rw-r--r--bootstrap.example.toml9
-rw-r--r--compiler/rustc_abi/src/canon_abi.rs4
-rw-r--r--compiler/rustc_abi/src/extern_abi.rs6
-rw-r--r--compiler/rustc_ast/src/ast.rs68
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs616
-rw-r--r--compiler/rustc_ast/src/visit.rs1215
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs17
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs10
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs93
-rw-r--r--compiler/rustc_ast_lowering/src/stability.rs3
-rw-r--r--compiler/rustc_ast_passes/messages.ftl17
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs89
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs64
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs14
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/mod.rs12
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs8
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs107
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/fixup.rs91
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/item.rs4
-rw-r--r--compiler/rustc_attr_data_structures/src/attributes.rs44
-rw-r--r--compiler/rustc_attr_data_structures/src/lib.rs2
-rw-r--r--compiler/rustc_attr_data_structures/src/lints.rs14
-rw-r--r--compiler/rustc_attr_data_structures/src/stability.rs1
-rw-r--r--compiler/rustc_attr_parsing/messages.ftl8
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs38
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/confusables.rs8
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/deprecation.rs25
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/inline.rs97
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/mod.rs186
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/repr.rs23
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/stability.rs54
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/transparency.rs19
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs240
-rw-r--r--compiler/rustc_attr_parsing/src/lib.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/lints.rs19
-rw-r--r--compiler/rustc_attr_parsing/src/parser.rs14
-rw-r--r--compiler/rustc_attr_parsing/src/session_diagnostics.rs13
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs14
-rw-r--r--compiler/rustc_borrowck/src/type_check/constraint_conversion.rs5
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs7
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/mod.rs5
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/unsize.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/vtable.rs2
-rw-r--r--compiler/rustc_codegen_gcc/example/mini_core.rs4
-rw-r--r--compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs6
-rw-r--r--compiler/rustc_codegen_gcc/messages.ftl7
-rw-r--r--compiler/rustc_codegen_gcc/src/abi.rs6
-rw-r--r--compiler/rustc_codegen_gcc/src/errors.rs15
-rw-r--r--compiler/rustc_codegen_gcc/src/gcc_util.rs27
-rw-r--r--compiler/rustc_codegen_llvm/messages.ftl9
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/errors.rs17
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs25
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs190
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs3
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/type_.rs8
-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_const_eval/src/interpret/intrinsics.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/util.rs4
-rw-r--r--compiler/rustc_data_structures/src/thousands/mod.rs35
-rw-r--r--compiler/rustc_data_structures/src/thousands/tests.rs56
-rw-r--r--compiler/rustc_errors/src/lib.rs16
-rw-r--r--compiler/rustc_expand/messages.ftl3
-rw-r--r--compiler/rustc_expand/src/base.rs6
-rw-r--r--compiler/rustc_expand/src/config.rs11
-rw-r--r--compiler/rustc_expand/src/errors.rs4
-rw-r--r--compiler/rustc_expand/src/expand.rs190
-rw-r--r--compiler/rustc_expand/src/lib.rs1
-rw-r--r--compiler/rustc_expand/src/mbe/macro_check.rs25
-rw-r--r--compiler/rustc_expand/src/stats.rs171
-rw-r--r--compiler/rustc_feature/src/accepted.rs2
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs212
-rw-r--r--compiler/rustc_feature/src/lib.rs13
-rw-r--r--compiler/rustc_feature/src/removed.rs182
-rw-r--r--compiler/rustc_feature/src/unstable.rs4
-rw-r--r--compiler/rustc_hir/src/hir.rs5
-rw-r--r--compiler/rustc_hir/src/lib.rs1
-rw-r--r--compiler/rustc_hir/src/lints.rs23
-rw-r--r--compiler/rustc_hir/src/stable_hash_impls.rs8
-rw-r--r--compiler/rustc_hir_analysis/Cargo.toml1
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl4
-rw-r--r--compiler/rustc_hir_analysis/src/autoderef.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs56
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs14
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs19
-rw-r--r--compiler/rustc_hir_typeck/messages.ftl48
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs18
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs135
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs9
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/loops.rs (renamed from compiler/rustc_passes/src/loops.rs)39
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs15
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs123
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs5
-rw-r--r--compiler/rustc_infer/src/infer/type_variable.rs3
-rw-r--r--compiler/rustc_infer/src/infer/unify_key.rs3
-rw-r--r--compiler/rustc_interface/src/passes.rs82
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_lint/messages.ftl5
-rw-r--r--compiler/rustc_lint/src/builtin.rs52
-rw-r--r--compiler/rustc_lint/src/early.rs2
-rw-r--r--compiler/rustc_lint/src/early/diagnostics.rs3
-rw-r--r--compiler/rustc_lint/src/lib.rs6
-rw-r--r--compiler/rustc_lint/src/lints.rs30
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs2
-rw-r--r--compiler/rustc_lint/src/types.rs3
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs48
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs1
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs29
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs6
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs16
-rw-r--r--compiler/rustc_middle/src/middle/mod.rs2
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs2
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs2
-rw-r--r--compiler/rustc_middle/src/query/erase.rs1
-rw-r--r--compiler/rustc_middle/src/query/mod.rs15
-rw-r--r--compiler/rustc_middle/src/ty/context.rs36
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs1
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs7
-rw-r--r--compiler/rustc_mir_transform/src/early_otherwise_branch.rs32
-rw-r--r--compiler/rustc_mir_transform/src/inline/cycle.rs2
-rw-r--r--compiler/rustc_mir_transform/src/lower_intrinsics.rs4
-rw-r--r--compiler/rustc_mir_transform/src/validate.rs48
-rw-r--r--compiler/rustc_next_trait_solver/src/canonicalizer.rs105
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/mod.rs4
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs3
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs6
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs32
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs7
-rw-r--r--compiler/rustc_parse_format/src/lib.rs299
-rw-r--r--compiler/rustc_parse_format/src/tests.rs42
-rw-r--r--compiler/rustc_passes/messages.ftl46
-rw-r--r--compiler/rustc_passes/src/check_attr.rs22
-rw-r--r--compiler/rustc_passes/src/dead.rs30
-rw-r--r--compiler/rustc_passes/src/errors.rs149
-rw-r--r--compiler/rustc_passes/src/input_stats.rs16
-rw-r--r--compiler/rustc_passes/src/lib.rs2
-rw-r--r--compiler/rustc_passes/src/lib_features.rs8
-rw-r--r--compiler/rustc_passes/src/stability.rs11
-rw-r--r--compiler/rustc_resolve/messages.ftl2
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs28
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs8
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs134
-rw-r--r--compiler/rustc_resolve/src/ident.rs1
-rw-r--r--compiler/rustc_resolve/src/imports.rs4
-rw-r--r--compiler/rustc_resolve/src/late.rs2
-rw-r--r--compiler/rustc_resolve/src/lib.rs28
-rw-r--r--compiler/rustc_resolve/src/macros.rs33
-rw-r--r--compiler/rustc_session/messages.ftl8
-rw-r--r--compiler/rustc_session/src/config.rs9
-rw-r--r--compiler/rustc_session/src/errors.rs17
-rw-r--r--compiler/rustc_session/src/features.rs59
-rw-r--r--compiler/rustc_session/src/lib.rs1
-rw-r--r--compiler/rustc_session/src/options.rs15
-rw-r--r--compiler/rustc_session/src/parse.rs9
-rw-r--r--compiler/rustc_smir/src/rustc_internal/internal.rs1
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context.rs9
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/abi.rs46
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/ty.rs1
-rw-r--r--compiler/rustc_smir/src/stable_mir/abi.rs37
-rw-r--r--compiler/rustc_smir/src/stable_mir/compiler_interface.rs7
-rw-r--r--compiler/rustc_smir/src/stable_mir/ty.rs14
-rw-r--r--compiler/rustc_span/src/hygiene.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs9
-rw-r--r--compiler/rustc_target/src/asm/loongarch.rs10
-rw-r--r--compiler/rustc_target/src/spec/abi_map.rs2
-rw-r--r--compiler/rustc_target/src/spec/base/xtensa.rs2
-rw-r--r--compiler/rustc_target/src/spec/json.rs8
-rw-r--r--compiler/rustc_target/src/spec/mod.rs20
-rw-r--r--compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/avr_none.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/msp430_none_elf.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs2
-rw-r--r--compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs2
-rw-r--r--compiler/rustc_target/src/target_features.rs43
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs15
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs41
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs87
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs12
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/analyse.rs99
-rw-r--r--compiler/rustc_trait_selection/src/traits/normalize.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs143
-rw-r--r--compiler/rustc_traits/src/codegen.rs1
-rw-r--r--compiler/rustc_transmute/src/layout/dfa.rs45
-rw-r--r--compiler/rustc_transmute/src/layout/mod.rs111
-rw-r--r--compiler/rustc_transmute/src/layout/tree.rs48
-rw-r--r--compiler/rustc_transmute/src/layout/tree/tests.rs16
-rw-r--r--compiler/rustc_transmute/src/lib.rs30
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/mod.rs208
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/query_context.rs21
-rw-r--r--compiler/rustc_transmute/src/maybe_transmutable/tests.rs57
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs8
-rw-r--r--compiler/rustc_type_ir/src/canonical.rs9
-rw-r--r--compiler/rustc_type_ir/src/fast_reject.rs11
-rw-r--r--compiler/rustc_type_ir/src/interner.rs13
-rw-r--r--compiler/rustc_type_ir/src/ty_kind.rs17
-rw-r--r--library/Cargo.lock74
-rw-r--r--library/alloc/src/ffi/c_str.rs2
-rw-r--r--library/alloctests/tests/slice.rs13
-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/ffi/c_str.rs4
-rw-r--r--library/core/src/fmt/num.rs280
-rw-r--r--library/core/src/intrinsics/mod.rs13
-rw-r--r--library/core/src/lib.rs1
-rw-r--r--library/core/src/macros/mod.rs13
-rw-r--r--library/core/src/mem/mod.rs15
-rw-r--r--library/core/src/num/int_macros.rs1
-rw-r--r--library/core/src/num/mod.rs1
-rw-r--r--library/core/src/num/uint_macros.rs24
-rw-r--r--library/core/src/ops/control_flow.rs4
-rw-r--r--library/core/src/ops/mod.rs2
-rw-r--r--library/core/src/ops/try_trait.rs14
-rw-r--r--library/core/src/option.rs4
-rw-r--r--library/core/src/primitive_docs.rs3
-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/result.rs4
-rw-r--r--library/core/src/slice/ascii.rs1
-rw-r--r--library/core/src/slice/iter.rs7
-rw-r--r--library/core/src/slice/mod.rs1
-rw-r--r--library/core/src/sync/atomic.rs179
-rw-r--r--library/core/src/task/poll.rs8
-rw-r--r--library/core/src/task/wake.rs1
-rw-r--r--library/coretests/tests/ffi/cstr.rs2
-rw-r--r--library/coretests/tests/fmt/num.rs157
-rw-r--r--library/coretests/tests/lib.rs1
-rw-r--r--library/coretests/tests/num/uint_macros.rs8
-rw-r--r--library/std/Cargo.toml6
-rw-r--r--library/std/src/io/mod.rs40
m---------library/stdarch0
-rw-r--r--library/unwind/Cargo.toml2
-rw-r--r--src/bootstrap/src/core/build_steps/check.rs14
-rw-r--r--src/bootstrap/src/core/build_steps/clippy.rs6
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs119
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs27
-rw-r--r--src/bootstrap/src/core/build_steps/doc.rs22
-rw-r--r--src/bootstrap/src/core/build_steps/gcc.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/install.rs6
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs26
-rw-r--r--src/bootstrap/src/core/build_steps/perf.rs8
-rw-r--r--src/bootstrap/src/core/build_steps/run.rs4
-rw-r--r--src/bootstrap/src/core/build_steps/setup.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs43
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs50
-rw-r--r--src/bootstrap/src/core/builder/cargo.rs2
-rw-r--r--src/bootstrap/src/core/builder/mod.rs37
-rw-r--r--src/bootstrap/src/core/builder/tests.rs20
-rw-r--r--src/bootstrap/src/core/config/config.rs235
-rw-r--r--src/bootstrap/src/core/config/flags.rs5
-rw-r--r--src/bootstrap/src/core/config/tests.rs4
-rw-r--r--src/bootstrap/src/core/config/toml/build.rs11
-rw-r--r--src/bootstrap/src/core/config/toml/mod.rs2
-rw-r--r--src/bootstrap/src/core/config/toml/rust.rs9
-rw-r--r--src/bootstrap/src/core/config/toml/target.rs4
-rw-r--r--src/bootstrap/src/core/download.rs93
-rw-r--r--src/bootstrap/src/core/sanity.rs12
-rw-r--r--src/bootstrap/src/lib.rs187
-rw-r--r--src/bootstrap/src/utils/cc_detect.rs6
-rw-r--r--src/bootstrap/src/utils/cc_detect/tests.rs2
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-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.rs204
-rw-r--r--src/bootstrap/src/utils/mod.rs1
-rw-r--r--src/bootstrap/src/utils/render_tests.rs3
-rw-r--r--src/build_helper/src/lib.rs1
-rw-r--r--src/build_helper/src/targets.rs11
-rw-r--r--src/ci/docker/host-x86_64/mingw-check-2/Dockerfile5
-rw-r--r--src/doc/rustc-dev-guide/rust-version2
-rw-r--r--src/doc/rustc-dev-guide/src/git.md3
-rw-r--r--src/doc/rustc-dev-guide/src/tests/compiletest.md2
-rw-r--r--src/doc/rustc-dev-guide/src/tests/directives.md1
-rw-r--r--src/doc/rustc/src/platform-support.md38
-rw-r--r--src/doc/rustc/src/platform-support/loongarch-none.md4
-rw-r--r--src/doc/unstable-book/src/compiler-flags/macro-stats.md24
-rw-r--r--src/doc/unstable-book/src/language-features/asm-experimental-arch.md5
-rw-r--r--src/etc/completions/x.fish46
-rw-r--r--src/etc/completions/x.ps146
-rw-r--r--src/etc/completions/x.py.fish46
-rw-r--r--src/etc/completions/x.py.ps146
-rw-r--r--src/etc/completions/x.py.zsh46
-rw-r--r--src/etc/completions/x.zsh46
-rw-r--r--src/librustdoc/clean/auto_trait.rs4
-rw-r--r--src/librustdoc/clean/blanket_impl.rs6
-rw-r--r--src/librustdoc/clean/cfg.rs29
-rw-r--r--src/librustdoc/clean/inline.rs69
-rw-r--r--src/librustdoc/clean/mod.rs14
-rw-r--r--src/librustdoc/clean/types.rs2
-rw-r--r--src/librustdoc/json/mod.rs5
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/CHANGELOG.md5
-rw-r--r--src/tools/clippy/clippy_dev/src/update_lints.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/booleans.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/utils.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/checked_conversions.rs60
-rw-r--r--src/tools/clippy/clippy_lints/src/cloned_ref_to_slice_refs.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/coerce_container_to_any.rs108
-rw-r--r--src/tools/clippy/clippy_lints/src/copies.rs51
-rw-r--r--src/tools/clippy/clippy_lints/src/create_dir.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/ctfe.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/default.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_names.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_types.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs113
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs40
-rw-r--r--src/tools/clippy/clippy_lints/src/endian_bytes.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/format_args.rs124
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/if_let_mutex.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/infallible_try_from.rs76
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_clamp.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_string_new.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/match_result_ok.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/ip_constant.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/open_options.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_splitn.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/non_canonical_impls.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_block.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/serde_api.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/std_instead_of_core.rs79
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/swap.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/types/borrowed_box.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs124
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_io_amount.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_result_ok.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_unit.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/vec_init_then_push.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs64
-rw-r--r--src/tools/clippy/clippy_lints/src/zombie_processes.rs26
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs2
-rw-r--r--src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs2
-rw-r--r--src/tools/clippy/clippy_utils/README.md2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs15
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs12
-rw-r--r--src/tools/clippy/clippy_utils/src/sym.rs22
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/mod.rs37
-rw-r--r--src/tools/clippy/rust-toolchain.toml2
-rw-r--r--src/tools/clippy/tests/compile-test.rs8
-rw-r--r--src/tools/clippy/tests/symbols-used.rs81
-rw-r--r--src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs1
-rw-r--r--src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr6
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs37
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr17
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs31
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr17
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs39
-rw-r--r--src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr28
-rw-r--r--src/tools/clippy/tests/ui/cmp_null.fixed6
-rw-r--r--src/tools/clippy/tests/ui/cmp_null.rs6
-rw-r--r--src/tools/clippy/tests/ui/cmp_null.stderr8
-rw-r--r--src/tools/clippy/tests/ui/coerce_container_to_any.fixed26
-rw-r--r--src/tools/clippy/tests/ui/coerce_container_to_any.rs26
-rw-r--r--src/tools/clippy/tests/ui/coerce_container_to_any.stderr23
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-14935.rs27
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-9463.rs7
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-9463.stderr29
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-rust-107877.rs1
-rw-r--r--src/tools/clippy/tests/ui/create_dir.fixed23
-rw-r--r--src/tools/clippy/tests/ui/create_dir.rs19
-rw-r--r--src/tools/clippy/tests/ui/create_dir.stderr43
-rw-r--r--src/tools/clippy/tests/ui/disallowed_names.rs15
-rw-r--r--src/tools/clippy/tests/ui/disallowed_names.stderr28
-rw-r--r--src/tools/clippy/tests/ui/doc_suspicious_footnotes.fixed186
-rw-r--r--src/tools/clippy/tests/ui/doc_suspicious_footnotes.rs162
-rw-r--r--src/tools/clippy/tests/ui/doc_suspicious_footnotes.stderr179
-rw-r--r--src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.rs4
-rw-r--r--src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.stderr17
-rw-r--r--src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.txt13
-rw-r--r--src/tools/clippy/tests/ui/format_args.fixed10
-rw-r--r--src/tools/clippy/tests/ui/format_args.rs10
-rw-r--r--src/tools/clippy/tests/ui/indexing_slicing_index.rs1
-rw-r--r--src/tools/clippy/tests/ui/indexing_slicing_index.stderr31
-rw-r--r--src/tools/clippy/tests/ui/infallible_try_from.rs33
-rw-r--r--src/tools/clippy/tests/ui/infallible_try_from.stderr23
-rw-r--r--src/tools/clippy/tests/ui/ip_constant.fixed107
-rw-r--r--src/tools/clippy/tests/ui/ip_constant.rs127
-rw-r--r--src/tools/clippy/tests/ui/ip_constant.stderr338
-rw-r--r--src/tools/clippy/tests/ui/ip_constant_from_external.rs12
-rw-r--r--src/tools/clippy/tests/ui/ip_constant_from_external.stderr16
-rw-r--r--src/tools/clippy/tests/ui/localhost.txt1
-rw-r--r--src/tools/clippy/tests/ui/manual_flatten.fixed148
-rw-r--r--src/tools/clippy/tests/ui/manual_flatten.rs39
-rw-r--r--src/tools/clippy/tests/ui/manual_flatten.stderr139
-rw-r--r--src/tools/clippy/tests/ui/manual_swap_auto_fix.fixed11
-rw-r--r--src/tools/clippy/tests/ui/manual_swap_auto_fix.rs14
-rw-r--r--src/tools/clippy/tests/ui/manual_swap_auto_fix.stderr11
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding.fixed16
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding.rs18
-rw-r--r--src/tools/clippy/tests/ui/match_single_binding.stderr35
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed36
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs36
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr17
-rw-r--r--src/tools/clippy/tests/ui/needless_lifetimes.fixed2
-rw-r--r--src/tools/clippy/tests/ui/needless_lifetimes.rs2
-rw-r--r--src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed16
-rw-r--r--src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs18
-rw-r--r--src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr15
-rw-r--r--src/tools/clippy/tests/ui/pointer_format.rs66
-rw-r--r--src/tools/clippy/tests/ui/pointer_format.stderr47
-rw-r--r--src/tools/clippy/tests/ui/print_literal.fixed11
-rw-r--r--src/tools/clippy/tests/ui/print_literal.rs11
-rw-r--r--src/tools/clippy/tests/ui/print_literal.stderr50
-rw-r--r--src/tools/clippy/tests/ui/semicolon_outside_block.fixed25
-rw-r--r--src/tools/clippy/tests/ui/semicolon_outside_block.rs25
-rw-r--r--src/tools/clippy/tests/ui/std_instead_of_core.fixed6
-rw-r--r--src/tools/clippy/tests/ui/std_instead_of_core.rs6
-rw-r--r--src/tools/clippy/tests/ui/unit_arg.rs24
-rw-r--r--src/tools/clippy/tests/ui/unit_arg.stderr23
-rw-r--r--src/tools/clippy/tests/ui/unit_arg_empty_blocks.fixed34
-rw-r--r--src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs31
-rw-r--r--src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr46
-rw-r--r--src/tools/clippy/tests/ui/unit_arg_fixable.fixed78
-rw-r--r--src/tools/clippy/tests/ui/unit_arg_fixable.rs71
-rw-r--r--src/tools/clippy/tests/ui/unit_arg_fixable.stderr110
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.edition2021.fixed8
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.edition2024.fixed8
-rw-r--r--src/tools/clippy/tests/ui/unused_unit.rs8
-rw-r--r--src/tools/clippy/tests/ui/write_literal.fixed12
-rw-r--r--src/tools/clippy/tests/ui/write_literal.rs12
-rw-r--r--src/tools/clippy/tests/ui/write_literal.stderr50
-rw-r--r--src/tools/clippy/tests/ui/zombie_processes.rs10
-rw-r--r--src/tools/clippy/util/gh-pages/script.js2
-rw-r--r--src/tools/compiletest/src/directive-list.rs1
-rw-r--r--src/tools/compiletest/src/header/needs.rs5
-rw-r--r--src/tools/compiletest/src/header/tests.rs11
-rw-r--r--src/tools/miri/README.md5
-rw-r--r--src/tools/miri/src/bin/miri.rs2
-rw-r--r--src/tools/miri/src/eval.rs3
-rw-r--r--src/tools/miri/src/intrinsics/mod.rs16
-rw-r--r--src/tools/miri/src/intrinsics/simd.rs7
-rw-r--r--src/tools/miri/src/machine.rs5
-rw-r--r--src/tools/miri/src/math.rs4
-rw-r--r--src/tools/miri/src/operator.rs9
-rw-r--r--src/tools/rust-analyzer/.github/workflows/autopublish.yaml6
-rw-r--r--src/tools/rust-analyzer/.github/workflows/publish-libs.yaml2
-rw-r--r--src/tools/rust-analyzer/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/db.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs20
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs253
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs48
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/diagnostics.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs379
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs28
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs37
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs102
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs102
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs147
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_underscore.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs77
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/diagnostic.rs60
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs78
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/rename.rs200
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs157
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/expand_macro.rs61
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs64
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs15
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/implied_dyn_trait.rs133
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/rename.rs238
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs11
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs7
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/types.rs14
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs8
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rast15
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/angled_path_without_qual.rast42
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_bounds_macro_call_recovery.rast112
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_bounds_macro_call_recovery.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/call_expr.rast46
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/closure_binder.rast36
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/closure_binder.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lambda_expr.rast30
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/qual_paths.rast62
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_path_in_pattern.rast9
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_clause.rast31
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0036_fully_qualified.rast31
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0042_ufcs_call_list.rast15
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast31
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs133
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs137
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs168
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs6
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs14
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs3
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs10
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs1
-rw-r--r--src/tools/rust-analyzer/crates/syntax/rust.ungram7
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs66
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs23
-rw-r--r--src/tools/rust-analyzer/crates/test-fixture/src/lib.rs69
-rw-r--r--src/tools/rust-analyzer/docs/book/src/non_cargo_based_projects.md2
-rw-r--r--src/tools/rust-analyzer/editors/code/package-lock.json6
-rw-r--r--src/tools/rust-analyzer/rust-version2
-rw-r--r--src/tools/rustbook/Cargo.lock180
-rw-r--r--src/tools/tidy/src/deps.rs1
-rw-r--r--tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs31
-rw-r--r--tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs (renamed from tests/codegen/dont-shuffle-bswaps.rs)30
-rw-r--r--tests/codegen/retpoline.rs29
-rw-r--r--tests/crashes/139825.rs5
-rw-r--r--tests/debuginfo/type-names.rs4
-rw-r--r--tests/incremental/hashes/trait_defs.rs4
-rw-r--r--tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff5
-rw-r--r--tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff5
-rw-r--r--tests/mir-opt/early_otherwise_branch.opt5.EarlyOtherwiseBranch.diff3
-rw-r--r--tests/mir-opt/early_otherwise_branch.rs33
-rw-r--r--tests/mir-opt/early_otherwise_branch.target_self.EarlyOtherwiseBranch.diff28
-rw-r--r--tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff5
-rw-r--r--tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-abort.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-unwind.diff2
-rw-r--r--tests/mir-opt/lower_intrinsics.rs2
-rw-r--r--tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir2
-rw-r--r--tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir2
-rw-r--r--tests/pretty/postfix-match/precedence.pp2
-rw-r--r--tests/run-make/cpp-global-destructors/rmake.rs6
-rw-r--r--tests/run-make/export-executable-symbols/rmake.rs3
-rw-r--r--tests/run-make/incr-foreign-head-span/rmake.rs5
-rw-r--r--tests/run-make/incr-prev-body-beyond-eof/rmake.rs6
-rw-r--r--tests/run-make/incr-test-moved-file/rmake.rs5
-rw-r--r--tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs5
-rw-r--r--tests/rustdoc-json/fn_pointer/abi.rs9
-rw-r--r--tests/rustdoc-json/fns/abi.rs9
-rw-r--r--tests/rustdoc-json/methods/abi.rs17
-rw-r--r--tests/rustdoc-json/vectorcall.rs27
-rw-r--r--tests/rustdoc/cfg-bool.rs10
-rw-r--r--tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html4
-rw-r--r--tests/rustdoc/macro/macro-generated-macro.rs2
-rw-r--r--tests/ui-fulldeps/pprust-parenthesis-insertion.rs4
-rw-r--r--tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr14
-rw-r--r--tests/ui-fulldeps/stable-mir/check_abi.rs37
-rw-r--r--tests/ui-fulldeps/stable-mir/closure-generic-body.rs90
-rw-r--r--tests/ui-fulldeps/stable-mir/closure_body.rs90
-rw-r--r--tests/ui/abi/bad-custom.rs121
-rw-r--r--tests/ui/abi/bad-custom.stderr299
-rw-r--r--tests/ui/abi/custom.rs88
-rw-r--r--tests/ui/abi/unsupported.aarch64.stderr86
-rw-r--r--tests/ui/abi/unsupported.arm.stderr86
-rw-r--r--tests/ui/abi/unsupported.i686.stderr12
-rw-r--r--tests/ui/abi/unsupported.riscv32.stderr86
-rw-r--r--tests/ui/abi/unsupported.riscv64.stderr86
-rw-r--r--tests/ui/abi/unsupported.rs8
-rw-r--r--tests/ui/abi/unsupported.x64.stderr78
-rw-r--r--tests/ui/abi/unsupported.x64_win.stderr144
-rw-r--r--tests/ui/async-await/async-block-control-flow-static-semantics.stderr32
-rw-r--r--tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr16
-rw-r--r--tests/ui/async-await/issues/issue-63388-1.stderr9
-rw-r--r--tests/ui/auxiliary/typeid-intrinsic-aux1.rs6
-rw-r--r--tests/ui/auxiliary/typeid-intrinsic-aux2.rs6
-rw-r--r--tests/ui/box/empty-alloc-deref-rvalue.rs10
-rw-r--r--tests/ui/cfg/cfg-false-use-item.rs (renamed from tests/ui/filter-block-view-items.rs)2
-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/check-cfg/target_feature.stderr3
-rw-r--r--tests/ui/const-generics/const-arg-in-const-arg.min.stderr8
-rw-r--r--tests/ui/const-generics/defaults/complex-generic-default-expr.min.stderr2
-rw-r--r--tests/ui/const-generics/early/const_arg_trivial_macro_expansion-4.stderr6
-rw-r--r--tests/ui/const-generics/early/macro_rules-braces.stderr8
-rw-r--r--tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces-2.stderr2
-rw-r--r--tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces.stderr2
-rw-r--r--tests/ui/const-generics/early/trivial-const-arg-nested-braces.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr4
-rw-r--r--tests/ui/const-generics/generic_const_exprs/bad-multiply.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/feature-gate-generic_const_exprs.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-72787.min.stderr8
-rw-r--r--tests/ui/const-generics/generic_const_exprs/issue-72819-generic-in-const-eval.min.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.full.stderr13
-rw-r--r--tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.min.stderr11
-rw-r--r--tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.rs19
-rw-r--r--tests/ui/const-generics/issues/issue-68366.min.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-76701-ty-param-in-const.stderr2
-rw-r--r--tests/ui/const-generics/issues/issue-80375.stderr2
-rw-r--r--tests/ui/const-generics/legacy-const-generics-bad.stderr2
-rw-r--r--tests/ui/const-generics/min_const_generics/complex-expression.stderr8
-rw-r--r--tests/ui/const-generics/repeat_expr_hack_gives_right_generics.stderr4
-rw-r--r--tests/ui/consts/auxiliary/unstable_intrinsic.rs2
-rw-r--r--tests/ui/consts/const-adt-align-mismatch.rs2
-rw-r--r--tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs4
-rw-r--r--tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr4
-rw-r--r--tests/ui/consts/const-unstable-intrinsic.rs6
-rw-r--r--tests/ui/consts/const-unstable-intrinsic.stderr14
-rw-r--r--tests/ui/consts/gate-do-not-const-check.rs4
-rw-r--r--tests/ui/consts/gate-do-not-const-check.stderr5
-rw-r--r--tests/ui/coroutine/auto-trait-regions.stderr4
-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/derives/copy-drop-mutually-exclusive.rs (renamed from tests/ui/exclusive-drop-and-copy.rs)2
-rw-r--r--tests/ui/derives/copy-drop-mutually-exclusive.stderr (renamed from tests/ui/exclusive-drop-and-copy.stderr)4
-rw-r--r--tests/ui/diagnostic_namespace/multiline_spans.rs55
-rw-r--r--tests/ui/diagnostic_namespace/multiline_spans.stderr71
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs19
-rw-r--r--tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr114
-rw-r--r--tests/ui/drop/explicit-drop-call-error.fixed (renamed from tests/ui/illegal-ufcs-drop.fixed)2
-rw-r--r--tests/ui/drop/explicit-drop-call-error.rs (renamed from tests/ui/illegal-ufcs-drop.rs)2
-rw-r--r--tests/ui/drop/explicit-drop-call-error.stderr (renamed from tests/ui/illegal-ufcs-drop.stderr)2
-rw-r--r--tests/ui/editions/edition-keywords-2018-2015-parsing.stderr8
-rw-r--r--tests/ui/editions/edition-keywords-2018-2018-parsing.stderr16
-rw-r--r--tests/ui/editions/unsafe-attr-edition-span.e2024.stderr24
-rw-r--r--tests/ui/editions/unsafe-attr-edition-span.rs27
-rw-r--r--tests/ui/empty-allocation-rvalue-non-null.rs7
-rw-r--r--tests/ui/empty-type-parameter-list.rs24
-rw-r--r--tests/ui/enum/dead-code-associated-function.rs20
-rw-r--r--tests/ui/enum/dead-code-associated-function.stderr30
-rw-r--r--tests/ui/error-should-say-copy-not-pod.rs7
-rw-r--r--tests/ui/error-should-say-copy-not-pod.stderr22
-rw-r--r--tests/ui/explicit-i-suffix.rs13
-rw-r--r--tests/ui/ext-nonexistent.rs2
-rw-r--r--tests/ui/ext-nonexistent.stderr8
-rw-r--r--tests/ui/fact.rs26
-rw-r--r--tests/ui/feature-gates/feature-gate-abi-custom.rs51
-rw-r--r--tests/ui/feature-gates/feature-gate-abi-custom.stderr117
-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/feature-gate-pattern-complexity-limit.rs4
-rw-r--r--tests/ui/feature-gates/feature-gate-pattern-complexity-limit.stderr5
-rw-r--r--tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs12
-rw-r--r--tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr14
-rw-r--r--tests/ui/feature-gates/feature-gate-rustc-attrs.rs6
-rw-r--r--tests/ui/feature-gates/feature-gate-rustc-attrs.stderr15
-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/issue-43106-gating-of-builtin-attrs-error.rs6
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr75
-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/fmt/format-macro-no-std.rs (renamed from tests/ui/format-no-std.rs)7
-rw-r--r--tests/ui/force-inlining/gate.rs8
-rw-r--r--tests/ui/force-inlining/gate.stderr12
-rw-r--r--tests/ui/fun-indirect-call.rs9
-rw-r--r--tests/ui/future-incompatible-lint-group.rs15
-rw-r--r--tests/ui/future-incompatible-lint-group.stderr43
-rw-r--r--tests/ui/generics/empty-generic-brackets-equiv.rs27
-rw-r--r--tests/ui/generics/empty-generic-brackets-equiv.stderr (renamed from tests/ui/empty-type-parameter-list.stderr)2
-rw-r--r--tests/ui/global-scope.rs13
-rw-r--r--tests/ui/hello.rs10
-rw-r--r--tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr21
-rw-r--r--tests/ui/impl-trait/auto-trait-selection.next.stderr21
-rw-r--r--tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr2
-rw-r--r--tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs2
-rw-r--r--tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr9
-rw-r--r--tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr2
-rw-r--r--tests/ui/impl-trait/recursive-coroutine-boxed.rs3
-rw-r--r--tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr8
-rw-r--r--tests/ui/impl-trait/recursive-in-exhaustiveness.rs2
-rw-r--r--tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr8
-rw-r--r--tests/ui/impl-trait/two_tait_defining_each_other2.rs2
-rw-r--r--tests/ui/include-macros/parent_dir.rs2
-rw-r--r--tests/ui/include-macros/parent_dir.stderr17
-rw-r--r--tests/ui/inline-const/break-inside-inline-const-issue-128604.rs6
-rw-r--r--tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr32
-rw-r--r--tests/ui/inline-const/cross-const-control-flow-125846.stderr20
-rw-r--r--tests/ui/intrinsics/intrinsic-alignment.rs10
-rw-r--r--tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr4
-rw-r--r--tests/ui/issues/issue-13058.stderr8
-rw-r--r--tests/ui/issues/issue-14285.stderr8
-rw-r--r--tests/ui/issues/issue-15034.stderr7
-rw-r--r--tests/ui/issues/issue-28561.rs1
-rw-r--r--tests/ui/issues/issue-3154.stderr7
-rw-r--r--tests/ui/issues/issue-40288-2.stderr16
-rw-r--r--tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr2
-rw-r--r--tests/ui/lifetimes/lifetime-errors/42701_one_named_and_one_anonymous.stderr8
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.stderr8
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-2.stderr7
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-3.stderr7
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr7
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr7
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else.stderr7
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.stderr7
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.stderr8
-rw-r--r--tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.stderr7
-rw-r--r--tests/ui/lifetimes/noisy-follow-up-erro.stderr9
-rw-r--r--tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs12
-rw-r--r--tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr21
-rw-r--r--tests/ui/lint/expansion-time.rs4
-rw-r--r--tests/ui/lint/expansion-time.stderr33
-rw-r--r--tests/ui/lint/fn-ptr-comparisons-some.rs2
-rw-r--r--tests/ui/lint/fn-ptr-comparisons-some.stderr13
-rw-r--r--tests/ui/lint/fn-ptr-comparisons-weird.rs22
-rw-r--r--tests/ui/lint/fn-ptr-comparisons-weird.stderr47
-rw-r--r--tests/ui/lint/fn-ptr-comparisons.fixed2
-rw-r--r--tests/ui/lint/fn-ptr-comparisons.rs2
-rw-r--r--tests/ui/lint/fn-ptr-comparisons.stderr24
-rw-r--r--tests/ui/lint/future-incompatible-lint-group.rs30
-rw-r--r--tests/ui/lint/future-incompatible-lint-group.stderr37
-rw-r--r--tests/ui/loops/issue-43162.stderr12
-rw-r--r--tests/ui/macros/auxiliary/serde.rs19
-rw-r--r--tests/ui/macros/issue-39404.rs6
-rw-r--r--tests/ui/macros/issue-39404.stderr26
-rw-r--r--tests/ui/macros/macro-match-nonterminal.rs2
-rw-r--r--tests/ui/macros/macro-match-nonterminal.stderr39
-rw-r--r--tests/ui/macros/macro-missing-fragment-deduplication.rs6
-rw-r--r--tests/ui/macros/macro-missing-fragment-deduplication.stderr26
-rw-r--r--tests/ui/macros/macro-missing-fragment.e2015.stderr85
-rw-r--r--tests/ui/macros/macro-missing-fragment.rs24
-rw-r--r--tests/ui/macros/macro-missing-fragment.stderr (renamed from tests/ui/macros/macro-missing-fragment.e2024.stderr)14
-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/macros/missing-derive-1.rs33
-rw-r--r--tests/ui/macros/missing-derive-1.stderr47
-rw-r--r--tests/ui/macros/missing-derive-2.rs26
-rw-r--r--tests/ui/macros/missing-derive-2.stderr47
-rw-r--r--tests/ui/macros/missing-derive-3.rs24
-rw-r--r--tests/ui/macros/missing-derive-3.stderr32
-rw-r--r--tests/ui/macros/nested-macro-expansion.rs (renamed from tests/ui/ext-expand-inner-exprs.rs)2
-rw-r--r--tests/ui/methods/inherent-methods-same-name.rs (renamed from tests/ui/impl-inherent-non-conflict.rs)11
-rw-r--r--tests/ui/methods/missing-bound-on-tuple.rs39
-rw-r--r--tests/ui/methods/missing-bound-on-tuple.stderr58
-rw-r--r--tests/ui/mir/mir_refs_correct.rs2
-rw-r--r--tests/ui/modules/impl-cross-module.rs (renamed from tests/ui/impl-not-adjacent-to-type.rs)2
-rw-r--r--tests/ui/nll/sugg-mut-for-binding-issue-137486.fixed23
-rw-r--r--tests/ui/nll/sugg-mut-for-binding-issue-137486.rs21
-rw-r--r--tests/ui/nll/sugg-mut-for-binding-issue-137486.stderr37
-rw-r--r--tests/ui/nullable-pointer-iotareduction.rs2
-rw-r--r--tests/ui/object-lifetime/object-lifetime-default-from-box-error.stderr8
-rw-r--r--tests/ui/on-unimplemented/feature-gate-on-unimplemented.rs7
-rw-r--r--tests/ui/on-unimplemented/feature-gate-on-unimplemented.stderr5
-rw-r--r--tests/ui/parser/block-no-opening-brace.rs4
-rw-r--r--tests/ui/parser/block-no-opening-brace.stderr6
-rw-r--r--tests/ui/parser/macro/issue-33569.rs1
-rw-r--r--tests/ui/parser/macro/issue-33569.stderr24
-rw-r--r--tests/ui/parser/misspelled-keywords/async-move.stderr4
-rw-r--r--tests/ui/print-calling-conventions.stdout1
-rw-r--r--tests/ui/proc-macro/derive-helper-legacy-limits.stderr6
-rw-r--r--tests/ui/proc-macro/derive-helper-shadowing.stderr2
-rw-r--r--tests/ui/proc-macro/disappearing-resolution.stderr6
-rw-r--r--tests/ui/regions/regions-glb-free-free.stderr7
-rw-r--r--tests/ui/regions/regions-infer-at-fn-not-param.stderr9
-rw-r--r--tests/ui/resolve/auxiliary/issue-80079.rs2
-rw-r--r--tests/ui/resolve/auxiliary/privacy-struct-ctor.rs2
-rw-r--r--tests/ui/resolve/extern-prelude-fail.rs1
-rw-r--r--tests/ui/resolve/extern-prelude-fail.stderr4
-rw-r--r--tests/ui/resolve/global-scope-resolution.rs21
-rw-r--r--tests/ui/resolve/issue-42944.rs2
-rw-r--r--tests/ui/resolve/issue-5035.rs2
-rw-r--r--tests/ui/resolve/issue-5035.stderr6
-rw-r--r--tests/ui/resolve/nonexistent-macro.rs6
-rw-r--r--tests/ui/resolve/nonexistent-macro.stderr8
-rw-r--r--tests/ui/resolve/privacy-enum-ctor.rs4
-rw-r--r--tests/ui/resolve/privacy-enum-ctor.stderr38
-rw-r--r--tests/ui/resolve/privacy-struct-ctor.rs4
-rw-r--r--tests/ui/resolve/privacy-struct-ctor.stderr34
-rw-r--r--tests/ui/resolve/resolve-bad-visibility.rs1
-rw-r--r--tests/ui/resolve/resolve-bad-visibility.stderr10
-rw-r--r--tests/ui/resolve/suggest-builder-fn.rs2
-rw-r--r--tests/ui/resolve/unresolved-segments-visibility.rs2
-rw-r--r--tests/ui/resolve/unresolved-segments-visibility.stderr6
-rw-r--r--tests/ui/rust-2018/edition-lint-fully-qualified-paths.fixed1
-rw-r--r--tests/ui/rust-2018/edition-lint-fully-qualified-paths.rs1
-rw-r--r--tests/ui/rust-2018/edition-lint-fully-qualified-paths.stderr8
-rw-r--r--tests/ui/rust-2018/edition-lint-nested-empty-paths.fixed1
-rw-r--r--tests/ui/rust-2018/edition-lint-nested-empty-paths.rs1
-rw-r--r--tests/ui/rust-2018/edition-lint-nested-empty-paths.stderr12
-rw-r--r--tests/ui/rust-2018/edition-lint-nested-paths.fixed1
-rw-r--r--tests/ui/rust-2018/edition-lint-nested-paths.rs1
-rw-r--r--tests/ui/rust-2018/edition-lint-nested-paths.stderr10
-rw-r--r--tests/ui/rust-2018/edition-lint-paths.fixed1
-rw-r--r--tests/ui/rust-2018/edition-lint-paths.rs1
-rw-r--r--tests/ui/rust-2018/edition-lint-paths.stderr20
-rw-r--r--tests/ui/rust-2018/extern-crate-rename.fixed1
-rw-r--r--tests/ui/rust-2018/extern-crate-rename.rs1
-rw-r--r--tests/ui/rust-2018/extern-crate-rename.stderr4
-rw-r--r--tests/ui/rust-2018/extern-crate-submod.fixed1
-rw-r--r--tests/ui/rust-2018/extern-crate-submod.rs1
-rw-r--r--tests/ui/rust-2018/extern-crate-submod.stderr4
-rw-r--r--tests/ui/rust-2018/try-ident.fixed1
-rw-r--r--tests/ui/rust-2018/try-ident.rs1
-rw-r--r--tests/ui/rust-2018/try-ident.stderr6
-rw-r--r--tests/ui/rust-2018/try-macro.fixed1
-rw-r--r--tests/ui/rust-2018/try-macro.rs1
-rw-r--r--tests/ui/rust-2018/try-macro.stderr4
-rw-r--r--tests/ui/rustdoc/feature-gate-doc_primitive.rs4
-rw-r--r--tests/ui/rustdoc/feature-gate-doc_primitive.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/self/self-shadowing-import.rs2
-rw-r--r--tests/ui/sepcomp/auxiliary/sepcomp_lib.rs4
-rw-r--r--tests/ui/sepcomp/sepcomp-extern.rs4
-rw-r--r--tests/ui/sepcomp/sepcomp-fns-backwards.rs4
-rw-r--r--tests/ui/sepcomp/sepcomp-fns.rs4
-rw-r--r--tests/ui/sepcomp/sepcomp-statics.rs4
-rw-r--r--tests/ui/sepcomp/sepcomp-unwind.rs4
-rw-r--r--tests/ui/shadowed-use-visibility.rs2
-rw-r--r--tests/ui/shadowed/shadowed-trait-methods.rs2
-rw-r--r--tests/ui/shadowed/shadowed-use-visibility.rs8
-rw-r--r--tests/ui/shadowed/shadowed-use-visibility.stderr14
-rw-r--r--tests/ui/simd/size-align.rs8
-rw-r--r--tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs2
-rw-r--r--tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr4
-rw-r--r--tests/ui/span/dropck_arr_cycle_checked.rs2
-rw-r--r--tests/ui/span/dropck_vec_cycle_checked.rs2
-rw-r--r--tests/ui/span/vec-must-not-hide-type-from-dropck.rs2
-rw-r--r--tests/ui/span/visibility-ty-params.rs6
-rw-r--r--tests/ui/span/visibility-ty-params.stderr18
-rw-r--r--tests/ui/stability-attribute/auxiliary/pub-and-stability.rs (renamed from tests/ui/auxiliary/pub-and-stability.rs)0
-rw-r--r--tests/ui/stability-attribute/renamed_feature.rs3
-rw-r--r--tests/ui/stability-attribute/renamed_feature.stderr9
-rw-r--r--tests/ui/stability-attribute/stability-privacy-interaction.rs (renamed from tests/ui/explore-issue-38412.rs)34
-rw-r--r--tests/ui/stability-attribute/stability-privacy-interaction.stderr (renamed from tests/ui/explore-issue-38412.stderr)42
-rw-r--r--tests/ui/static/auxiliary/static_priv_by_default.rs10
-rw-r--r--tests/ui/static/static-extern-type.rs4
-rw-r--r--tests/ui/statics/auxiliary/static_fn_inline_xc_aux.rs2
-rw-r--r--tests/ui/statics/auxiliary/static_fn_trait_xc_aux.rs2
-rw-r--r--tests/ui/statics/static-impl.rs4
-rw-r--r--tests/ui/stats/auxiliary/include.rs3
-rw-r--r--tests/ui/stats/input-stats.stderr4
-rw-r--r--tests/ui/stats/macro-stats.rs130
-rw-r--r--tests/ui/stats/macro-stats.stderr26
-rw-r--r--tests/ui/structs-enums/enum-alignment.rs2
-rw-r--r--tests/ui/structs-enums/issue-2718-a.rs2
-rw-r--r--tests/ui/structs-enums/namespaced-enum-glob-import.rs2
-rw-r--r--tests/ui/structs-enums/rec-align-u32.rs4
-rw-r--r--tests/ui/structs-enums/rec-align-u64.rs4
-rw-r--r--tests/ui/structs-enums/tag-align-dyn-u64.rs2
-rw-r--r--tests/ui/structs-enums/tag-align-dyn-variants.rs2
-rw-r--r--tests/ui/structs-enums/tag-align-u64.rs2
-rw-r--r--tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs7
-rw-r--r--tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr40
-rw-r--r--tests/ui/suggestions/ice-unwrap-probe-many-result-125876.rs1
-rw-r--r--tests/ui/suggestions/ice-unwrap-probe-many-result-125876.stderr8
-rw-r--r--tests/ui/suggestions/issue-116434-2015.rs2
-rw-r--r--tests/ui/suggestions/issue-116434-2015.stderr14
-rw-r--r--tests/ui/suggestions/issue-61963.rs1
-rw-r--r--tests/ui/suggestions/issue-61963.stderr6
-rw-r--r--tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr8
-rw-r--r--tests/ui/suggestions/missing-lifetime-specifier.rs10
-rw-r--r--tests/ui/suggestions/missing-lifetime-specifier.stderr55
-rw-r--r--tests/ui/symbol-names/impl1.rs2
-rw-r--r--tests/ui/symbol-names/issue-53912.rs10
-rw-r--r--tests/ui/symbol-names/issue-60925.rs10
-rw-r--r--tests/ui/target-feature/retpoline-target-feature-flag.by_feature.stderr7
-rw-r--r--tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr7
-rw-r--r--tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr7
-rw-r--r--tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr7
-rw-r--r--tests/ui/target-feature/retpoline-target-feature-flag.rs23
-rw-r--r--tests/ui/threads-sendsync/thread-local-syntax.rs2
-rw-r--r--tests/ui/tool-attributes/diagnostic_item.rs4
-rw-r--r--tests/ui/tool-attributes/diagnostic_item.stderr4
-rw-r--r--tests/ui/track-diagnostics/track.stderr2
-rw-r--r--tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.fixed1
-rw-r--r--tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.rs1
-rw-r--r--tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr2
-rw-r--r--tests/ui/traits/auxiliary/traitimpl.rs2
-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/traits/const-traits/inherent-impl.rs2
-rw-r--r--tests/ui/traits/const-traits/inherent-impl.stderr4
-rw-r--r--tests/ui/traits/const-traits/mbe-dyn-const-2015.rs1
-rw-r--r--tests/ui/traits/default-method/rustc_must_implement_one_of_gated.rs4
-rw-r--r--tests/ui/traits/default-method/rustc_must_implement_one_of_gated.stderr5
-rw-r--r--tests/ui/traits/impl-2.rs2
-rw-r--r--tests/ui/traits/item-privacy.rs18
-rw-r--r--tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs6
-rw-r--r--tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr15
-rw-r--r--tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs2
-rw-r--r--tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr6
-rw-r--r--tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.is_send.stderr13
-rw-r--r--tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.not_send.stderr13
-rw-r--r--tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.rs2
-rw-r--r--tests/ui/traits/static-method-overwriting.rs4
-rw-r--r--tests/ui/transmutability/references/reject_extension.stderr2
-rw-r--r--tests/ui/transmutability/references/unit-to-u8.stderr2
-rw-r--r--tests/ui/transmutability/references/unsafecell.rs12
-rw-r--r--tests/ui/transmutability/references/unsafecell.stderr32
-rw-r--r--tests/ui/tuple/tuple-struct-fields/test.rs2
-rw-r--r--tests/ui/tuple/tuple-struct-fields/test2.rs2
-rw-r--r--tests/ui/tuple/tuple-struct-fields/test3.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr6
-rw-r--r--tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs2
-rw-r--r--tests/ui/type-alias-impl-trait/nested-tait-inference2.next.stderr6
-rw-r--r--tests/ui/type-alias-impl-trait/nested-tait-inference2.rs2
-rw-r--r--tests/ui/type/auxiliary/crate_a1.rs4
-rw-r--r--tests/ui/type/auxiliary/crate_a2.rs2
-rw-r--r--tests/ui/type/issue-7607-2.rs2
-rw-r--r--tests/ui/type/pattern_types/matching.rs1
-rw-r--r--tests/ui/type/type-mismatch-same-crate-name.stderr2
-rw-r--r--tests/ui/typeck/issue-114529-illegal-break-with-value.stderr36
-rw-r--r--tests/ui/underscore-imports/basic.rs24
-rw-r--r--tests/ui/underscore-imports/basic.stderr12
-rw-r--r--tests/ui/unpretty/exhaustive.expanded.stdout2
-rw-r--r--tests/ui/unresolved/unresolved-import-recovery.rs2
-rw-r--r--tests/ui/unresolved/unresolved-import-recovery.stderr6
-rw-r--r--tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr12
-rw-r--r--tests/ui/unsized/unsized3-rpass.rs4
-rw-r--r--tests/ui/use/use-mod/use-mod-4.rs2
-rw-r--r--tests/ui/use/use-mod/use-mod-4.stderr20
-rw-r--r--tests/ui/variance/variance-trait-matching.stderr8
-rw-r--r--tests/ui/warnings/no-explicit-path-issue-122509.rs4
-rw-r--r--tests/ui/weird-exprs.rs2
-rw-r--r--tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs10
-rw-r--r--tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr90
-rw-r--r--triagebot.toml72
961 files changed, 16842 insertions, 8757 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e5054a07567..841bc39bf1e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -64,12 +64,18 @@ jobs:
         uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
         with:
           workspaces: src/ci/citool
+      - name: Test citool
+        # Only test citool on the auto branch, to reduce latency of the calculate matrix job
+        # on PR/try builds.
+        if: ${{ github.ref == 'refs/heads/auto' }}
+        run: |
+          cd src/ci/citool
+          CARGO_INCREMENTAL=0 cargo test
       - name: Calculate the CI job matrix
         env:
           COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
         run: |
           cd src/ci/citool
-          CARGO_INCREMENTAL=0 cargo test
           CARGO_INCREMENTAL=0 cargo run calculate-job-matrix >> $GITHUB_OUTPUT
         id: jobs
   job:
diff --git a/Cargo.lock b/Cargo.lock
index 93abab8469a..9c0978b92f7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -80,9 +80,9 @@ dependencies = [
 
 [[package]]
 name = "anstream"
-version = "0.6.18"
+version = "0.6.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
+checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933"
 dependencies = [
  "anstyle",
  "anstyle-parse",
@@ -95,58 +95,58 @@ dependencies = [
 
 [[package]]
 name = "anstyle"
-version = "1.0.10"
+version = "1.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
+checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
 
 [[package]]
 name = "anstyle-lossy"
-version = "1.1.3"
+version = "1.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "934ff8719effd2023a48cf63e69536c1c3ced9d3895068f6f5cc9a4ff845e59b"
+checksum = "04d3a5dc826f84d0ea11882bb8054ff7f3d482602e11bb181101303a279ea01f"
 dependencies = [
  "anstyle",
 ]
 
 [[package]]
 name = "anstyle-parse"
-version = "0.2.6"
+version = "0.2.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
+checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
 dependencies = [
  "utf8parse",
 ]
 
 [[package]]
 name = "anstyle-query"
-version = "1.1.2"
+version = "1.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
+checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9"
 dependencies = [
  "windows-sys 0.59.0",
 ]
 
 [[package]]
 name = "anstyle-svg"
-version = "0.1.7"
+version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3607949e9f6de49ea4bafe12f5e4fd73613ebf24795e48587302a8cc0e4bb35"
+checksum = "c681338396641f4e32a29f045d0c70950da7207b4376685b51396c481ee36f1a"
 dependencies = [
- "anstream",
  "anstyle",
  "anstyle-lossy",
+ "anstyle-parse",
  "html-escape",
  "unicode-width 0.2.0",
 ]
 
 [[package]]
 name = "anstyle-wincon"
-version = "3.0.7"
+version = "3.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
+checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882"
 dependencies = [
  "anstyle",
- "once_cell",
+ "once_cell_polyfill",
  "windows-sys 0.59.0",
 ]
 
@@ -266,9 +266,9 @@ dependencies = [
 
 [[package]]
 name = "bitflags"
-version = "2.9.0"
+version = "2.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
+checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
 
 [[package]]
 name = "blake3"
@@ -341,15 +341,15 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.17.0"
+version = "3.18.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
+checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
 
 [[package]]
 name = "bytecount"
-version = "0.6.8"
+version = "0.6.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce"
+checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e"
 
 [[package]]
 name = "bytes"
@@ -359,9 +359,9 @@ checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
 
 [[package]]
 name = "camino"
-version = "1.1.9"
+version = "1.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3"
+checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab"
 dependencies = [
  "serde",
 ]
@@ -487,9 +487,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.38"
+version = "4.5.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000"
+checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -507,9 +507,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.38"
+version = "4.5.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120"
+checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51"
 dependencies = [
  "anstream",
  "anstyle",
@@ -642,16 +642,16 @@ dependencies = [
 
 [[package]]
 name = "color-eyre"
-version = "0.6.4"
+version = "0.6.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6e1761c0e16f8883bbbb8ce5990867f4f06bf11a0253da6495a04ce4b6ef0ec"
+checksum = "e5920befb47832a6d61ee3a3a846565cfa39b331331e68a3b1d1116630f2f26d"
 dependencies = [
  "backtrace",
  "color-spantrace",
  "eyre",
  "indenter",
  "once_cell",
- "owo-colors 4.2.0",
+ "owo-colors 4.2.1",
  "tracing-error",
 ]
 
@@ -678,21 +678,21 @@ dependencies = [
 
 [[package]]
 name = "color-spantrace"
-version = "0.2.2"
+version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ddd8d5bfda1e11a501d0a7303f3bfed9aa632ebdb859be40d0fd70478ed70d5"
+checksum = "b8b88ea9df13354b55bc7234ebcce36e6ef896aca2e42a15de9e10edce01b427"
 dependencies = [
  "once_cell",
- "owo-colors 4.2.0",
+ "owo-colors 4.2.1",
  "tracing-core",
  "tracing-error",
 ]
 
 [[package]]
 name = "colorchoice"
-version = "1.0.3"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
+checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
 
 [[package]]
 name = "colored"
@@ -851,9 +851,9 @@ dependencies = [
 
 [[package]]
 name = "curl"
-version = "0.4.47"
+version = "0.4.48"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9fb4d13a1be2b58f14d60adba57c9834b78c62fd86c3e76a148f732686e9265"
+checksum = "9e2d5c8f48d9c0c23250e52b55e82a6ab4fdba6650c931f5a0a57a43abda812b"
 dependencies = [
  "curl-sys",
  "libc",
@@ -861,14 +861,14 @@ dependencies = [
  "openssl-sys",
  "schannel",
  "socket2",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
 name = "curl-sys"
-version = "0.4.80+curl-8.12.1"
+version = "0.4.82+curl-8.14.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55f7df2eac63200c3ab25bde3b2268ef2ee56af3d238e76d61f01c3c49bff734"
+checksum = "c4d63638b5ec65f1a4ae945287b3fd035be4554bbaf211901159c9a2a74fb5be"
 dependencies = [
  "cc",
  "libc",
@@ -876,7 +876,7 @@ dependencies = [
  "openssl-sys",
  "pkg-config",
  "vcpkg",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -1142,9 +1142,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
 
 [[package]]
 name = "errno"
-version = "0.3.11"
+version = "0.3.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
+checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
 dependencies = [
  "libc",
  "windows-sys 0.59.0",
@@ -1207,9 +1207,9 @@ dependencies = [
 
 [[package]]
 name = "flate2"
-version = "1.1.1"
+version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
+checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
 dependencies = [
  "crc32fast",
  "miniz_oxide",
@@ -1487,9 +1487,9 @@ dependencies = [
 
 [[package]]
 name = "hashbrown"
-version = "0.15.3"
+version = "0.15.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
+checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
 dependencies = [
  "allocator-api2",
  "equivalent",
@@ -1511,9 +1511,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
 
 [[package]]
 name = "hermit-abi"
-version = "0.3.9"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08"
 
 [[package]]
 name = "hex"
@@ -1700,9 +1700,9 @@ checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
 
 [[package]]
 name = "icu_properties"
-version = "2.0.0"
+version = "2.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a"
+checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
 dependencies = [
  "displaydoc",
  "icu_collections",
@@ -1716,9 +1716,9 @@ dependencies = [
 
 [[package]]
 name = "icu_properties_data"
-version = "2.0.0"
+version = "2.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04"
+checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
 
 [[package]]
 name = "icu_provider"
@@ -1933,9 +1933,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
 
 [[package]]
 name = "jiff"
-version = "0.2.13"
+version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f02000660d30638906021176af16b17498bd0d12813dbfe7b276d8bc7f3c0806"
+checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93"
 dependencies = [
  "jiff-static",
  "log",
@@ -1946,9 +1946,9 @@ dependencies = [
 
 [[package]]
 name = "jiff-static"
-version = "0.2.13"
+version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3c30758ddd7188629c6713fc45d1188af4f44c90582311d0c8d8c9907f60c48"
+checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2002,9 +2002,9 @@ dependencies = [
 
 [[package]]
 name = "jsonpath-rust"
-version = "1.0.1"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a37c2c87b8d16e788ce359660fead0ea5f4ed29ff400d55be74a4e01d1817d9"
+checksum = "5b37465feaf9d41f74df7da98c6c1c31ca8ea06d11b5bf7869c8f1ccc51a793f"
 dependencies = [
  "pest",
  "pest_derive",
@@ -2080,9 +2080,9 @@ dependencies = [
 
 [[package]]
 name = "libloading"
-version = "0.8.7"
+version = "0.8.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c"
+checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
 dependencies = [
  "cfg-if",
  "windows-targets 0.53.0",
@@ -2170,9 +2170,9 @@ dependencies = [
 
 [[package]]
 name = "lock_api"
-version = "0.4.12"
+version = "0.4.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
+checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
 dependencies = [
  "autocfg",
  "scopeguard",
@@ -2463,9 +2463,9 @@ dependencies = [
 
 [[package]]
 name = "num_cpus"
-version = "1.16.0"
+version = "1.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
+checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
 dependencies = [
  "hermit-abi",
  "libc",
@@ -2539,6 +2539,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
 
 [[package]]
+name = "once_cell_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
+
+[[package]]
 name = "opener"
 version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2558,9 +2564,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
 
 [[package]]
 name = "openssl-sys"
-version = "0.9.108"
+version = "0.9.109"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847"
+checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571"
 dependencies = [
  "cc",
  "libc",
@@ -2611,9 +2617,9 @@ checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
 
 [[package]]
 name = "owo-colors"
-version = "4.2.0"
+version = "4.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1036865bb9422d3300cf723f657c2851d0e9ab12567854b1f4eba3d77decf564"
+checksum = "26995317201fa17f3656c36716aed4a7c81743a9634ac4c99c0eeda495db0cec"
 
 [[package]]
 name = "pad"
@@ -2637,9 +2643,9 @@ dependencies = [
 
 [[package]]
 name = "parking_lot"
-version = "0.12.3"
+version = "0.12.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
+checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
 dependencies = [
  "lock_api",
  "parking_lot_core",
@@ -2647,9 +2653,9 @@ dependencies = [
 
 [[package]]
 name = "parking_lot_core"
-version = "0.9.10"
+version = "0.9.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
+checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
 dependencies = [
  "cfg-if",
  "libc",
@@ -2802,9 +2808,9 @@ dependencies = [
 
 [[package]]
 name = "portable-atomic"
-version = "1.11.0"
+version = "1.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
+checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
 
 [[package]]
 name = "portable-atomic-util"
@@ -3228,9 +3234,9 @@ dependencies = [
 
 [[package]]
 name = "rustc_apfloat"
-version = "0.2.2+llvm-462a31f5a5ab"
+version = "0.2.3+llvm-462a31f5a5ab"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "121e2195ff969977a4e2b5c9965ea867fce7e4cb5aee5b09dee698a7932d574f"
+checksum = "486c2179b4796f65bfe2ee33679acf0927ac83ecf583ad6c91c3b4570911b9ad"
 dependencies = [
  "bitflags",
  "smallvec",
@@ -3787,6 +3793,7 @@ dependencies = [
  "rustc_arena",
  "rustc_ast",
  "rustc_attr_data_structures",
+ "rustc_attr_parsing",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_feature",
@@ -4768,9 +4775,9 @@ dependencies = [
 
 [[package]]
 name = "rustversion"
-version = "1.0.20"
+version = "1.0.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
+checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
 
 [[package]]
 name = "ruzstd"
@@ -4866,9 +4873,9 @@ dependencies = [
 
 [[package]]
 name = "serde_spanned"
-version = "0.6.8"
+version = "0.6.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
+checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
 dependencies = [
  "serde",
 ]
@@ -4933,15 +4940,15 @@ dependencies = [
 
 [[package]]
 name = "smallvec"
-version = "1.15.0"
+version = "1.15.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
 
 [[package]]
 name = "socket2"
-version = "0.5.9"
+version = "0.5.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef"
+checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
 dependencies = [
  "libc",
  "windows-sys 0.52.0",
@@ -5111,9 +5118,9 @@ dependencies = [
 
 [[package]]
 name = "sysinfo"
-version = "0.35.0"
+version = "0.35.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b897c8ea620e181c7955369a31be5f48d9a9121cb59fd33ecef9ff2a34323422"
+checksum = "3c3ffa3e4ff2b324a57f7aeb3c349656c7b127c3c189520251a648102a92496e"
 dependencies = [
  "libc",
  "objc2-core-foundation",
@@ -5354,9 +5361,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
 
 [[package]]
 name = "tokio"
-version = "1.45.0"
+version = "1.45.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165"
+checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
 dependencies = [
  "backtrace",
  "bytes",
@@ -5386,9 +5393,9 @@ dependencies = [
 
 [[package]]
 name = "toml_datetime"
-version = "0.6.9"
+version = "0.6.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3"
+checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
 dependencies = [
  "serde",
 ]
@@ -5420,9 +5427,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-attributes"
-version = "0.1.28"
+version = "0.1.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
+checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -5504,11 +5511,11 @@ dependencies = [
 
 [[package]]
 name = "type-map"
-version = "0.5.0"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "deb68604048ff8fa93347f02441e4487594adc20bb8a084f9e564d2b827a0a9f"
+checksum = "cb30dbbd9036155e74adad6812e9898d03ec374946234fbcebd5dfc7b9187b90"
 dependencies = [
- "rustc-hash 1.1.0",
+ "rustc-hash 2.1.1",
 ]
 
 [[package]]
@@ -5729,11 +5736,13 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
 
 [[package]]
 name = "uuid"
-version = "1.16.0"
+version = "1.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
+checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
 dependencies = [
  "getrandom 0.3.3",
+ "js-sys",
+ "wasm-bindgen",
 ]
 
 [[package]]
@@ -5892,12 +5901,12 @@ dependencies = [
 
 [[package]]
 name = "wasm-encoder"
-version = "0.230.0"
+version = "0.233.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4349d0943718e6e434b51b9639e876293093dca4b96384fb136ab5bd5ce6660"
+checksum = "9679ae3cf7cfa2ca3a327f7fab97f27f3294d402fd1a76ca8ab514e17973e4d3"
 dependencies = [
  "leb128fmt",
- "wasmparser 0.230.0",
+ "wasmparser 0.233.0",
 ]
 
 [[package]]
@@ -5937,42 +5946,42 @@ dependencies = [
 
 [[package]]
 name = "wasmparser"
-version = "0.230.0"
+version = "0.232.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "808198a69b5a0535583370a51d459baa14261dfab04800c4864ee9e1a14346ed"
+checksum = "917739b33bb1eb0e9a49bcd2637a351931be4578d0cc4d37b908d7a797784fbb"
 dependencies = [
  "bitflags",
- "indexmap",
- "semver",
 ]
 
 [[package]]
 name = "wasmparser"
-version = "0.232.0"
+version = "0.233.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "917739b33bb1eb0e9a49bcd2637a351931be4578d0cc4d37b908d7a797784fbb"
+checksum = "b51cb03afce7964bbfce46602d6cb358726f36430b6ba084ac6020d8ce5bc102"
 dependencies = [
  "bitflags",
+ "indexmap",
+ "semver",
 ]
 
 [[package]]
 name = "wast"
-version = "230.0.0"
+version = "233.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8edac03c5fa691551531533928443faf3dc61a44f814a235c7ec5d17b7b34f1"
+checksum = "2eaf4099d8d0c922b83bf3c90663f5666f0769db9e525184284ebbbdb1dd2180"
 dependencies = [
  "bumpalo",
  "leb128fmt",
  "memchr",
  "unicode-width 0.2.0",
- "wasm-encoder 0.230.0",
+ "wasm-encoder 0.233.0",
 ]
 
 [[package]]
 name = "wat"
-version = "1.230.0"
+version = "1.233.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d77d62229e38db83eac32bacb5f61ebb952366ab0dae90cf2b3c07a65eea894"
+checksum = "3d9bc80f5e4b25ea086ef41b91ccd244adde45d931c384d94a8ff64ab8bd7d87"
 dependencies = [
  "wast",
 ]
@@ -6033,13 +6042,13 @@ dependencies = [
 
 [[package]]
 name = "windows-bindgen"
-version = "0.61.0"
+version = "0.61.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac1c59c20569610dd9ed784d5f003fb493ec57b4cf39d974eb03a84bb7156c90"
+checksum = "9b4e97b01190d32f268a2dfbd3f006f77840633746707fbe40bcee588108a231"
 dependencies = [
- "rayon",
  "serde",
  "serde_json",
+ "windows-threading",
 ]
 
 [[package]]
@@ -6053,9 +6062,9 @@ dependencies = [
 
 [[package]]
 name = "windows-core"
-version = "0.61.0"
+version = "0.61.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
+checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
 dependencies = [
  "windows-implement",
  "windows-interface",
@@ -6066,12 +6075,13 @@ dependencies = [
 
 [[package]]
 name = "windows-future"
-version = "0.2.0"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32"
+checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
 dependencies = [
  "windows-core",
  "windows-link",
+ "windows-threading",
 ]
 
 [[package]]
@@ -6114,18 +6124,18 @@ dependencies = [
 
 [[package]]
 name = "windows-result"
-version = "0.3.2"
+version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
+checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
 dependencies = [
  "windows-link",
 ]
 
 [[package]]
 name = "windows-strings"
-version = "0.4.0"
+version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
+checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
 dependencies = [
  "windows-link",
 ]
@@ -6205,6 +6215,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "windows-threading"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
 name = "windows_aarch64_gnullvm"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/bootstrap.example.toml b/bootstrap.example.toml
index 1371fd6442f..19cf360b0fb 100644
--- a/bootstrap.example.toml
+++ b/bootstrap.example.toml
@@ -381,6 +381,15 @@
 #    "miri", "cargo-miri" # for dev/nightly channels
 #]
 
+# Specify build configuration specific for some tool, such as enabled features.
+# This option has no effect on which tools are enabled: refer to the `tools` option for that.
+#
+# For example, to build Miri with tracing support, use `tool.miri.features = ["tracing"]`
+#
+# The default value for the `features` array is `[]`. However, please note that other flags in
+# `bootstrap.toml` might influence the features enabled for some tools.
+#tool.TOOL_NAME.features = [FEATURE1, FEATURE2]
+
 # Verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose, 3 == print environment variables on each rustc invocation
 #verbose = 0
 
diff --git a/compiler/rustc_abi/src/canon_abi.rs b/compiler/rustc_abi/src/canon_abi.rs
index 03eeb645489..7c020be6761 100644
--- a/compiler/rustc_abi/src/canon_abi.rs
+++ b/compiler/rustc_abi/src/canon_abi.rs
@@ -28,6 +28,9 @@ pub enum CanonAbi {
     Rust,
     RustCold,
 
+    /// An ABI that rustc does not know how to call or define.
+    Custom,
+
     /// ABIs relevant to 32-bit Arm targets
     Arm(ArmCall),
     /// ABI relevant to GPUs: the entry point for a GPU kernel
@@ -57,6 +60,7 @@ impl fmt::Display for CanonAbi {
             CanonAbi::C => ExternAbi::C { unwind: false },
             CanonAbi::Rust => ExternAbi::Rust,
             CanonAbi::RustCold => ExternAbi::RustCold,
+            CanonAbi::Custom => ExternAbi::Custom,
             CanonAbi::Arm(arm_call) => match arm_call {
                 ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false },
                 ArmCall::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall,
diff --git a/compiler/rustc_abi/src/extern_abi.rs b/compiler/rustc_abi/src/extern_abi.rs
index 0bc1c8a0930..7457ae1f033 100644
--- a/compiler/rustc_abi/src/extern_abi.rs
+++ b/compiler/rustc_abi/src/extern_abi.rs
@@ -40,6 +40,11 @@ pub enum ExternAbi {
     /// Even normally-compatible Rust types can become ABI-incompatible with this ABI!
     Unadjusted,
 
+    /// An ABI that rustc does not know how to call or define. Functions with this ABI can
+    /// only be created using `#[naked]` functions or `extern "custom"` blocks, and can only
+    /// be called from inline assembly.
+    Custom,
+
     /// UEFI ABI, usually an alias of C, but sometimes an arch-specific alias
     /// and only valid on platforms that have a UEFI standard
     EfiApi,
@@ -141,6 +146,7 @@ abi_impls! {
             AvrNonBlockingInterrupt =><= "avr-non-blocking-interrupt",
             Cdecl { unwind: false } =><= "cdecl",
             Cdecl { unwind: true } =><= "cdecl-unwind",
+            Custom =><= "custom",
             EfiApi =><= "efiapi",
             Fastcall { unwind: false } =><= "fastcall",
             Fastcall { unwind: true } =><= "fastcall-unwind",
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index cf40c3f7f6f..6b51cbd7fbe 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -97,12 +97,12 @@ pub struct Path {
     pub tokens: Option<LazyAttrTokenStream>,
 }
 
+// Succeeds if the path has a single segment that is arg-free and matches the given symbol.
 impl PartialEq<Symbol> for Path {
     #[inline]
     fn eq(&self, name: &Symbol) -> bool {
         if let [segment] = self.segments.as_ref()
-            && segment.args.is_none()
-            && segment.ident.name == *name
+            && segment == name
         {
             true
         } else {
@@ -111,6 +111,15 @@ impl PartialEq<Symbol> for Path {
     }
 }
 
+// Succeeds if the path has segments that are arg-free and match the given symbols.
+impl PartialEq<&[Symbol]> for Path {
+    #[inline]
+    fn eq(&self, names: &&[Symbol]) -> bool {
+        self.segments.len() == names.len()
+            && self.segments.iter().zip(names.iter()).all(|(s1, s2)| s1 == s2)
+    }
+}
+
 impl<CTX: rustc_span::HashStableContext> HashStable<CTX> for Path {
     fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
         self.segments.len().hash_stable(hcx, hasher);
@@ -166,6 +175,14 @@ pub struct PathSegment {
     pub args: Option<P<GenericArgs>>,
 }
 
+// Succeeds if the path segment is arg-free and matches the given symbol.
+impl PartialEq<Symbol> for PathSegment {
+    #[inline]
+    fn eq(&self, name: &Symbol) -> bool {
+        self.args.is_none() && self.ident.name == *name
+    }
+}
+
 impl PathSegment {
     pub fn from_ident(ident: Ident) -> Self {
         PathSegment { ident, id: DUMMY_NODE_ID, args: None }
@@ -1441,11 +1458,15 @@ impl Expr {
                 }
             }
 
-            ExprKind::Break(..)
-            | ExprKind::Ret(..)
-            | ExprKind::Yield(..)
-            | ExprKind::Yeet(..)
-            | ExprKind::Become(..) => ExprPrecedence::Jump,
+            ExprKind::Break(_ /*label*/, value)
+            | ExprKind::Ret(value)
+            | ExprKind::Yield(YieldKind::Prefix(value))
+            | ExprKind::Yeet(value) => match value {
+                Some(_) => ExprPrecedence::Jump,
+                None => ExprPrecedence::Unambiguous,
+            },
+
+            ExprKind::Become(_) => ExprPrecedence::Jump,
 
             // `Range` claims to have higher precedence than `Assign`, but `x .. x = x` fails to
             // parse, instead of parsing as `(x .. x) = x`. Giving `Range` a lower precedence
@@ -1502,6 +1523,7 @@ impl Expr {
             | ExprKind::Underscore
             | ExprKind::UnsafeBinderCast(..)
             | ExprKind::While(..)
+            | ExprKind::Yield(YieldKind::Postfix(..))
             | ExprKind::Err(_)
             | ExprKind::Dummy => ExprPrecedence::Unambiguous,
         }
@@ -3520,6 +3542,38 @@ impl FnHeader {
             || matches!(constness, Const::Yes(_))
             || !matches!(ext, Extern::None)
     }
+
+    /// Return a span encompassing the header, or none if all options are default.
+    pub fn span(&self) -> Option<Span> {
+        fn append(a: &mut Option<Span>, b: Span) {
+            *a = match a {
+                None => Some(b),
+                Some(x) => Some(x.to(b)),
+            }
+        }
+
+        let mut full_span = None;
+
+        match self.safety {
+            Safety::Unsafe(span) | Safety::Safe(span) => append(&mut full_span, span),
+            Safety::Default => {}
+        };
+
+        if let Some(coroutine_kind) = self.coroutine_kind {
+            append(&mut full_span, coroutine_kind.span());
+        }
+
+        if let Const::Yes(span) = self.constness {
+            append(&mut full_span, span);
+        }
+
+        match self.ext {
+            Extern::Implicit(span) | Extern::Explicit(_, span) => append(&mut full_span, span),
+            Extern::None => {}
+        }
+
+        full_span
+    }
 }
 
 impl Default for FnHeader {
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_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 537d4a2a6af..718edad0cc6 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -73,16 +73,15 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     // Merge attributes into the inner expression.
                     if !e.attrs.is_empty() {
                         let old_attrs = self.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]);
-                        let attrs = &*self.arena.alloc_from_iter(
-                            self.lower_attrs_vec(&e.attrs, e.span)
-                                .into_iter()
-                                .chain(old_attrs.iter().cloned()),
-                        );
-                        if attrs.is_empty() {
+                        let new_attrs = self
+                            .lower_attrs_vec(&e.attrs, e.span, ex.hir_id)
+                            .into_iter()
+                            .chain(old_attrs.iter().cloned());
+                        let new_attrs = &*self.arena.alloc_from_iter(new_attrs);
+                        if new_attrs.is_empty() {
                             return ex;
                         }
-
-                        self.attrs.insert(ex.hir_id.local_id, attrs);
+                        self.attrs.insert(ex.hir_id.local_id, new_attrs);
                     }
                     return ex;
                 }
@@ -2035,7 +2034,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 let ret_expr = self.checked_return(Some(from_residual_expr));
                 self.arena.alloc(self.expr(try_span, ret_expr))
             };
-            self.lower_attrs(ret_expr.hir_id, &attrs, ret_expr.span);
+            self.lower_attrs(ret_expr.hir_id, &attrs, span);
 
             let break_pat = self.pat_cf_break(try_span, residual_local);
             self.arm(break_pat, ret_expr)
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index d1a2ddbdb34..e2d291a536d 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -63,7 +63,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
 
         for (def_id, info) in lctx.children {
             let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
-            debug_assert!(
+            assert!(
                 matches!(owner, hir::MaybeOwner::Phantom),
                 "duplicate copy of {def_id:?} in lctx.children"
             );
@@ -78,7 +78,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
             match node {
                 AstOwner::NonOwner => {}
                 AstOwner::Crate(c) => {
-                    debug_assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID);
+                    assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID);
                     self.with_lctx(CRATE_NODE_ID, |lctx| {
                         let module = lctx.lower_mod(&c.items, &c.spans);
                         // FIXME(jdonszelman): is dummy span ever a problem here?
@@ -1160,7 +1160,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     ) -> hir::BodyId {
         let body = hir::Body { params, value: self.arena.alloc(value) };
         let id = body.id();
-        debug_assert_eq!(id.hir_id.owner, self.current_hir_id_owner);
+        assert_eq!(id.hir_id.owner, self.current_hir_id_owner);
         self.bodies.push((id.hir_id.local_id, self.arena.alloc(body)));
         id
     }
@@ -1673,8 +1673,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
         itctx: ImplTraitContext,
         f: impl FnOnce(&mut Self) -> T,
     ) -> (&'hir hir::Generics<'hir>, T) {
-        debug_assert!(self.impl_trait_defs.is_empty());
-        debug_assert!(self.impl_trait_bounds.is_empty());
+        assert!(self.impl_trait_defs.is_empty());
+        assert!(self.impl_trait_bounds.is_empty());
 
         // Error if `?Trait` bounds in where clauses don't refer directly to type parameters.
         // Note: we used to clone these bounds directly onto the type parameter (and avoid lowering
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index b99df8bd7e5..4f0368bcb01 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -51,6 +51,7 @@ use rustc_data_structures::tagged_ptr::TaggedRef;
 use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey};
 use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
 use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
+use rustc_hir::lints::DelayedLint;
 use rustc_hir::{
     self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem,
     LifetimeSource, LifetimeSyntax, ParamName, TraitCandidate,
@@ -141,6 +142,8 @@ struct LoweringContext<'a, 'hir> {
     allow_for_await: Arc<[Symbol]>,
     allow_async_fn_traits: Arc<[Symbol]>,
 
+    delayed_lints: Vec<DelayedLint>,
+
     attribute_parser: AttributeParser<'hir>,
 }
 
@@ -190,6 +193,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
 
             attribute_parser: AttributeParser::new(tcx.sess, tcx.features(), registered_tools),
+            delayed_lints: Vec::new(),
         }
     }
 
@@ -198,6 +202,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     }
 }
 
+struct SpanLowerer {
+    is_incremental: bool,
+    def_id: LocalDefId,
+}
+
+impl SpanLowerer {
+    fn lower(&self, span: Span) -> Span {
+        if self.is_incremental {
+            span.with_parent(Some(self.def_id))
+        } else {
+            // Do not make spans relative when not using incremental compilation.
+            span
+        }
+    }
+}
+
 #[extension(trait ResolverAstLoweringExt)]
 impl ResolverAstLowering {
     fn legacy_const_generic_args(&self, expr: &Expr) -> Option<Vec<usize>> {
@@ -503,7 +523,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         span: Span,
     ) -> LocalDefId {
         let parent = self.current_hir_id_owner.def_id;
-        debug_assert_ne!(node_id, ast::DUMMY_NODE_ID);
+        assert_ne!(node_id, ast::DUMMY_NODE_ID);
         assert!(
             self.opt_local_def_id(node_id).is_none(),
             "adding a def'n for node-id {:?} and def kind {:?} but a previous def'n exists: {:?}",
@@ -573,6 +593,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             std::mem::replace(&mut self.item_local_id_counter, hir::ItemLocalId::new(1));
         let current_impl_trait_defs = std::mem::take(&mut self.impl_trait_defs);
         let current_impl_trait_bounds = std::mem::take(&mut self.impl_trait_bounds);
+        let current_delayed_lints = std::mem::take(&mut self.delayed_lints);
 
         // Do not reset `next_node_id` and `node_id_to_def_id`:
         // we want `f` to be able to refer to the `LocalDefId`s that the caller created.
@@ -586,10 +607,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         }
 
         let item = f(self);
-        debug_assert_eq!(owner_id, item.def_id());
+        assert_eq!(owner_id, item.def_id());
         // `f` should have consumed all the elements in these vectors when constructing `item`.
-        debug_assert!(self.impl_trait_defs.is_empty());
-        debug_assert!(self.impl_trait_bounds.is_empty());
+        assert!(self.impl_trait_defs.is_empty());
+        assert!(self.impl_trait_bounds.is_empty());
         let info = self.make_owner_info(item);
 
         self.attrs = current_attrs;
@@ -606,6 +627,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         self.item_local_id_counter = current_local_counter;
         self.impl_trait_defs = current_impl_trait_defs;
         self.impl_trait_bounds = current_impl_trait_bounds;
+        self.delayed_lints = current_delayed_lints;
 
         debug_assert!(!self.children.iter().any(|(id, _)| id == &owner_id.def_id));
         self.children.push((owner_id.def_id, hir::MaybeOwner::Owner(info)));
@@ -616,6 +638,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let mut bodies = std::mem::take(&mut self.bodies);
         let define_opaque = std::mem::take(&mut self.define_opaque);
         let trait_map = std::mem::take(&mut self.trait_map);
+        let delayed_lints = std::mem::take(&mut self.delayed_lints).into_boxed_slice();
 
         #[cfg(debug_assertions)]
         for (id, attrs) in attrs.iter() {
@@ -629,14 +652,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let bodies = SortedMap::from_presorted_elements(bodies);
 
         // Don't hash unless necessary, because it's expensive.
-        let (opt_hash_including_bodies, attrs_hash) =
-            self.tcx.hash_owner_nodes(node, &bodies, &attrs, define_opaque);
+        let (opt_hash_including_bodies, attrs_hash, delayed_lints_hash) =
+            self.tcx.hash_owner_nodes(node, &bodies, &attrs, &delayed_lints, define_opaque);
         let num_nodes = self.item_local_id_counter.as_usize();
         let (nodes, parenting) = index::index_hir(self.tcx, node, &bodies, num_nodes);
         let nodes = hir::OwnerNodes { opt_hash_including_bodies, nodes, bodies };
         let attrs = hir::AttributeMap { map: attrs, opt_hash: attrs_hash, define_opaque };
+        let delayed_lints =
+            hir::lints::DelayedLints { lints: delayed_lints, opt_hash: delayed_lints_hash };
 
-        self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map })
+        self.arena.alloc(hir::OwnerInfo { nodes, parenting, attrs, trait_map, delayed_lints })
     }
 
     /// This method allocates a new `HirId` for the given `NodeId`.
@@ -759,15 +784,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         })
     }
 
+    fn span_lowerer(&self) -> SpanLowerer {
+        SpanLowerer {
+            is_incremental: self.tcx.sess.opts.incremental.is_some(),
+            def_id: self.current_hir_id_owner.def_id,
+        }
+    }
+
     /// Intercept all spans entering HIR.
     /// Mark a span as relative to the current owning item.
     fn lower_span(&self, span: Span) -> Span {
-        if self.tcx.sess.opts.incremental.is_some() {
-            span.with_parent(Some(self.current_hir_id_owner.def_id))
-        } else {
-            // Do not make spans relative when not using incremental compilation.
-            span
-        }
+        self.span_lowerer().lower(span)
     }
 
     fn lower_ident(&self, ident: Ident) -> Ident {
@@ -889,9 +916,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         if attrs.is_empty() {
             &[]
         } else {
-            let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span));
+            let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span), id);
 
-            debug_assert_eq!(id.owner, self.current_hir_id_owner);
+            assert_eq!(id.owner, self.current_hir_id_owner);
             let ret = self.arena.alloc_from_iter(lowered_attrs);
 
             // this is possible if an item contained syntactical attribute,
@@ -909,16 +936,30 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         }
     }
 
-    fn lower_attrs_vec(&self, attrs: &[Attribute], target_span: Span) -> Vec<hir::Attribute> {
-        self.attribute_parser
-            .parse_attribute_list(attrs, target_span, OmitDoc::Lower, |s| self.lower_span(s))
+    fn lower_attrs_vec(
+        &mut self,
+        attrs: &[Attribute],
+        target_span: Span,
+        target_hir_id: HirId,
+    ) -> Vec<hir::Attribute> {
+        let l = self.span_lowerer();
+        self.attribute_parser.parse_attribute_list(
+            attrs,
+            target_span,
+            target_hir_id,
+            OmitDoc::Lower,
+            |s| l.lower(s),
+            |l| {
+                self.delayed_lints.push(DelayedLint::AttributeParsing(l));
+            },
+        )
     }
 
     fn alias_attrs(&mut self, id: HirId, target_id: HirId) {
-        debug_assert_eq!(id.owner, self.current_hir_id_owner);
-        debug_assert_eq!(target_id.owner, self.current_hir_id_owner);
+        assert_eq!(id.owner, self.current_hir_id_owner);
+        assert_eq!(target_id.owner, self.current_hir_id_owner);
         if let Some(&a) = self.attrs.get(&target_id.local_id) {
-            debug_assert!(!a.is_empty());
+            assert!(!a.is_empty());
             self.attrs.insert(id.local_id, a);
         }
     }
@@ -1397,7 +1438,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) =
                     self.resolver.get_lifetime_res(t.id)
                 {
-                    debug_assert_eq!(start.plus(1), end);
+                    assert_eq!(start.plus(1), end);
                     start
                 } else {
                     self.next_node_id()
@@ -1805,16 +1846,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let res = match res {
             LifetimeRes::Param { param, .. } => hir::LifetimeKind::Param(param),
             LifetimeRes::Fresh { param, .. } => {
-                debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
+                assert_eq!(ident.name, kw::UnderscoreLifetime);
                 let param = self.local_def_id(param);
                 hir::LifetimeKind::Param(param)
             }
             LifetimeRes::Infer => {
-                debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
+                assert_eq!(ident.name, kw::UnderscoreLifetime);
                 hir::LifetimeKind::Infer
             }
             LifetimeRes::Static { .. } => {
-                debug_assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime));
+                assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime));
                 hir::LifetimeKind::Static
             }
             LifetimeRes::Error => hir::LifetimeKind::Error,
@@ -2244,7 +2285,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     ) -> hir::Stmt<'hir> {
         let hir_id = self.next_id();
         if let Some(a) = attrs {
-            debug_assert!(!a.is_empty());
+            assert!(!a.is_empty());
             self.attrs.insert(hir_id.local_id, a);
         }
         let local = hir::LetStmt {
diff --git a/compiler/rustc_ast_lowering/src/stability.rs b/compiler/rustc_ast_lowering/src/stability.rs
index eb052ba1c6d..b8fa2dd3dd6 100644
--- a/compiler/rustc_ast_lowering/src/stability.rs
+++ b/compiler/rustc_ast_lowering/src/stability.rs
@@ -134,5 +134,8 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
             feature: sym::cmse_nonsecure_entry,
             explain: GateReason::Experimental,
         }),
+        ExternAbi::Custom => {
+            Err(UnstableAbi { abi, feature: sym::abi_custom, explain: GateReason::Experimental })
+        }
     }
 }
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 80754a8f65a..9a267501230 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -1,3 +1,20 @@
+ast_passes_abi_custom_coroutine =
+    functions with the `"custom"` ABI cannot be `{$coroutine_kind_str}`
+    .suggestion = remove the `{$coroutine_kind_str}` keyword from this definiton
+
+ast_passes_abi_custom_invalid_signature =
+    invalid signature for `extern "custom"` function
+    .note = functions with the `"custom"` ABI cannot have any parameters or return type
+    .suggestion = remove the parameters and return type
+
+ast_passes_abi_custom_safe_foreign_function =
+    foreign functions with the `"custom"` ABI cannot be safe
+    .suggestion = remove the `safe` keyword from this definition
+
+ast_passes_abi_custom_safe_function =
+    functions with the `"custom"` ABI must be unsafe
+    .suggestion = add the `unsafe` keyword to this definition
+
 ast_passes_assoc_const_without_body =
     associated constant in `impl` without body
     .suggestion = provide a definition for the constant
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index d6fe04d2994..018887d0e8e 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -18,6 +18,7 @@
 
 use std::mem;
 use std::ops::{Deref, DerefMut};
+use std::str::FromStr;
 
 use itertools::{Either, Itertools};
 use rustc_abi::ExternAbi;
@@ -81,6 +82,7 @@ struct AstValidator<'a> {
 
     /// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe.
     extern_mod_safety: Option<Safety>,
+    extern_mod_abi: Option<ExternAbi>,
 
     lint_node_id: NodeId,
 
@@ -121,10 +123,17 @@ impl<'a> AstValidator<'a> {
         self.outer_trait_or_trait_impl = old;
     }
 
-    fn with_in_extern_mod(&mut self, extern_mod_safety: Safety, f: impl FnOnce(&mut Self)) {
-        let old = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety));
+    fn with_in_extern_mod(
+        &mut self,
+        extern_mod_safety: Safety,
+        abi: Option<ExternAbi>,
+        f: impl FnOnce(&mut Self),
+    ) {
+        let old_safety = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety));
+        let old_abi = mem::replace(&mut self.extern_mod_abi, abi);
         f(self);
-        self.extern_mod_safety = old;
+        self.extern_mod_safety = old_safety;
+        self.extern_mod_abi = old_abi;
     }
 
     fn with_tilde_const(
@@ -370,6 +379,65 @@ impl<'a> AstValidator<'a> {
         }
     }
 
+    /// An `extern "custom"` function must be unsafe, and must not have any parameters or return
+    /// type.
+    fn check_custom_abi(&self, ctxt: FnCtxt, ident: &Ident, sig: &FnSig) {
+        let dcx = self.dcx();
+
+        // An `extern "custom"` function must be unsafe.
+        match sig.header.safety {
+            Safety::Unsafe(_) => { /* all good */ }
+            Safety::Safe(safe_span) => {
+                let safe_span =
+                    self.sess.psess.source_map().span_until_non_whitespace(safe_span.to(sig.span));
+                dcx.emit_err(errors::AbiCustomSafeForeignFunction { span: sig.span, safe_span });
+            }
+            Safety::Default => match ctxt {
+                FnCtxt::Foreign => { /* all good */ }
+                FnCtxt::Free | FnCtxt::Assoc(_) => {
+                    self.dcx().emit_err(errors::AbiCustomSafeFunction {
+                        span: sig.span,
+                        unsafe_span: sig.span.shrink_to_lo(),
+                    });
+                }
+            },
+        }
+
+        // An `extern "custom"` function cannot be `async` and/or `gen`.
+        if let Some(coroutine_kind) = sig.header.coroutine_kind {
+            let coroutine_kind_span = self
+                .sess
+                .psess
+                .source_map()
+                .span_until_non_whitespace(coroutine_kind.span().to(sig.span));
+
+            self.dcx().emit_err(errors::AbiCustomCoroutine {
+                span: sig.span,
+                coroutine_kind_span,
+                coroutine_kind_str: coroutine_kind.as_str(),
+            });
+        }
+
+        // An `extern "custom"` function must not have any parameters or return type.
+        let mut spans: Vec<_> = sig.decl.inputs.iter().map(|p| p.span).collect();
+        if let FnRetTy::Ty(ref ret_ty) = sig.decl.output {
+            spans.push(ret_ty.span);
+        }
+
+        if !spans.is_empty() {
+            let header_span = sig.header.span().unwrap_or(sig.span.shrink_to_lo());
+            let suggestion_span = header_span.shrink_to_hi().to(sig.decl.output.span());
+            let padding = if header_span.is_empty() { "" } else { " " };
+
+            self.dcx().emit_err(errors::AbiCustomInvalidSignature {
+                spans,
+                symbol: ident.name,
+                suggestion_span,
+                padding,
+            });
+        }
+    }
+
     /// This ensures that items can only be `unsafe` (or unmarked) outside of extern
     /// blocks.
     ///
@@ -1005,7 +1073,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 if abi.is_none() {
                     self.handle_missing_abi(*extern_span, item.id);
                 }
-                self.with_in_extern_mod(*safety, |this| {
+
+                let extern_abi = abi.and_then(|abi| ExternAbi::from_str(abi.symbol.as_str()).ok());
+                self.with_in_extern_mod(*safety, extern_abi, |this| {
                     visit::walk_item(this, item);
                 });
                 self.extern_mod_span = old_item;
@@ -1145,6 +1215,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 self.check_foreign_fn_bodyless(*ident, body.as_deref());
                 self.check_foreign_fn_headerless(sig.header);
                 self.check_foreign_item_ascii_only(*ident);
+                if self.extern_mod_abi == Some(ExternAbi::Custom) {
+                    self.check_custom_abi(FnCtxt::Foreign, ident, sig);
+                }
             }
             ForeignItemKind::TyAlias(box TyAlias {
                 defaultness,
@@ -1352,6 +1425,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             self.check_item_safety(span, safety);
         }
 
+        if let FnKind::Fn(ctxt, _, fun) = fk
+            && let Extern::Explicit(str_lit, _) = fun.sig.header.ext
+            && let Ok(ExternAbi::Custom) = ExternAbi::from_str(str_lit.symbol.as_str())
+        {
+            self.check_custom_abi(ctxt, &fun.ident, &fun.sig);
+        }
+
         self.check_c_variadic_type(fk);
 
         // Functions cannot both be `const async` or `const gen`
@@ -1703,6 +1783,7 @@ pub fn check_crate(
         outer_impl_trait_span: None,
         disallow_tilde_const: Some(TildeConstReason::Item),
         extern_mod_safety: None,
+        extern_mod_abi: None,
         lint_node_id: CRATE_NODE_ID,
         is_sdylib_interface,
         lint_buffer: lints,
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 6f9737e0831..c437e62f4d3 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -824,3 +824,67 @@ pub(crate) struct MissingAbi {
     #[suggestion(code = "extern \"<abi>\"", applicability = "has-placeholders")]
     pub span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_abi_custom_safe_foreign_function)]
+pub(crate) struct AbiCustomSafeForeignFunction {
+    #[primary_span]
+    pub span: Span,
+
+    #[suggestion(
+        ast_passes_suggestion,
+        applicability = "maybe-incorrect",
+        code = "",
+        style = "verbose"
+    )]
+    pub safe_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_abi_custom_safe_function)]
+pub(crate) struct AbiCustomSafeFunction {
+    #[primary_span]
+    pub span: Span,
+
+    #[suggestion(
+        ast_passes_suggestion,
+        applicability = "maybe-incorrect",
+        code = "unsafe ",
+        style = "verbose"
+    )]
+    pub unsafe_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_abi_custom_coroutine)]
+pub(crate) struct AbiCustomCoroutine {
+    #[primary_span]
+    pub span: Span,
+
+    #[suggestion(
+        ast_passes_suggestion,
+        applicability = "maybe-incorrect",
+        code = "",
+        style = "verbose"
+    )]
+    pub coroutine_kind_span: Span,
+    pub coroutine_kind_str: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_abi_custom_invalid_signature)]
+#[note]
+pub(crate) struct AbiCustomInvalidSignature {
+    #[primary_span]
+    pub spans: Vec<Span>,
+
+    #[suggestion(
+        ast_passes_suggestion,
+        applicability = "maybe-incorrect",
+        code = "{padding}fn {symbol}()",
+        style = "verbose"
+    )]
+    pub suggestion_span: Span,
+    pub symbol: Symbol,
+    pub padding: &'static str,
+}
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 3682d25d341..1ec56868f37 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -36,6 +36,16 @@ macro_rules! gate_alt {
             feature_err(&$visitor.sess, $name, $span, $explain).emit();
         }
     }};
+    ($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr, $notes: expr) => {{
+        if !$has_feature && !$span.allows_unstable($name) {
+            #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
+            let mut diag = feature_err(&$visitor.sess, $name, $span, $explain);
+            for note in $notes {
+                diag.note(*note);
+            }
+            diag.emit();
+        }
+    }};
 }
 
 /// The case involving a multispan.
@@ -154,11 +164,11 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
         let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
         // Check feature gates for built-in attributes.
         if let Some(BuiltinAttribute {
-            gate: AttributeGate::Gated(_, name, descr, has_feature),
+            gate: AttributeGate::Gated { feature, message, check, notes, .. },
             ..
         }) = attr_info
         {
-            gate_alt!(self, has_feature(self.features), *name, attr.span, *descr);
+            gate_alt!(self, check(self.features), *feature, attr.span, *message, *notes);
         }
         // Check unstable flavors of the `#[doc]` attribute.
         if attr.has_name(sym::doc) {
diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs
index a05e2bd6a5d..a766e2006e5 100644
--- a/compiler/rustc_ast_pretty/src/pprust/mod.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs
@@ -53,6 +53,18 @@ pub fn item_to_string(i: &ast::Item) -> String {
     State::new().item_to_string(i)
 }
 
+pub fn assoc_item_to_string(i: &ast::AssocItem) -> String {
+    State::new().assoc_item_to_string(i)
+}
+
+pub fn foreign_item_to_string(i: &ast::ForeignItem) -> String {
+    State::new().foreign_item_to_string(i)
+}
+
+pub fn stmt_to_string(s: &ast::Stmt) -> String {
+    State::new().stmt_to_string(s)
+}
+
 pub fn path_to_string(p: &ast::Path) -> String {
     State::new().path_to_string(p)
 }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 0990c9b27eb..3d738fa31f2 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1063,6 +1063,14 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
         Self::to_string(|s| s.print_item(i))
     }
 
+    fn assoc_item_to_string(&self, i: &ast::AssocItem) -> String {
+        Self::to_string(|s| s.print_assoc_item(i))
+    }
+
+    fn foreign_item_to_string(&self, i: &ast::ForeignItem) -> String {
+        Self::to_string(|s| s.print_foreign_item(i))
+    }
+
     fn path_to_string(&self, p: &ast::Path) -> String {
         Self::to_string(|s| s.print_path(p, false, 0))
     }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index c9a7e2aebd0..ee49246a4bb 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -7,8 +7,8 @@ use rustc_ast::util::classify;
 use rustc_ast::util::literal::escape_byte_str_symbol;
 use rustc_ast::util::parser::{self, ExprPrecedence, Fixity};
 use rustc_ast::{
-    self as ast, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece, FormatCount,
-    FormatDebugHex, FormatSign, FormatTrait, YieldKind, token,
+    self as ast, BinOpKind, BlockCheckMode, FormatAlignment, FormatArgPosition, FormatArgsPiece,
+    FormatCount, FormatDebugHex, FormatSign, FormatTrait, YieldKind, token,
 };
 
 use crate::pp::Breaks::Inconsistent;
@@ -214,13 +214,6 @@ impl<'a> State<'a> {
     }
 
     fn print_expr_call(&mut self, func: &ast::Expr, args: &[P<ast::Expr>], fixup: FixupContext) {
-        let needs_paren = match func.kind {
-            // In order to call a named field, needs parens: `(self.fun)()`
-            // But not for an unnamed field: `self.0()`
-            ast::ExprKind::Field(_, name) => !name.is_numeric(),
-            _ => func.precedence() < ExprPrecedence::Unambiguous,
-        };
-
         // Independent of parenthesization related to precedence, we must
         // parenthesize `func` if this is a statement context in which without
         // parentheses, a statement boundary would occur inside `func` or
@@ -237,8 +230,16 @@ impl<'a> State<'a> {
         // because the latter is valid syntax but with the incorrect meaning.
         // It's a match-expression followed by tuple-expression, not a function
         // call.
-        self.print_expr_cond_paren(func, needs_paren, fixup.leftmost_subexpression());
+        let func_fixup = fixup.leftmost_subexpression_with_operator(true);
+
+        let needs_paren = match func.kind {
+            // In order to call a named field, needs parens: `(self.fun)()`
+            // But not for an unnamed field: `self.0()`
+            ast::ExprKind::Field(_, name) => !name.is_numeric(),
+            _ => func_fixup.precedence(func) < ExprPrecedence::Unambiguous,
+        };
 
+        self.print_expr_cond_paren(func, needs_paren, func_fixup);
         self.print_call_post(args)
     }
 
@@ -281,9 +282,24 @@ impl<'a> State<'a> {
         rhs: &ast::Expr,
         fixup: FixupContext,
     ) {
+        let operator_can_begin_expr = match op {
+            | BinOpKind::Sub     // -x
+            | BinOpKind::Mul     // *x
+            | BinOpKind::And     // &&x
+            | BinOpKind::Or      // || x
+            | BinOpKind::BitAnd  // &x
+            | BinOpKind::BitOr   // |x| x
+            | BinOpKind::Shl     // <<T as Trait>::Type as Trait>::CONST
+            | BinOpKind::Lt      // <T as Trait>::CONST
+              => true,
+            _ => false,
+        };
+
+        let left_fixup = fixup.leftmost_subexpression_with_operator(operator_can_begin_expr);
+
         let binop_prec = op.precedence();
-        let left_prec = lhs.precedence();
-        let right_prec = rhs.precedence();
+        let left_prec = left_fixup.precedence(lhs);
+        let right_prec = fixup.precedence(rhs);
 
         let (mut left_needs_paren, right_needs_paren) = match op.fixity() {
             Fixity::Left => (left_prec < binop_prec, right_prec <= binop_prec),
@@ -312,18 +328,18 @@ impl<'a> State<'a> {
             _ => {}
         }
 
-        self.print_expr_cond_paren(lhs, left_needs_paren, fixup.leftmost_subexpression());
+        self.print_expr_cond_paren(lhs, left_needs_paren, left_fixup);
         self.space();
         self.word_space(op.as_str());
-        self.print_expr_cond_paren(rhs, right_needs_paren, fixup.subsequent_subexpression());
+        self.print_expr_cond_paren(rhs, right_needs_paren, fixup.rightmost_subexpression());
     }
 
     fn print_expr_unary(&mut self, op: ast::UnOp, expr: &ast::Expr, fixup: FixupContext) {
         self.word(op.as_str());
         self.print_expr_cond_paren(
             expr,
-            expr.precedence() < ExprPrecedence::Prefix,
-            fixup.subsequent_subexpression(),
+            fixup.precedence(expr) < ExprPrecedence::Prefix,
+            fixup.rightmost_subexpression(),
         );
     }
 
@@ -344,8 +360,8 @@ impl<'a> State<'a> {
         }
         self.print_expr_cond_paren(
             expr,
-            expr.precedence() < ExprPrecedence::Prefix,
-            fixup.subsequent_subexpression(),
+            fixup.precedence(expr) < ExprPrecedence::Prefix,
+            fixup.rightmost_subexpression(),
         );
     }
 
@@ -590,8 +606,8 @@ impl<'a> State<'a> {
                 self.word_space("=");
                 self.print_expr_cond_paren(
                     rhs,
-                    rhs.precedence() < ExprPrecedence::Assign,
-                    fixup.subsequent_subexpression(),
+                    fixup.precedence(rhs) < ExprPrecedence::Assign,
+                    fixup.rightmost_subexpression(),
                 );
             }
             ast::ExprKind::AssignOp(op, lhs, rhs) => {
@@ -604,8 +620,8 @@ impl<'a> State<'a> {
                 self.word_space(op.node.as_str());
                 self.print_expr_cond_paren(
                     rhs,
-                    rhs.precedence() < ExprPrecedence::Assign,
-                    fixup.subsequent_subexpression(),
+                    fixup.precedence(rhs) < ExprPrecedence::Assign,
+                    fixup.rightmost_subexpression(),
                 );
             }
             ast::ExprKind::Field(expr, ident) => {
@@ -618,10 +634,11 @@ impl<'a> State<'a> {
                 self.print_ident(*ident);
             }
             ast::ExprKind::Index(expr, index, _) => {
+                let expr_fixup = fixup.leftmost_subexpression_with_operator(true);
                 self.print_expr_cond_paren(
                     expr,
-                    expr.precedence() < ExprPrecedence::Unambiguous,
-                    fixup.leftmost_subexpression(),
+                    expr_fixup.precedence(expr) < ExprPrecedence::Unambiguous,
+                    expr_fixup,
                 );
                 self.word("[");
                 self.print_expr(index, FixupContext::default());
@@ -634,10 +651,11 @@ impl<'a> State<'a> {
                 // a "normal" binop gets parenthesized. (`LOr` is the lowest-precedence binop.)
                 let fake_prec = ExprPrecedence::LOr;
                 if let Some(e) = start {
+                    let start_fixup = fixup.leftmost_subexpression_with_operator(true);
                     self.print_expr_cond_paren(
                         e,
-                        e.precedence() < fake_prec,
-                        fixup.leftmost_subexpression(),
+                        start_fixup.precedence(e) < fake_prec,
+                        start_fixup,
                     );
                 }
                 match limits {
@@ -647,8 +665,8 @@ impl<'a> State<'a> {
                 if let Some(e) = end {
                     self.print_expr_cond_paren(
                         e,
-                        e.precedence() < fake_prec,
-                        fixup.subsequent_subexpression(),
+                        fixup.precedence(e) < fake_prec,
+                        fixup.rightmost_subexpression(),
                     );
                 }
             }
@@ -665,11 +683,10 @@ impl<'a> State<'a> {
                     self.space();
                     self.print_expr_cond_paren(
                         expr,
-                        // Parenthesize if required by precedence, or in the
-                        // case of `break 'inner: loop { break 'inner 1 } + 1`
-                        expr.precedence() < ExprPrecedence::Jump
-                            || (opt_label.is_none() && classify::leading_labeled_expr(expr)),
-                        fixup.subsequent_subexpression(),
+                        // Parenthesize `break 'inner: loop { break 'inner 1 } + 1`
+                        //                     ^---------------------------------^
+                        opt_label.is_none() && classify::leading_labeled_expr(expr),
+                        fixup.rightmost_subexpression(),
                     );
                 }
             }
@@ -684,11 +701,7 @@ impl<'a> State<'a> {
                 self.word("return");
                 if let Some(expr) = result {
                     self.word(" ");
-                    self.print_expr_cond_paren(
-                        expr,
-                        expr.precedence() < ExprPrecedence::Jump,
-                        fixup.subsequent_subexpression(),
-                    );
+                    self.print_expr(expr, fixup.rightmost_subexpression());
                 }
             }
             ast::ExprKind::Yeet(result) => {
@@ -697,21 +710,13 @@ impl<'a> State<'a> {
                 self.word("yeet");
                 if let Some(expr) = result {
                     self.word(" ");
-                    self.print_expr_cond_paren(
-                        expr,
-                        expr.precedence() < ExprPrecedence::Jump,
-                        fixup.subsequent_subexpression(),
-                    );
+                    self.print_expr(expr, fixup.rightmost_subexpression());
                 }
             }
             ast::ExprKind::Become(result) => {
                 self.word("become");
                 self.word(" ");
-                self.print_expr_cond_paren(
-                    result,
-                    result.precedence() < ExprPrecedence::Jump,
-                    fixup.subsequent_subexpression(),
-                );
+                self.print_expr(result, fixup.rightmost_subexpression());
             }
             ast::ExprKind::InlineAsm(a) => {
                 // FIXME: Print `builtin # asm` once macro `asm` uses `builtin_syntax`.
@@ -761,11 +766,7 @@ impl<'a> State<'a> {
 
                 if let Some(expr) = e {
                     self.space();
-                    self.print_expr_cond_paren(
-                        expr,
-                        expr.precedence() < ExprPrecedence::Jump,
-                        fixup.subsequent_subexpression(),
-                    );
+                    self.print_expr(expr, fixup.rightmost_subexpression());
                 }
             }
             ast::ExprKind::Yield(YieldKind::Postfix(e)) => {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs b/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs
index 3ef21f5cb29..eb5ac8b78a8 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs
@@ -1,5 +1,6 @@
-use rustc_ast::Expr;
-use rustc_ast::util::{classify, parser};
+use rustc_ast::util::classify;
+use rustc_ast::util::parser::{self, ExprPrecedence};
+use rustc_ast::{Expr, ExprKind, YieldKind};
 
 // The default amount of fixing is minimal fixing, so all fixups are set to `false` by `Default`.
 // Fixups should be turned on in a targeted fashion where needed.
@@ -93,6 +94,24 @@ pub(crate) struct FixupContext {
     /// }
     /// ```
     parenthesize_exterior_struct_lit: bool,
+
+    /// This is the difference between:
+    ///
+    /// ```ignore (illustrative)
+    /// let _ = (return) - 1;  // without paren, this would return -1
+    ///
+    /// let _ = return + 1;  // no paren because '+' cannot begin expr
+    /// ```
+    next_operator_can_begin_expr: bool,
+
+    /// This is the difference between:
+    ///
+    /// ```ignore (illustrative)
+    /// let _ = 1 + return 1;  // no parens if rightmost subexpression
+    ///
+    /// let _ = 1 + (return 1) + 1;  // needs parens
+    /// ```
+    next_operator_can_continue_expr: bool,
 }
 
 impl FixupContext {
@@ -134,6 +153,8 @@ impl FixupContext {
             match_arm: false,
             leftmost_subexpression_in_match_arm: self.match_arm
                 || self.leftmost_subexpression_in_match_arm,
+            next_operator_can_begin_expr: false,
+            next_operator_can_continue_expr: true,
             ..self
         }
     }
@@ -148,19 +169,34 @@ impl FixupContext {
             leftmost_subexpression_in_stmt: false,
             match_arm: self.match_arm || self.leftmost_subexpression_in_match_arm,
             leftmost_subexpression_in_match_arm: false,
+            next_operator_can_begin_expr: false,
+            next_operator_can_continue_expr: true,
             ..self
         }
     }
 
-    /// Transform this fixup into the one that should apply when printing any
-    /// subexpression that is neither a leftmost subexpression nor surrounded in
-    /// delimiters.
+    /// Transform this fixup into the one that should apply when printing a
+    /// leftmost subexpression followed by punctuation that is legal as the
+    /// first token of an expression.
+    pub(crate) fn leftmost_subexpression_with_operator(
+        self,
+        next_operator_can_begin_expr: bool,
+    ) -> Self {
+        FixupContext { next_operator_can_begin_expr, ..self.leftmost_subexpression() }
+    }
+
+    /// Transform this fixup into the one that should apply when printing the
+    /// rightmost subexpression of the current expression.
+    ///
+    /// The rightmost subexpression is any subexpression that has a different
+    /// first token than the current expression, but has the same last token.
+    ///
+    /// For example in `$a + $b` and `-$b`, the subexpression `$b` is a
+    /// rightmost subexpression.
     ///
-    /// This is for any subexpression that has a different first token than the
-    /// current expression, and is not surrounded by a paren/bracket/brace. For
-    /// example the `$b` in `$a + $b` and `-$b`, but not the one in `[$b]` or
-    /// `$a.f($b)`.
-    pub(crate) fn subsequent_subexpression(self) -> Self {
+    /// Not every expression has a rightmost subexpression. For example neither
+    /// `[$b]` nor `$a.f($b)` have one.
+    pub(crate) fn rightmost_subexpression(self) -> Self {
         FixupContext {
             stmt: false,
             leftmost_subexpression_in_stmt: false,
@@ -193,6 +229,39 @@ impl FixupContext {
     ///     "let chain".
     pub(crate) fn needs_par_as_let_scrutinee(self, expr: &Expr) -> bool {
         self.parenthesize_exterior_struct_lit && parser::contains_exterior_struct_lit(expr)
-            || parser::needs_par_as_let_scrutinee(expr.precedence())
+            || parser::needs_par_as_let_scrutinee(self.precedence(expr))
+    }
+
+    /// Determines the effective precedence of a subexpression. Some expressions
+    /// have higher or lower precedence when adjacent to particular operators.
+    pub(crate) fn precedence(self, expr: &Expr) -> ExprPrecedence {
+        if self.next_operator_can_begin_expr {
+            // Decrease precedence of value-less jumps when followed by an
+            // operator that would otherwise get interpreted as beginning a
+            // value for the jump.
+            if let ExprKind::Break(..)
+            | ExprKind::Ret(..)
+            | ExprKind::Yeet(..)
+            | ExprKind::Yield(YieldKind::Prefix(..)) = expr.kind
+            {
+                return ExprPrecedence::Jump;
+            }
+        }
+
+        if !self.next_operator_can_continue_expr {
+            // Increase precedence of expressions that extend to the end of
+            // current statement or group.
+            if let ExprKind::Break(..)
+            | ExprKind::Closure(..)
+            | ExprKind::Ret(..)
+            | ExprKind::Yeet(..)
+            | ExprKind::Yield(YieldKind::Prefix(..))
+            | ExprKind::Range(None, ..) = expr.kind
+            {
+                return ExprPrecedence::Prefix;
+            }
+        }
+
+        expr.precedence()
     }
 }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 3638eb31c61..6c442553976 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -28,7 +28,7 @@ impl<'a> State<'a> {
         }
     }
 
-    fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
+    pub(crate) fn print_foreign_item(&mut self, item: &ast::ForeignItem) {
         let ast::Item { id, span, ref attrs, ref kind, ref vis, tokens: _ } = *item;
         self.ann.pre(self, AnnNode::SubItem(id));
         self.hardbreak_if_not_bol();
@@ -548,7 +548,7 @@ impl<'a> State<'a> {
         }
     }
 
-    fn print_assoc_item(&mut self, item: &ast::AssocItem) {
+    pub(crate) fn print_assoc_item(&mut self, item: &ast::AssocItem) {
         let ast::Item { id, span, ref attrs, ref kind, ref vis, tokens: _ } = *item;
         self.ann.pre(self, AnnNode::SubItem(id));
         self.hardbreak_if_not_bol();
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_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs
index dbfc95b047a..b0fc19d1cd7 100644
--- a/compiler/rustc_attr_data_structures/src/lib.rs
+++ b/compiler/rustc_attr_data_structures/src/lib.rs
@@ -8,6 +8,8 @@ mod attributes;
 mod stability;
 mod version;
 
+pub mod lints;
+
 use std::num::NonZero;
 
 pub use attributes::*;
diff --git a/compiler/rustc_attr_data_structures/src/lints.rs b/compiler/rustc_attr_data_structures/src/lints.rs
new file mode 100644
index 00000000000..7e3664b2263
--- /dev/null
+++ b/compiler/rustc_attr_data_structures/src/lints.rs
@@ -0,0 +1,14 @@
+use rustc_macros::HashStable_Generic;
+use rustc_span::Span;
+
+#[derive(Clone, Debug, HashStable_Generic)]
+pub struct AttributeLint<Id> {
+    pub id: Id,
+    pub span: Span,
+    pub kind: AttributeLintKind,
+}
+
+#[derive(Clone, Debug, HashStable_Generic)]
+pub enum AttributeLintKind {
+    UnusedDuplicate { this: Span, other: Span, warning: bool },
+}
diff --git a/compiler/rustc_attr_data_structures/src/stability.rs b/compiler/rustc_attr_data_structures/src/stability.rs
index c0ca08a60f8..218e771c745 100644
--- a/compiler/rustc_attr_data_structures/src/stability.rs
+++ b/compiler/rustc_attr_data_structures/src/stability.rs
@@ -132,6 +132,7 @@ pub enum StabilityLevel {
         /// fn foobar() {}
         /// ```
         implied_by: Option<Symbol>,
+        old_name: Option<Symbol>,
     },
     /// `#[stable]`
     Stable {
diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl
index 45174c9582d..c9443feb021 100644
--- a/compiler/rustc_attr_parsing/messages.ftl
+++ b/compiler/rustc_attr_parsing/messages.ftl
@@ -131,7 +131,15 @@ attr_parsing_unsupported_literal_generic =
 attr_parsing_unsupported_literal_suggestion =
     consider removing the prefix
 
+attr_parsing_unused_duplicate =
+    unused attribute
+    .suggestion = remove this attribute
+    .note = attribute also specified here
+    .warn = {-passes_previously_accepted}
 attr_parsing_unused_multiple =
     multiple `{$name}` attributes
     .suggestion = remove this attribute
     .note = attribute also specified here
+
+-attr_parsing_perviously_accepted =
+    this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
index d0465546b73..81192f902a2 100644
--- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
@@ -4,41 +4,43 @@ use rustc_attr_data_structures::AttributeKind;
 use rustc_span::{Span, Symbol, sym};
 
 use super::{CombineAttributeParser, ConvertFn};
-use crate::context::AcceptContext;
+use crate::context::{AcceptContext, Stage};
 use crate::parser::ArgParser;
 use crate::session_diagnostics;
 
 pub(crate) struct AllowInternalUnstableParser;
-impl CombineAttributeParser for AllowInternalUnstableParser {
-    const PATH: &'static [Symbol] = &[sym::allow_internal_unstable];
+impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
+    const PATH: &[Symbol] = &[sym::allow_internal_unstable];
     type Item = (Symbol, Span);
     const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowInternalUnstable;
 
-    fn extend<'a>(
-        cx: &'a AcceptContext<'a>,
-        args: &'a ArgParser<'a>,
-    ) -> impl IntoIterator<Item = Self::Item> + 'a {
-        parse_unstable(cx, args, Self::PATH[0]).into_iter().zip(iter::repeat(cx.attr_span))
+    fn extend<'c>(
+        cx: &'c mut AcceptContext<'_, '_, S>,
+        args: &'c ArgParser<'_>,
+    ) -> impl IntoIterator<Item = Self::Item> {
+        parse_unstable(cx, args, <Self as CombineAttributeParser<S>>::PATH[0])
+            .into_iter()
+            .zip(iter::repeat(cx.attr_span))
     }
 }
 
 pub(crate) struct AllowConstFnUnstableParser;
-impl CombineAttributeParser for AllowConstFnUnstableParser {
-    const PATH: &'static [Symbol] = &[sym::rustc_allow_const_fn_unstable];
+impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
+    const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable];
     type Item = Symbol;
     const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowConstFnUnstable;
 
-    fn extend<'a>(
-        cx: &'a AcceptContext<'a>,
-        args: &'a ArgParser<'a>,
-    ) -> impl IntoIterator<Item = Self::Item> + 'a {
-        parse_unstable(cx, args, Self::PATH[0])
+    fn extend<'c>(
+        cx: &'c mut AcceptContext<'_, '_, S>,
+        args: &'c ArgParser<'_>,
+    ) -> impl IntoIterator<Item = Self::Item> + 'c {
+        parse_unstable(cx, args, <Self as CombineAttributeParser<S>>::PATH[0])
     }
 }
 
-fn parse_unstable<'a>(
-    cx: &AcceptContext<'_>,
-    args: &'a ArgParser<'a>,
+fn parse_unstable<S: Stage>(
+    cx: &AcceptContext<'_, '_, S>,
+    args: &ArgParser<'_>,
     symbol: Symbol,
 ) -> impl IntoIterator<Item = Symbol> {
     let mut res = Vec::new();
diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs
index 6cff952fcf2..afd3c012f05 100644
--- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs
@@ -3,7 +3,7 @@ use rustc_span::{Span, Symbol, sym};
 use thin_vec::ThinVec;
 
 use super::{AcceptMapping, AttributeParser};
-use crate::context::FinalizeContext;
+use crate::context::{FinalizeContext, Stage};
 use crate::session_diagnostics;
 
 #[derive(Default)]
@@ -12,8 +12,8 @@ pub(crate) struct ConfusablesParser {
     first_span: Option<Span>,
 }
 
-impl AttributeParser for ConfusablesParser {
-    const ATTRIBUTES: AcceptMapping<Self> = &[(&[sym::rustc_confusables], |this, cx, args| {
+impl<S: Stage> AttributeParser<S> for ConfusablesParser {
+    const ATTRIBUTES: AcceptMapping<Self, S> = &[(&[sym::rustc_confusables], |this, cx, args| {
         let Some(list) = args.list() else {
             // FIXME(jdonszelmann): error when not a list? Bring validation code here.
             //       NOTE: currently subsequent attributes are silently ignored using
@@ -45,7 +45,7 @@ impl AttributeParser for ConfusablesParser {
         this.first_span.get_or_insert(cx.attr_span);
     })];
 
-    fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
+    fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         if self.confusables.is_empty() {
             return None;
         }
diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
index 006c1fe3b9c..1faee41c2a9 100644
--- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
@@ -1,17 +1,17 @@
 use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation};
 use rustc_span::{Span, Symbol, sym};
 
-use super::SingleAttributeParser;
 use super::util::parse_version;
-use crate::context::AcceptContext;
+use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
+use crate::context::{AcceptContext, Stage};
 use crate::parser::ArgParser;
 use crate::session_diagnostics;
 use crate::session_diagnostics::UnsupportedLiteralReason;
 
 pub(crate) struct DeprecationParser;
 
-fn get(
-    cx: &AcceptContext<'_>,
+fn get<S: Stage>(
+    cx: &AcceptContext<'_, '_, S>,
     name: Symbol,
     param_span: Span,
     arg: &ArgParser<'_>,
@@ -41,19 +41,12 @@ fn get(
     }
 }
 
-impl SingleAttributeParser for DeprecationParser {
-    const PATH: &'static [Symbol] = &[sym::deprecated];
+impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
+    const PATH: &[Symbol] = &[sym::deprecated];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
 
-    fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span) {
-        // FIXME(jdonszelmann): merge with errors from check_attrs.rs
-        cx.emit_err(session_diagnostics::UnusedMultiple {
-            this: cx.attr_span,
-            other: first_span,
-            name: sym::deprecated,
-        });
-    }
-
-    fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let features = cx.features();
 
         let mut since = None;
diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs
new file mode 100644
index 00000000000..c7f82082c2e
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs
@@ -0,0 +1,97 @@
+// FIXME(jdonszelmann): merge these two parsers and error when both attributes are present here.
+//                      note: need to model better how duplicate attr errors work when not using
+//                      SingleAttributeParser which is what we have two of here.
+
+use rustc_attr_data_structures::lints::AttributeLintKind;
+use rustc_attr_data_structures::{AttributeKind, InlineAttr};
+use rustc_feature::{AttributeTemplate, template};
+use rustc_span::{Symbol, sym};
+
+use super::{AcceptContext, AttributeOrder, OnDuplicate};
+use crate::attributes::SingleAttributeParser;
+use crate::context::Stage;
+use crate::parser::ArgParser;
+
+pub(crate) struct InlineParser;
+
+impl<S: Stage> SingleAttributeParser<S> for InlineParser {
+    const PATH: &'static [Symbol] = &[sym::inline];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
+    const TEMPLATE: AttributeTemplate = template!(Word, List: "always|never");
+
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        match args {
+            ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)),
+            ArgParser::List(list) => {
+                let Some(l) = list.single() else {
+                    cx.expected_single_argument(list.span);
+                    return None;
+                };
+
+                match l.meta_item().and_then(|i| i.word_without_args().map(|i| i.name)) {
+                    Some(sym::always) => {
+                        Some(AttributeKind::Inline(InlineAttr::Always, cx.attr_span))
+                    }
+                    Some(sym::never) => {
+                        Some(AttributeKind::Inline(InlineAttr::Never, cx.attr_span))
+                    }
+                    _ => {
+                        cx.expected_specific_argument(l.span(), vec!["always", "never"]);
+                        return None;
+                    }
+                }
+            }
+            ArgParser::NameValue(_) => {
+                let suggestions =
+                    <Self as SingleAttributeParser<S>>::TEMPLATE.suggestions(false, "inline");
+                cx.emit_lint(
+                    AttributeLintKind::IllFormedAttributeInput { suggestions },
+                    cx.attr_span,
+                );
+                return None;
+            }
+        }
+    }
+}
+
+pub(crate) struct RustcForceInlineParser;
+
+impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
+    const PATH: &'static [Symbol] = &[sym::rustc_force_inline];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
+    const TEMPLATE: AttributeTemplate = template!(Word, List: "reason", NameValueStr: "reason");
+
+    fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        let reason = match args {
+            ArgParser::NoArgs => None,
+            ArgParser::List(list) => {
+                let Some(l) = list.single() else {
+                    cx.expected_single_argument(list.span);
+                    return None;
+                };
+
+                let Some(reason) = l.lit().and_then(|i| i.kind.str()) else {
+                    cx.expected_string_literal(l.span());
+                    return None;
+                };
+
+                Some(reason)
+            }
+            ArgParser::NameValue(v) => {
+                let Some(reason) = v.value_as_str() else {
+                    cx.expected_string_literal(v.value_span);
+                    return None;
+                };
+
+                Some(reason)
+            }
+        };
+
+        Some(AttributeKind::Inline(
+            InlineAttr::Force { attr_span: cx.attr_span, reason },
+            cx.attr_span,
+        ))
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index bf18e10e19f..caf55e6685e 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -12,16 +12,18 @@
 //! - [`CombineAttributeParser`]: makes it easy to implement an attribute which should combine the
 //! contents of attributes, if an attribute appear multiple times in a list
 //!
-//! Attributes should be added to [`ATTRIBUTE_MAPPING`](crate::context::ATTRIBUTE_MAPPING) to be parsed.
+//! Attributes should be added to `crate::context::ATTRIBUTE_PARSERS` to be parsed.
 
 use std::marker::PhantomData;
 
 use rustc_attr_data_structures::AttributeKind;
+use rustc_attr_data_structures::lints::AttributeLintKind;
 use rustc_span::{Span, Symbol};
 use thin_vec::ThinVec;
 
-use crate::context::{AcceptContext, FinalizeContext};
+use crate::context::{AcceptContext, FinalizeContext, Stage};
 use crate::parser::ArgParser;
+use crate::session_diagnostics::UnusedMultiple;
 
 pub(crate) mod allow_unstable;
 pub(crate) mod cfg;
@@ -32,8 +34,8 @@ pub(crate) mod stability;
 pub(crate) mod transparency;
 pub(crate) mod util;
 
-type AcceptFn<T> = fn(&mut T, &AcceptContext<'_>, &ArgParser<'_>);
-type AcceptMapping<T> = &'static [(&'static [Symbol], AcceptFn<T>)];
+type AcceptFn<T, S> = for<'sess> fn(&mut T, &mut AcceptContext<'_, 'sess, S>, &ArgParser<'_>);
+type AcceptMapping<T, S> = &'static [(&'static [Symbol], AcceptFn<T, S>)];
 
 /// An [`AttributeParser`] is a type which searches for syntactic attributes.
 ///
@@ -51,15 +53,24 @@ type AcceptMapping<T> = &'static [(&'static [Symbol], AcceptFn<T>)];
 /// whether it has seen the attribute it has been looking for.
 ///
 /// The state machine is automatically reset to parse attributes on the next item.
-pub(crate) trait AttributeParser: Default + 'static {
+///
+/// For a simpler attribute parsing interface, consider using [`SingleAttributeParser`]
+/// or [`CombineAttributeParser`] instead.
+pub(crate) trait AttributeParser<S: Stage>: Default + 'static {
     /// The symbols for the attributes that this parser is interested in.
     ///
     /// If an attribute has this symbol, the `accept` function will be called on it.
-    const ATTRIBUTES: AcceptMapping<Self>;
+    const ATTRIBUTES: AcceptMapping<Self, S>;
 
     /// The parser has gotten a chance to accept the attributes on an item,
     /// here it can produce an attribute.
-    fn finalize(self, cx: &FinalizeContext<'_>) -> Option<AttributeKind>;
+    ///
+    /// All finalize methods of all parsers are unconditionally called.
+    /// This means you can't unconditionally return `Some` here,
+    /// that'd be equivalent to unconditionally applying an attribute to
+    /// every single syntax item that could have attributes applied to it.
+    /// Your accept mappings should determine whether this returns something.
+    fn finalize(self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind>;
 }
 
 /// Alternative to [`AttributeParser`] that automatically handles state management.
@@ -71,43 +82,130 @@ pub(crate) trait AttributeParser: Default + 'static {
 ///
 /// [`SingleAttributeParser`] can only convert attributes one-to-one, and cannot combine multiple
 /// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example.
-pub(crate) trait SingleAttributeParser: 'static {
-    const PATH: &'static [Symbol];
-
-    /// Called when a duplicate attribute is found.
-    ///
-    /// `first_span` is the span of the first occurrence of this attribute.
-    // FIXME(jdonszelmann): default error
-    fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span);
+pub(crate) trait SingleAttributeParser<S: Stage>: 'static {
+    const PATH: &[Symbol];
+    const ATTRIBUTE_ORDER: AttributeOrder;
+    const ON_DUPLICATE: OnDuplicate<S>;
 
     /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`]
-    fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind>;
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind>;
 }
 
-pub(crate) struct Single<T: SingleAttributeParser>(PhantomData<T>, Option<(AttributeKind, Span)>);
+pub(crate) struct Single<T: SingleAttributeParser<S>, S: Stage>(
+    PhantomData<(S, T)>,
+    Option<(AttributeKind, Span)>,
+);
 
-impl<T: SingleAttributeParser> Default for Single<T> {
+impl<T: SingleAttributeParser<S>, S: Stage> Default for Single<T, S> {
     fn default() -> Self {
         Self(Default::default(), Default::default())
     }
 }
 
-impl<T: SingleAttributeParser> AttributeParser for Single<T> {
-    const ATTRIBUTES: AcceptMapping<Self> = &[(T::PATH, |group: &mut Single<T>, cx, args| {
-        if let Some((_, s)) = group.1 {
-            T::on_duplicate(cx, s);
-            return;
-        }
+impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S> {
+    const ATTRIBUTES: AcceptMapping<Self, S> =
+        &[(T::PATH, |group: &mut Single<T, S>, cx, args| {
+            if let Some(pa) = T::convert(cx, args) {
+                match T::ATTRIBUTE_ORDER {
+                    // keep the first and report immediately. ignore this attribute
+                    AttributeOrder::KeepFirst => {
+                        if let Some((_, unused)) = group.1 {
+                            T::ON_DUPLICATE.exec::<T>(cx, cx.attr_span, unused);
+                            return;
+                        }
+                    }
+                    // keep the new one and warn about the previous,
+                    // then replace
+                    AttributeOrder::KeepLast => {
+                        if let Some((_, used)) = group.1 {
+                            T::ON_DUPLICATE.exec::<T>(cx, used, cx.attr_span);
+                        }
+                    }
+                }
+
+                group.1 = Some((pa, cx.attr_span));
+            }
+        })];
+
+    fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
+        Some(self.1?.0)
+    }
+}
 
-        if let Some(pa) = T::convert(cx, args) {
-            group.1 = Some((pa, cx.attr_span));
-        }
-    })];
+// FIXME(jdonszelmann): logic is implemented but the attribute parsers needing
+// them will be merged in another PR
+#[allow(unused)]
+pub(crate) enum OnDuplicate<S: Stage> {
+    /// Give a default warning
+    Warn,
 
-    fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
-        Some(self.1?.0)
+    /// Duplicates will be a warning, with a note that this will be an error in the future.
+    WarnButFutureError,
+
+    /// Give a default error
+    Error,
+
+    /// Ignore duplicates
+    Ignore,
+
+    /// Custom function called when a duplicate attribute is found.
+    ///
+    /// - `unused` is the span of the attribute that was unused or bad because of some
+    ///   duplicate reason (see [`AttributeOrder`])
+    /// - `used` is the span of the attribute that was used in favor of the unused attribute
+    Custom(fn(cx: &AcceptContext<'_, '_, S>, used: Span, unused: Span)),
+}
+
+impl<S: Stage> OnDuplicate<S> {
+    fn exec<P: SingleAttributeParser<S>>(
+        &self,
+        cx: &mut AcceptContext<'_, '_, S>,
+        used: Span,
+        unused: Span,
+    ) {
+        match self {
+            OnDuplicate::Warn => cx.emit_lint(
+                AttributeLintKind::UnusedDuplicate { this: unused, other: used, warning: false },
+                unused,
+            ),
+            OnDuplicate::WarnButFutureError => cx.emit_lint(
+                AttributeLintKind::UnusedDuplicate { this: unused, other: used, warning: true },
+                unused,
+            ),
+            OnDuplicate::Error => {
+                cx.emit_err(UnusedMultiple {
+                    this: used,
+                    other: unused,
+                    name: Symbol::intern(
+                        &P::PATH.into_iter().map(|i| i.to_string()).collect::<Vec<_>>().join(".."),
+                    ),
+                });
+            }
+            OnDuplicate::Ignore => {}
+            OnDuplicate::Custom(f) => f(cx, used, unused),
+        }
     }
 }
+//
+// FIXME(jdonszelmann): logic is implemented but the attribute parsers needing
+// them will be merged in another PR
+#[allow(unused)]
+pub(crate) enum AttributeOrder {
+    /// Duplicates after the first attribute will be an error.
+    ///
+    /// This should be used where duplicates would be ignored, but carry extra
+    /// meaning that could cause confusion. For example, `#[stable(since="1.0")]
+    /// #[stable(since="2.0")]`, which version should be used for `stable`?
+    KeepFirst,
+
+    /// Duplicates preceding the last instance of the attribute will be a
+    /// warning, with a note that this will be an error in the future.
+    ///
+    /// This is the same as `FutureWarnFollowing`, except the last attribute is
+    /// the one that is "used". Ideally these can eventually migrate to
+    /// `ErrorPreceding`.
+    KeepLast,
+}
 
 type ConvertFn<E> = fn(ThinVec<E>) -> AttributeKind;
 
@@ -118,35 +216,35 @@ type ConvertFn<E> = fn(ThinVec<E>) -> AttributeKind;
 ///
 /// [`CombineAttributeParser`] can only convert a single kind of attribute, and cannot combine multiple
 /// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example.
-pub(crate) trait CombineAttributeParser: 'static {
-    const PATH: &'static [Symbol];
+pub(crate) trait CombineAttributeParser<S: Stage>: 'static {
+    const PATH: &[rustc_span::Symbol];
 
     type Item;
     const CONVERT: ConvertFn<Self::Item>;
 
     /// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`]
-    fn extend<'a>(
-        cx: &'a AcceptContext<'a>,
-        args: &'a ArgParser<'a>,
-    ) -> impl IntoIterator<Item = Self::Item> + 'a;
+    fn extend<'c>(
+        cx: &'c mut AcceptContext<'_, '_, S>,
+        args: &'c ArgParser<'_>,
+    ) -> impl IntoIterator<Item = Self::Item> + 'c;
 }
 
-pub(crate) struct Combine<T: CombineAttributeParser>(
-    PhantomData<T>,
-    ThinVec<<T as CombineAttributeParser>::Item>,
+pub(crate) struct Combine<T: CombineAttributeParser<S>, S: Stage>(
+    PhantomData<(S, T)>,
+    ThinVec<<T as CombineAttributeParser<S>>::Item>,
 );
 
-impl<T: CombineAttributeParser> Default for Combine<T> {
+impl<T: CombineAttributeParser<S>, S: Stage> Default for Combine<T, S> {
     fn default() -> Self {
         Self(Default::default(), Default::default())
     }
 }
 
-impl<T: CombineAttributeParser> AttributeParser for Combine<T> {
-    const ATTRIBUTES: AcceptMapping<Self> =
-        &[(T::PATH, |group: &mut Combine<T>, cx, args| group.1.extend(T::extend(cx, args)))];
+impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S> {
+    const ATTRIBUTES: AcceptMapping<Self, S> =
+        &[(T::PATH, |group: &mut Combine<T, S>, cx, args| group.1.extend(T::extend(cx, args)))];
 
-    fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
+    fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         if self.1.is_empty() { None } else { Some(T::CONVERT(self.1)) }
     }
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs
index 69316541e19..753b2366b41 100644
--- a/compiler/rustc_attr_parsing/src/attributes/repr.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs
@@ -4,7 +4,7 @@ use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr};
 use rustc_span::{DUMMY_SP, Span, Symbol, sym};
 
 use super::{CombineAttributeParser, ConvertFn};
-use crate::context::AcceptContext;
+use crate::context::{AcceptContext, Stage};
 use crate::parser::{ArgParser, MetaItemListParser, MetaItemParser};
 use crate::session_diagnostics;
 use crate::session_diagnostics::IncorrectReprFormatGenericCause;
@@ -19,15 +19,15 @@ use crate::session_diagnostics::IncorrectReprFormatGenericCause;
 // FIXME(jdonszelmann): is a vec the right representation here even? isn't it just a struct?
 pub(crate) struct ReprParser;
 
-impl CombineAttributeParser for ReprParser {
+impl<S: Stage> CombineAttributeParser<S> for ReprParser {
     type Item = (ReprAttr, Span);
-    const PATH: &'static [Symbol] = &[sym::repr];
+    const PATH: &[Symbol] = &[sym::repr];
     const CONVERT: ConvertFn<Self::Item> = AttributeKind::Repr;
 
-    fn extend<'a>(
-        cx: &'a AcceptContext<'a>,
-        args: &'a ArgParser<'a>,
-    ) -> impl IntoIterator<Item = Self::Item> + 'a {
+    fn extend<'c>(
+        cx: &'c mut AcceptContext<'_, '_, S>,
+        args: &'c ArgParser<'_>,
+    ) -> impl IntoIterator<Item = Self::Item> + 'c {
         let mut reprs = Vec::new();
 
         let Some(list) = args.list() else {
@@ -91,7 +91,10 @@ fn int_type_of_word(s: Symbol) -> Option<IntType> {
     }
 }
 
-fn parse_repr(cx: &AcceptContext<'_>, param: &MetaItemParser<'_>) -> Option<ReprAttr> {
+fn parse_repr<S: Stage>(
+    cx: &AcceptContext<'_, '_, S>,
+    param: &MetaItemParser<'_>,
+) -> Option<ReprAttr> {
     use ReprAttr::*;
 
     // FIXME(jdonszelmann): invert the parsing here to match on the word first and then the
@@ -180,8 +183,8 @@ enum AlignKind {
     Align,
 }
 
-fn parse_repr_align(
-    cx: &AcceptContext<'_>,
+fn parse_repr_align<S: Stage>(
+    cx: &AcceptContext<'_, '_, S>,
     list: &MetaItemListParser<'_>,
     param_span: Span,
     align_kind: AlignKind,
diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs
index ce69a54513d..6589a51db2b 100644
--- a/compiler/rustc_attr_parsing/src/attributes/stability.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs
@@ -8,8 +8,8 @@ use rustc_errors::ErrorGuaranteed;
 use rustc_span::{Span, Symbol, sym};
 
 use super::util::parse_version;
-use super::{AcceptMapping, AttributeParser, SingleAttributeParser};
-use crate::context::{AcceptContext, FinalizeContext};
+use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser};
+use crate::context::{AcceptContext, FinalizeContext, Stage};
 use crate::parser::{ArgParser, MetaItemParser};
 use crate::session_diagnostics::{self, UnsupportedLiteralReason};
 
@@ -31,7 +31,7 @@ pub(crate) struct StabilityParser {
 
 impl StabilityParser {
     /// Checks, and emits an error when a stability (or unstability) was already set, which would be a duplicate.
-    fn check_duplicate(&self, cx: &AcceptContext<'_>) -> bool {
+    fn check_duplicate<S: Stage>(&self, cx: &AcceptContext<'_, '_, S>) -> bool {
         if let Some((_, _)) = self.stability {
             cx.emit_err(session_diagnostics::MultipleStabilityLevels { span: cx.attr_span });
             true
@@ -41,8 +41,8 @@ impl StabilityParser {
     }
 }
 
-impl AttributeParser for StabilityParser {
-    const ATTRIBUTES: AcceptMapping<Self> = &[
+impl<S: Stage> AttributeParser<S> for StabilityParser {
+    const ATTRIBUTES: AcceptMapping<Self, S> = &[
         (&[sym::stable], |this, cx, args| {
             reject_outside_std!(cx);
             if !this.check_duplicate(cx)
@@ -65,7 +65,7 @@ impl AttributeParser for StabilityParser {
         }),
     ];
 
-    fn finalize(mut self, cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
+    fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         if let Some(atum) = self.allowed_through_unstable_modules {
             if let Some((
                 Stability {
@@ -95,8 +95,8 @@ pub(crate) struct BodyStabilityParser {
     stability: Option<(DefaultBodyStability, Span)>,
 }
 
-impl AttributeParser for BodyStabilityParser {
-    const ATTRIBUTES: AcceptMapping<Self> =
+impl<S: Stage> AttributeParser<S> for BodyStabilityParser {
+    const ATTRIBUTES: AcceptMapping<Self, S> =
         &[(&[sym::rustc_default_body_unstable], |this, cx, args| {
             reject_outside_std!(cx);
             if this.stability.is_some() {
@@ -107,7 +107,7 @@ impl AttributeParser for BodyStabilityParser {
             }
         })];
 
-    fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
+    fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         let (stability, span) = self.stability?;
 
         Some(AttributeKind::BodyStability { stability, span })
@@ -116,13 +116,12 @@ impl AttributeParser for BodyStabilityParser {
 
 pub(crate) struct ConstStabilityIndirectParser;
 // FIXME(jdonszelmann): single word attribute group when we have these
-impl SingleAttributeParser for ConstStabilityIndirectParser {
-    const PATH: &'static [Symbol] = &[sym::rustc_const_stable_indirect];
+impl<S: Stage> SingleAttributeParser<S> for ConstStabilityIndirectParser {
+    const PATH: &[Symbol] = &[sym::rustc_const_stable_indirect];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore;
 
-    // ignore
-    fn on_duplicate(_cx: &AcceptContext<'_>, _first_span: Span) {}
-
-    fn convert(_cx: &AcceptContext<'_>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
+    fn convert(_cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
         Some(AttributeKind::ConstStabilityIndirect)
     }
 }
@@ -135,7 +134,7 @@ pub(crate) struct ConstStabilityParser {
 
 impl ConstStabilityParser {
     /// Checks, and emits an error when a stability (or unstability) was already set, which would be a duplicate.
-    fn check_duplicate(&self, cx: &AcceptContext<'_>) -> bool {
+    fn check_duplicate<S: Stage>(&self, cx: &AcceptContext<'_, '_, S>) -> bool {
         if let Some((_, _)) = self.stability {
             cx.emit_err(session_diagnostics::MultipleStabilityLevels { span: cx.attr_span });
             true
@@ -145,8 +144,8 @@ impl ConstStabilityParser {
     }
 }
 
-impl AttributeParser for ConstStabilityParser {
-    const ATTRIBUTES: AcceptMapping<Self> = &[
+impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
+    const ATTRIBUTES: AcceptMapping<Self, S> = &[
         (&[sym::rustc_const_stable], |this, cx, args| {
             reject_outside_std!(cx);
 
@@ -176,7 +175,7 @@ impl AttributeParser for ConstStabilityParser {
         }),
     ];
 
-    fn finalize(mut self, cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
+    fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         if self.promotable {
             if let Some((ref mut stab, _)) = self.stability {
                 stab.promotable = true;
@@ -196,8 +195,8 @@ impl AttributeParser for ConstStabilityParser {
 ///
 /// Emits an error when either the option was already Some, or the arguments weren't of form
 /// `name = value`
-fn insert_value_into_option_or_error(
-    cx: &AcceptContext<'_>,
+fn insert_value_into_option_or_error<S: Stage>(
+    cx: &AcceptContext<'_, '_, S>,
     param: &MetaItemParser<'_>,
     item: &mut Option<Symbol>,
 ) -> Option<()> {
@@ -223,8 +222,8 @@ fn insert_value_into_option_or_error(
 
 /// Read the content of a `stable`/`rustc_const_stable` attribute, and return the feature name and
 /// its stability information.
-pub(crate) fn parse_stability(
-    cx: &AcceptContext<'_>,
+pub(crate) fn parse_stability<S: Stage>(
+    cx: &AcceptContext<'_, '_, S>,
     args: &ArgParser<'_>,
 ) -> Option<(Symbol, StabilityLevel)> {
     let mut feature = None;
@@ -289,8 +288,8 @@ pub(crate) fn parse_stability(
 
 // Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable`
 /// attribute, and return the feature name and its stability information.
-pub(crate) fn parse_unstability(
-    cx: &AcceptContext<'_>,
+pub(crate) fn parse_unstability<S: Stage>(
+    cx: &AcceptContext<'_, '_, S>,
     args: &ArgParser<'_>,
 ) -> Option<(Symbol, StabilityLevel)> {
     let mut feature = None;
@@ -299,6 +298,7 @@ pub(crate) fn parse_unstability(
     let mut issue_num = None;
     let mut is_soft = false;
     let mut implied_by = None;
+    let mut old_name = None;
     for param in args.list()?.mixed() {
         let Some(param) = param.meta_item() else {
             cx.emit_err(session_diagnostics::UnsupportedLiteral {
@@ -346,11 +346,12 @@ pub(crate) fn parse_unstability(
             Some(sym::implied_by) => {
                 insert_value_into_option_or_error(cx, &param, &mut implied_by)?
             }
+            Some(sym::old_name) => insert_value_into_option_or_error(cx, &param, &mut old_name)?,
             _ => {
                 cx.emit_err(session_diagnostics::UnknownMetaItem {
                     span: param.span(),
                     item: param.path().to_string(),
-                    expected: &["feature", "reason", "issue", "soft", "implied_by"],
+                    expected: &["feature", "reason", "issue", "soft", "implied_by", "old_name"],
                 });
                 return None;
             }
@@ -375,6 +376,7 @@ pub(crate) fn parse_unstability(
                 issue: issue_num,
                 is_soft,
                 implied_by,
+                old_name,
             };
             Some((feature, level))
         }
diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs
index d229fc09740..16ad9d03e50 100644
--- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs
@@ -1,8 +1,9 @@
 use rustc_attr_data_structures::AttributeKind;
 use rustc_span::hygiene::Transparency;
-use rustc_span::{Span, Symbol, sym};
+use rustc_span::{Symbol, sym};
 
-use super::{AcceptContext, SingleAttributeParser};
+use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
+use crate::context::{AcceptContext, Stage};
 use crate::parser::ArgParser;
 
 pub(crate) struct TransparencyParser;
@@ -10,14 +11,14 @@ pub(crate) struct TransparencyParser;
 // FIXME(jdonszelmann): make these proper diagnostics
 #[allow(rustc::untranslatable_diagnostic)]
 #[allow(rustc::diagnostic_outside_of_impl)]
-impl SingleAttributeParser for TransparencyParser {
-    const PATH: &'static [Symbol] = &[sym::rustc_macro_transparency];
+impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
+    const PATH: &[Symbol] = &[sym::rustc_macro_transparency];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Custom(|cx, used, unused| {
+        cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes");
+    });
 
-    fn on_duplicate(cx: &crate::context::AcceptContext<'_>, first_span: Span) {
-        cx.dcx().span_err(vec![first_span, cx.attr_span], "multiple macro transparency attributes");
-    }
-
-    fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         match args.name_value().and_then(|nv| nv.value_as_str()) {
             Some(sym::transparent) => Some(Transparency::Transparent),
             Some(sym::semiopaque | sym::semitransparent) => Some(Transparency::SemiOpaque),
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index c02760d830c..47f72232828 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -1,13 +1,17 @@
 use std::cell::RefCell;
 use std::collections::BTreeMap;
-use std::ops::Deref;
+use std::marker::PhantomData;
+use std::ops::{Deref, DerefMut};
 use std::sync::LazyLock;
 
+use private::Sealed;
 use rustc_ast as ast;
+use rustc_ast::NodeId;
 use rustc_attr_data_structures::AttributeKind;
+use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind};
 use rustc_errors::{DiagCtxtHandle, Diagnostic};
 use rustc_feature::Features;
-use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId};
+use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId};
 use rustc_session::Session;
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
 
@@ -22,20 +26,40 @@ use crate::attributes::transparency::TransparencyParser;
 use crate::attributes::{AttributeParser as _, Combine, Single};
 use crate::parser::{ArgParser, MetaItemParser};
 
-macro_rules! attribute_groups {
+macro_rules! group_type {
+    ($stage: ty) => {
+         LazyLock<(
+            BTreeMap<&'static [Symbol], Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $stage>, &ArgParser<'a>) + Send + Sync>>,
+            Vec<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $stage>) -> Option<AttributeKind>>>
+        )>
+    };
+}
+
+macro_rules! attribute_parsers {
     (
         pub(crate) static $name: ident = [$($names: ty),* $(,)?];
     ) => {
-        type Accepts = BTreeMap<
-            &'static [Symbol],
-            Box<dyn Send + Sync + Fn(&AcceptContext<'_>, &ArgParser<'_>)>
-        >;
-        type Finalizes = Vec<
-            Box<dyn Send + Sync + Fn(&FinalizeContext<'_>) -> Option<AttributeKind>>
-        >;
-        pub(crate) static $name: LazyLock<(Accepts, Finalizes)> = LazyLock::new(|| {
-            let mut accepts = Accepts::new();
-            let mut finalizes = Finalizes::new();
+        mod early {
+            use super::*;
+            type Combine<T> = super::Combine<T, Early>;
+            type Single<T> = super::Single<T, Early>;
+
+            attribute_parsers!(@[Early] pub(crate) static $name = [$($names),*];);
+        }
+        mod late {
+            use super::*;
+            type Combine<T> = super::Combine<T, Late>;
+            type Single<T> = super::Single<T, Late>;
+
+            attribute_parsers!(@[Late] pub(crate) static $name = [$($names),*];);
+        }
+    };
+    (
+        @[$ty: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
+    ) => {
+        pub(crate) static $name: group_type!($ty) = LazyLock::new(|| {
+            let mut accepts = BTreeMap::<_, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $ty>, &ArgParser<'a>) + Send + Sync>>::new();
+            let mut finalizes = Vec::<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $ty>) -> Option<AttributeKind>>>::new();
             $(
                 {
                     thread_local! {
@@ -62,9 +86,8 @@ macro_rules! attribute_groups {
         });
     };
 }
-
-attribute_groups!(
-    pub(crate) static ATTRIBUTE_MAPPING = [
+attribute_parsers!(
+    pub(crate) static ATTRIBUTE_PARSERS = [
         // tidy-alphabetical-start
         BodyStabilityParser,
         ConfusablesParser,
@@ -86,30 +109,84 @@ attribute_groups!(
     ];
 );
 
+mod private {
+    pub trait Sealed {}
+    impl Sealed for super::Early {}
+    impl Sealed for super::Late {}
+}
+
+// allow because it's a sealed trait
+#[allow(private_interfaces)]
+pub trait Stage: Sized + 'static + Sealed {
+    type Id: Copy;
+
+    fn parsers() -> &'static group_type!(Self);
+
+    fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed;
+}
+
+// allow because it's a sealed trait
+#[allow(private_interfaces)]
+impl Stage for Early {
+    type Id = NodeId;
+
+    fn parsers() -> &'static group_type!(Self) {
+        &early::ATTRIBUTE_PARSERS
+    }
+    fn emit_err<'sess>(sess: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
+        sess.dcx().create_err(diag).delay_as_bug()
+    }
+}
+
+// allow because it's a sealed trait
+#[allow(private_interfaces)]
+impl Stage for Late {
+    type Id = HirId;
+
+    fn parsers() -> &'static group_type!(Self) {
+        &late::ATTRIBUTE_PARSERS
+    }
+    fn emit_err<'sess>(tcx: &'sess Session, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
+        tcx.dcx().emit_err(diag)
+    }
+}
+
+/// used when parsing attributes for miscelaneous things *before* ast lowering
+pub struct Early;
+/// used when parsing attributes during ast lowering
+pub struct Late;
+
 /// Context given to every attribute parser when accepting
 ///
 /// Gives [`AttributeParser`]s enough information to create errors, for example.
-pub(crate) struct AcceptContext<'a> {
-    pub(crate) group_cx: &'a FinalizeContext<'a>,
+pub(crate) struct AcceptContext<'f, 'sess, S: Stage> {
+    pub(crate) finalize_cx: FinalizeContext<'f, 'sess, S>,
     /// The span of the attribute currently being parsed
     pub(crate) attr_span: Span,
 }
 
-impl<'a> AcceptContext<'a> {
-    pub(crate) fn emit_err(&self, diag: impl Diagnostic<'a>) -> ErrorGuaranteed {
-        if self.limit_diagnostics {
-            self.dcx().create_err(diag).delay_as_bug()
-        } else {
-            self.dcx().emit_err(diag)
-        }
+impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
+    pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed {
+        S::emit_err(&self.sess, diag)
+    }
+
+    pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) {
+        let id = self.target_id;
+        (self.emit_lint)(AttributeLint { id, span, kind: lint });
     }
 }
 
-impl<'a> Deref for AcceptContext<'a> {
-    type Target = FinalizeContext<'a>;
+impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> {
+    type Target = FinalizeContext<'f, 'sess, S>;
 
     fn deref(&self) -> &Self::Target {
-        &self.group_cx
+        &self.finalize_cx
+    }
+}
+
+impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.finalize_cx
     }
 }
 
@@ -117,19 +194,29 @@ impl<'a> Deref for AcceptContext<'a> {
 ///
 /// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create
 /// errors, for example.
-pub(crate) struct FinalizeContext<'a> {
+pub(crate) struct FinalizeContext<'p, 'sess, S: Stage> {
     /// The parse context, gives access to the session and the
     /// diagnostics context.
-    pub(crate) cx: &'a AttributeParser<'a>,
+    pub(crate) cx: &'p mut AttributeParser<'sess, S>,
     /// The span of the syntactical component this attribute was applied to
     pub(crate) target_span: Span,
+    /// The id ([`NodeId`] if `S` is `Early`, [`HirId`] if `S` is `Late`) of the syntactical component this attribute was applied to
+    pub(crate) target_id: S::Id,
+
+    pub(crate) emit_lint: &'p mut dyn FnMut(AttributeLint<S::Id>),
 }
 
-impl<'a> Deref for FinalizeContext<'a> {
-    type Target = AttributeParser<'a>;
+impl<'p, 'sess: 'p, S: Stage> Deref for FinalizeContext<'p, 'sess, S> {
+    type Target = AttributeParser<'sess, S>;
 
     fn deref(&self) -> &Self::Target {
-        &self.cx
+        self.cx
+    }
+}
+
+impl<'p, 'sess: 'p, S: Stage> DerefMut for FinalizeContext<'p, 'sess, S> {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        self.cx
     }
 }
 
@@ -141,23 +228,20 @@ pub enum OmitDoc {
 
 /// Context created once, for example as part of the ast lowering
 /// context, through which all attributes can be lowered.
-pub struct AttributeParser<'sess> {
+pub struct AttributeParser<'sess, S: Stage = Late> {
     #[expect(dead_code)] // FIXME(jdonszelmann): needed later to verify we parsed all attributes
     tools: Vec<Symbol>,
-    sess: &'sess Session,
     features: Option<&'sess Features>,
+    sess: &'sess Session,
+    stage: PhantomData<S>,
 
     /// *Only* parse attributes with this symbol.
     ///
     /// Used in cases where we want the lowering infrastructure for parse just a single attribute.
     parse_only: Option<Symbol>,
-
-    /// Can be used to instruct parsers to reduce the number of diagnostics it emits.
-    /// Useful when using `parse_limited` and you know the attr will be reparsed later.
-    pub(crate) limit_diagnostics: bool,
 }
 
-impl<'sess> AttributeParser<'sess> {
+impl<'sess> AttributeParser<'sess, Early> {
     /// This method allows you to parse attributes *before* you have access to features or tools.
     /// One example where this is necessary, is to parse `feature` attributes themselves for
     /// example.
@@ -168,33 +252,53 @@ impl<'sess> AttributeParser<'sess> {
     ///
     /// To make sure use is limited, supply a `Symbol` you'd like to parse. Only attributes with
     /// that symbol are picked out of the list of instructions and parsed. Those are returned.
+    ///
+    /// No diagnostics will be emitted when parsing limited. Lints are not emitted at all, while
+    /// errors will be emitted as a delayed bugs. in other words, we *expect* attributes parsed
+    /// with `parse_limited` to be reparsed later during ast lowering where we *do* emit the errors
     pub fn parse_limited(
         sess: &'sess Session,
         attrs: &[ast::Attribute],
         sym: Symbol,
         target_span: Span,
-        limit_diagnostics: bool,
+        target_node_id: NodeId,
     ) -> Option<Attribute> {
-        let mut parsed = Self {
-            sess,
+        let mut p = Self {
             features: None,
             tools: Vec::new(),
             parse_only: Some(sym),
-            limit_diagnostics,
-        }
-        .parse_attribute_list(attrs, target_span, OmitDoc::Skip, std::convert::identity);
-
+            sess,
+            stage: PhantomData,
+        };
+        let mut parsed = p.parse_attribute_list(
+            attrs,
+            target_span,
+            target_node_id,
+            OmitDoc::Skip,
+            std::convert::identity,
+            |_lint| {
+                panic!("can't emit lints here for now (nothing uses this atm)");
+            },
+        );
         assert!(parsed.len() <= 1);
 
         parsed.pop()
     }
 
+    pub fn new_early(sess: &'sess Session, features: &'sess Features, tools: Vec<Symbol>) -> Self {
+        Self { features: Some(features), tools, parse_only: None, sess, stage: PhantomData }
+    }
+}
+
+impl<'sess> AttributeParser<'sess, Late> {
     pub fn new(sess: &'sess Session, features: &'sess Features, tools: Vec<Symbol>) -> Self {
-        Self { sess, features: Some(features), tools, parse_only: None, limit_diagnostics: false }
+        Self { features: Some(features), tools, parse_only: None, sess, stage: PhantomData }
     }
+}
 
+impl<'sess, S: Stage> AttributeParser<'sess, S> {
     pub(crate) fn sess(&self) -> &'sess Session {
-        self.sess
+        &self.sess
     }
 
     pub(crate) fn features(&self) -> &'sess Features {
@@ -202,25 +306,25 @@ impl<'sess> AttributeParser<'sess> {
     }
 
     pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> {
-        self.sess.dcx()
+        self.sess().dcx()
     }
 
     /// Parse a list of attributes.
     ///
     /// `target_span` is the span of the thing this list of attributes is applied to,
     /// and when `omit_doc` is set, doc attributes are filtered out.
-    pub fn parse_attribute_list<'a>(
-        &'a self,
-        attrs: &'a [ast::Attribute],
+    pub fn parse_attribute_list(
+        &mut self,
+        attrs: &[ast::Attribute],
         target_span: Span,
+        target_id: S::Id,
         omit_doc: OmitDoc,
 
         lower_span: impl Copy + Fn(Span) -> Span,
+        mut emit_lint: impl FnMut(AttributeLint<S::Id>),
     ) -> Vec<Attribute> {
         let mut attributes = Vec::new();
 
-        let group_cx = FinalizeContext { cx: self, target_span };
-
         for attr in attrs {
             // If we're only looking for a single attribute, skip all the ones we don't care about.
             if let Some(expected) = self.parse_only {
@@ -268,11 +372,18 @@ impl<'sess> AttributeParser<'sess> {
                     let args = parser.args();
                     let parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
 
-                    if let Some(accept) = ATTRIBUTE_MAPPING.0.get(parts.as_slice()) {
-                        let cx =
-                            AcceptContext { group_cx: &group_cx, attr_span: lower_span(attr.span) };
-
-                        accept(&cx, &args)
+                    if let Some(accept) = S::parsers().0.get(parts.as_slice()) {
+                        let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
+                            finalize_cx: FinalizeContext {
+                                cx: self,
+                                target_span,
+                                target_id,
+                                emit_lint: &mut emit_lint,
+                            },
+                            attr_span: lower_span(attr.span),
+                        };
+
+                        accept(&mut cx, args)
                     } else {
                         // If we're here, we must be compiling a tool attribute... Or someone
                         // forgot to parse their fancy new attribute. Let's warn them in any case.
@@ -302,8 +413,13 @@ impl<'sess> AttributeParser<'sess> {
         }
 
         let mut parsed_attributes = Vec::new();
-        for f in &ATTRIBUTE_MAPPING.1 {
-            if let Some(attr) = f(&group_cx) {
+        for f in &S::parsers().1 {
+            if let Some(attr) = f(&mut FinalizeContext {
+                cx: self,
+                target_span,
+                target_id,
+                emit_lint: &mut emit_lint,
+            }) {
                 parsed_attributes.push(Attribute::Parsed(attr));
             }
         }
diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs
index 15037e802ff..47eeb63bad3 100644
--- a/compiler/rustc_attr_parsing/src/lib.rs
+++ b/compiler/rustc_attr_parsing/src/lib.rs
@@ -85,7 +85,8 @@
 
 #[macro_use]
 mod attributes;
-mod context;
+pub(crate) mod context;
+mod lints;
 pub mod parser;
 mod session_diagnostics;
 
@@ -93,6 +94,7 @@ pub use attributes::cfg::*;
 pub use attributes::util::{
     find_crate_name, is_builtin_attr, is_doc_alias_attrs_contain_symbol, parse_version,
 };
-pub use context::{AttributeParser, OmitDoc};
+pub use context::{AttributeParser, Early, Late, OmitDoc};
+pub use lints::emit_attribute_lint;
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs
new file mode 100644
index 00000000000..d0d112446b4
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/lints.rs
@@ -0,0 +1,19 @@
+use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind};
+use rustc_errors::LintEmitter;
+use rustc_hir::HirId;
+
+use crate::session_diagnostics;
+
+pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<HirId>, lint_emitter: L) {
+    let AttributeLint { id, span, kind } = lint;
+
+    match kind {
+        &AttributeLintKind::UnusedDuplicate { this, other, warning } => lint_emitter
+            .emit_node_span_lint(
+                rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
+                *id,
+                *span,
+                session_diagnostics::UnusedDuplicate { this, other, warning },
+            ),
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs
index e10e3b511db..1edbe3a9d27 100644
--- a/compiler/rustc_attr_parsing/src/parser.rs
+++ b/compiler/rustc_attr_parsing/src/parser.rs
@@ -115,7 +115,7 @@ impl<'a> ArgParser<'a> {
         }
     }
 
-    pub fn from_attr_args(value: &'a AttrArgs, dcx: DiagCtxtHandle<'a>) -> Self {
+    pub fn from_attr_args<'sess>(value: &'a AttrArgs, dcx: DiagCtxtHandle<'sess>) -> Self {
         match value {
             AttrArgs::Empty => Self::NoArgs,
             AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
@@ -235,7 +235,7 @@ impl<'a> Debug for MetaItemParser<'a> {
 impl<'a> MetaItemParser<'a> {
     /// Create a new parser from a [`NormalAttr`], which is stored inside of any
     /// [`ast::Attribute`](rustc_ast::Attribute)
-    pub fn from_attr(attr: &'a NormalAttr, dcx: DiagCtxtHandle<'a>) -> Self {
+    pub fn from_attr<'sess>(attr: &'a NormalAttr, dcx: DiagCtxtHandle<'sess>) -> Self {
         Self {
             path: PathParser::Ast(&attr.item.path),
             args: ArgParser::from_attr_args(&attr.item.args, dcx),
@@ -320,13 +320,13 @@ fn expr_to_lit(dcx: DiagCtxtHandle<'_>, expr: &Expr, span: Span) -> MetaItemLit
     }
 }
 
-struct MetaItemListParserContext<'a> {
+struct MetaItemListParserContext<'a, 'sess> {
     // the tokens inside the delimiters, so `#[some::attr(a b c)]` would have `a b c` inside
     inside_delimiters: Peekable<TokenStreamIter<'a>>,
-    dcx: DiagCtxtHandle<'a>,
+    dcx: DiagCtxtHandle<'sess>,
 }
 
-impl<'a> MetaItemListParserContext<'a> {
+impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
     fn done(&mut self) -> bool {
         self.inside_delimiters.peek().is_none()
     }
@@ -507,11 +507,11 @@ pub struct MetaItemListParser<'a> {
 }
 
 impl<'a> MetaItemListParser<'a> {
-    fn new(delim: &'a DelimArgs, dcx: DiagCtxtHandle<'a>) -> MetaItemListParser<'a> {
+    fn new<'sess>(delim: &'a DelimArgs, dcx: DiagCtxtHandle<'sess>) -> Self {
         MetaItemListParser::new_tts(delim.tokens.iter(), delim.dspan.entire(), dcx)
     }
 
-    fn new_tts(tts: TokenStreamIter<'a>, span: Span, dcx: DiagCtxtHandle<'a>) -> Self {
+    fn new_tts<'sess>(tts: TokenStreamIter<'a>, span: Span, dcx: DiagCtxtHandle<'sess>) -> Self {
         MetaItemListParserContext { inside_delimiters: tts.peekable(), dcx }.parse(span)
     }
 
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
index 2c434175b4b..7f847d3dd4c 100644
--- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs
+++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -3,7 +3,7 @@ use std::num::IntErrorKind;
 use rustc_ast as ast;
 use rustc_errors::codes::*;
 use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
-use rustc_macros::{Diagnostic, Subdiagnostic};
+use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_span::{Span, Symbol};
 
 use crate::fluent_generated as fluent;
@@ -451,6 +451,17 @@ pub(crate) struct UnusedMultiple {
     pub name: Symbol,
 }
 
+#[derive(LintDiagnostic)]
+#[diag(attr_parsing_unused_duplicate)]
+pub(crate) struct UnusedDuplicate {
+    #[suggestion(code = "", applicability = "machine-applicable")]
+    pub this: Span,
+    #[note]
+    pub other: Span,
+    #[warning]
+    pub warning: bool,
+}
+
 #[derive(Diagnostic)]
 #[diag(attr_parsing_stability_outside_std, code = E0734)]
 pub(crate) struct StabilityOutsideStd {
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 1b4bb11d87b..34d36849939 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -3229,8 +3229,20 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                                     Applicability::MaybeIncorrect,
                                 );
                             }
+
+                            let mutability = if matches!(borrow.kind(), BorrowKind::Mut { .. }) {
+                                "mut "
+                            } else {
+                                ""
+                            };
+
                             if !is_format_arguments_item {
-                                let addition = format!("let binding = {};\n{}", s, " ".repeat(p));
+                                let addition = format!(
+                                    "let {}binding = {};\n{}",
+                                    mutability,
+                                    s,
+                                    " ".repeat(p)
+                                );
                                 err.multipart_suggestion_verbose(
                                     msg,
                                     vec![
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index a1c74672157..0a114467f43 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -141,8 +141,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> {
             }
 
             if !tcx.recursion_limit().value_within_limit(iteration) {
+                // This may actually be reachable. If so, we should convert
+                // this to a proper error/consider whether we should detect
+                // this somewhere else.
                 bug!(
-                    "FIXME(-Znext-solver): Overflowed when processing region obligations: {outlives_predicates:#?}"
+                    "unexpected overflowed when processing region obligations: {outlives_predicates:#?}"
                 );
             }
 
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 6dd3adf750d..d642851bb77 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -484,7 +484,7 @@ impl<'a> TraitDef<'a> {
         match item {
             Annotatable::Item(item) => {
                 let is_packed = matches!(
-                    AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, true),
+                    AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id),
                     Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(x, _)| matches!(x, ReprPacked(..)))
                 );
 
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs
index 1dc799c0aee..012e4dbc3ec 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs
@@ -644,9 +644,9 @@ pub mod intrinsics {
     #[rustc_intrinsic]
     pub unsafe fn size_of_val<T: ?::Sized>(val: *const T) -> usize;
     #[rustc_intrinsic]
-    pub fn min_align_of<T>() -> usize;
+    pub fn align_of<T>() -> usize;
     #[rustc_intrinsic]
-    pub unsafe fn min_align_of_val<T: ?::Sized>(val: *const T) -> usize;
+    pub unsafe fn align_of_val<T: ?::Sized>(val: *const T) -> usize;
     #[rustc_intrinsic]
     pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
     #[rustc_intrinsic]
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
index 93ca2e0e421..1499f948deb 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -204,11 +204,8 @@ fn main() {
         assert_eq!(intrinsics::size_of_val(a) as u8, 16);
         assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4);
 
-        assert_eq!(intrinsics::min_align_of::<u16>() as u8, 2);
-        assert_eq!(
-            intrinsics::min_align_of_val(&a) as u8,
-            intrinsics::min_align_of::<&str>() as u8
-        );
+        assert_eq!(intrinsics::align_of::<u16>() as u8, 2);
+        assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8);
 
         assert!(!intrinsics::needs_drop::<u8>());
         assert!(!intrinsics::needs_drop::<[u8]>());
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index fe5b220117f..4c6fd907815 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -51,6 +51,11 @@ pub(crate) fn conv_to_call_conv(
         CanonAbi::Rust | CanonAbi::C => default_call_conv,
         CanonAbi::RustCold => CallConv::Cold,
 
+        // Functions with this calling convention can only be called from assembly, but it is
+        // possible to declare an `extern "custom"` block, so the backend still needs a calling
+        // convention for declaring foreign functions.
+        CanonAbi::Custom => default_call_conv,
+
         CanonAbi::X86(x86_call) => match x86_call {
             X86Call::SysV64 => CallConv::SystemV,
             X86Call::Win64 => CallConv::WindowsFastcall,
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 1d1cf884e48..df5748c34d1 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -586,7 +586,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
             let (size, _align) = crate::unsize::size_and_align_of(fx, layout, meta);
             ret.write_cvalue(fx, CValue::by_val(size, usize_layout));
         }
-        sym::min_align_of_val => {
+        sym::align_of_val => {
             intrinsic_args!(fx, args => (ptr); intrinsic);
 
             let layout = fx.layout_of(generic_args.type_at(0));
@@ -613,7 +613,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
             intrinsic_args!(fx, args => (vtable); intrinsic);
             let vtable = vtable.load_scalar(fx);
 
-            let align = crate::vtable::min_align_of_obj(fx, vtable);
+            let align = crate::vtable::align_of_obj(fx, vtable);
             ret.write_cvalue(fx, CValue::by_val(align, usize_layout));
         }
 
diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs
index 662546e4999..df60b05c463 100644
--- a/compiler/rustc_codegen_cranelift/src/unsize.rs
+++ b/compiler/rustc_codegen_cranelift/src/unsize.rs
@@ -212,7 +212,7 @@ pub(crate) fn size_and_align_of<'tcx>(
             // load size/align from vtable
             (
                 crate::vtable::size_of_obj(fx, info.unwrap()),
-                crate::vtable::min_align_of_obj(fx, info.unwrap()),
+                crate::vtable::align_of_obj(fx, info.unwrap()),
             )
         }
         ty::Slice(_) | ty::Str => {
diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs
index 05a8e3c3342..1fae56949bc 100644
--- a/compiler/rustc_codegen_cranelift/src/vtable.rs
+++ b/compiler/rustc_codegen_cranelift/src/vtable.rs
@@ -31,7 +31,7 @@ pub(crate) fn size_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Val
     )
 }
 
-pub(crate) fn min_align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value {
+pub(crate) fn align_of_obj(fx: &mut FunctionCx<'_, '_, '_>, vtable: Value) -> Value {
     let usize_size = fx.layout_of(fx.tcx.types.usize).size.bytes() as usize;
     fx.bcx.ins().load(
         fx.pointer_type,
diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs
index d1d8e8fd5bc..aca1f0080ef 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core.rs
@@ -655,9 +655,9 @@ pub mod intrinsics {
     #[rustc_intrinsic]
     pub unsafe fn size_of_val<T: ?::Sized>(val: *const T) -> usize;
     #[rustc_intrinsic]
-    pub fn min_align_of<T>() -> usize;
+    pub fn align_of<T>() -> usize;
     #[rustc_intrinsic]
-    pub unsafe fn min_align_of_val<T: ?::Sized>(val: *const T) -> usize;
+    pub unsafe fn align_of_val<T: ?::Sized>(val: *const T) -> usize;
     #[rustc_intrinsic]
     pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize);
     #[rustc_intrinsic]
diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
index 4cbe66c5e4c..c3bd62e5897 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
@@ -153,7 +153,7 @@ fn main() {
     let slice = &[0, 1] as &[i32];
     let slice_ptr = slice as *const [i32] as *const i32;
 
-    let align = intrinsics::min_align_of::<*const i32>();
+    let align = intrinsics::align_of::<*const i32>();
     assert_eq!(slice_ptr as usize % align, 0);
 
     //return;
@@ -194,8 +194,8 @@ fn main() {
         assert_eq!(intrinsics::size_of_val(a) as u8, 8);
         assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4);
 
-        assert_eq!(intrinsics::min_align_of::<u16>() as u8, 2);
-        assert_eq!(intrinsics::min_align_of_val(&a) as u8, intrinsics::min_align_of::<&str>() as u8);
+        assert_eq!(intrinsics::align_of::<u16>() as u8, 2);
+        assert_eq!(intrinsics::align_of_val(&a) as u8, intrinsics::align_of::<&str>() as u8);
 
         assert!(!intrinsics::needs_drop::<u8>());
         assert!(!intrinsics::needs_drop::<[u8]>());
diff --git a/compiler/rustc_codegen_gcc/messages.ftl b/compiler/rustc_codegen_gcc/messages.ftl
index 546bfc87b68..18a8a5a1e04 100644
--- a/compiler/rustc_codegen_gcc/messages.ftl
+++ b/compiler/rustc_codegen_gcc/messages.ftl
@@ -2,9 +2,6 @@ codegen_gcc_unknown_ctarget_feature_prefix =
     unknown feature specified for `-Ctarget-feature`: `{$feature}`
     .note = features must begin with a `+` to enable or `-` to disable it
 
-codegen_gcc_forbidden_ctarget_feature =
-    target feature `{$feature}` cannot be toggled with `-Ctarget-feature`: {$reason}
-
 codegen_gcc_unwinding_inline_asm =
     GCC backend does not support unwinding from inline asm
 
@@ -26,10 +23,6 @@ codegen_gcc_unknown_ctarget_feature =
     .possible_feature = you might have meant: `{$rust_feature}`
     .consider_filing_feature_request = consider filing a feature request
 
-codegen_gcc_unstable_ctarget_feature =
-    unstable feature specified for `-Ctarget-feature`: `{$feature}`
-    .note = this feature is not stably supported; its behavior can change in the future
-
 codegen_gcc_missing_features =
     add the missing features in a `target_feature` attribute
 
diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs
index 3d0c258f576..08f3d281904 100644
--- a/compiler/rustc_codegen_gcc/src/abi.rs
+++ b/compiler/rustc_codegen_gcc/src/abi.rs
@@ -239,12 +239,16 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
 pub fn conv_to_fn_attribute<'gcc>(conv: CanonAbi, arch: &str) -> Option<FnAttribute<'gcc>> {
     let attribute = match conv {
         CanonAbi::C | CanonAbi::Rust => return None,
+        CanonAbi::RustCold => FnAttribute::Cold,
+        // Functions with this calling convention can only be called from assembly, but it is
+        // possible to declare an `extern "custom"` block, so the backend still needs a calling
+        // convention for declaring foreign functions.
+        CanonAbi::Custom => return None,
         CanonAbi::Arm(arm_call) => match arm_call {
             ArmCall::CCmseNonSecureCall => FnAttribute::ArmCmseNonsecureCall,
             ArmCall::CCmseNonSecureEntry => FnAttribute::ArmCmseNonsecureEntry,
             ArmCall::Aapcs => FnAttribute::ArmPcs("aapcs"),
         },
-        CanonAbi::RustCold => FnAttribute::Cold,
         CanonAbi::GpuKernel => {
             if arch == "amdgpu" {
                 FnAttribute::GcnAmdGpuHsaKernel
diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs
index ccd9abe3804..7786be9ae5d 100644
--- a/compiler/rustc_codegen_gcc/src/errors.rs
+++ b/compiler/rustc_codegen_gcc/src/errors.rs
@@ -17,21 +17,6 @@ pub(crate) struct UnknownCTargetFeature<'a> {
     pub rust_feature: PossibleFeature<'a>,
 }
 
-#[derive(Diagnostic)]
-#[diag(codegen_gcc_unstable_ctarget_feature)]
-#[note]
-pub(crate) struct UnstableCTargetFeature<'a> {
-    pub feature: &'a str,
-}
-
-#[derive(Diagnostic)]
-#[diag(codegen_gcc_forbidden_ctarget_feature)]
-pub(crate) struct ForbiddenCTargetFeature<'a> {
-    pub feature: &'a str,
-    pub enabled: &'a str,
-    pub reason: &'a str,
-}
-
 #[derive(Subdiagnostic)]
 pub(crate) enum PossibleFeature<'a> {
     #[help(codegen_gcc_possible_feature)]
diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs
index 2b053abdd19..d90e66aea31 100644
--- a/compiler/rustc_codegen_gcc/src/gcc_util.rs
+++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs
@@ -5,13 +5,17 @@ use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::unord::UnordSet;
 use rustc_session::Session;
+use rustc_session::features::{StabilityExt, retpoline_features_by_flags};
 use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
 use smallvec::{SmallVec, smallvec};
 
-use crate::errors::{
-    ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix,
-    UnstableCTargetFeature,
-};
+use crate::errors::{PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix};
+
+fn gcc_features_by_flags(sess: &Session) -> Vec<&str> {
+    let mut features: Vec<&str> = Vec::new();
+    retpoline_features_by_flags(sess, &mut features);
+    features
+}
 
 /// The list of GCC features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
 /// `--target` and similar).
@@ -45,7 +49,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
 
     // Compute implied features
     let mut all_rust_features = vec![];
-    for feature in sess.opts.cg.target_feature.split(',') {
+    for feature in sess.opts.cg.target_feature.split(',').chain(gcc_features_by_flags(sess)) {
         if let Some(feature) = feature.strip_prefix('+') {
             all_rust_features.extend(
                 UnordSet::from(sess.target.implied_target_features(feature))
@@ -94,18 +98,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
                     sess.dcx().emit_warn(unknown_feature);
                 }
                 Some(&(_, stability, _)) => {
-                    if let Err(reason) = stability.toggle_allowed() {
-                        sess.dcx().emit_warn(ForbiddenCTargetFeature {
-                            feature,
-                            enabled: if enable { "enabled" } else { "disabled" },
-                            reason,
-                        });
-                    } else if stability.requires_nightly().is_some() {
-                        // An unstable feature. Warn about using it. (It makes little sense
-                        // to hard-error here since we just warn about fully unknown
-                        // features above).
-                        sess.dcx().emit_warn(UnstableCTargetFeature { feature });
-                    }
+                    stability.verify_feature_enabled_by_flag(sess, enable, feature);
                 }
             }
 
diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl
index bda121c67fb..3faeb9b3b22 100644
--- a/compiler/rustc_codegen_llvm/messages.ftl
+++ b/compiler/rustc_codegen_llvm/messages.ftl
@@ -10,11 +10,6 @@ codegen_llvm_dynamic_linking_with_lto =
 
 codegen_llvm_fixed_x18_invalid_arch = the `-Zfixed-x18` flag is not supported on the `{$arch}` architecture
 
-codegen_llvm_forbidden_ctarget_feature =
-    target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason}
-    .note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-codegen_llvm_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
-
 codegen_llvm_from_llvm_diag = {$message}
 
 codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message}
@@ -76,10 +71,6 @@ codegen_llvm_unknown_ctarget_feature_prefix =
 
 codegen_llvm_unknown_debuginfo_compression = unknown debuginfo compression algorithm {$algorithm} - will fall back to uncompressed debuginfo
 
-codegen_llvm_unstable_ctarget_feature =
-    unstable feature specified for `-Ctarget-feature`: `{$feature}`
-    .note = this feature is not stably supported; its behavior can change in the future
-
 codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}
 
 codegen_llvm_write_ir = failed to write LLVM IR to {$path}
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 119cd634f98..aba63d75f1d 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -649,6 +649,10 @@ impl llvm::CallConv {
         match conv {
             CanonAbi::C | CanonAbi::Rust => llvm::CCallConv,
             CanonAbi::RustCold => llvm::PreserveMost,
+            // Functions with this calling convention can only be called from assembly, but it is
+            // possible to declare an `extern "custom"` block, so the backend still needs a calling
+            // convention for declaring foreign functions.
+            CanonAbi::Custom => llvm::CCallConv,
             CanonAbi::GpuKernel => {
                 if arch == "amdgpu" {
                     llvm::AmdgpuKernel
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_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
index eaafc680712..8bc74fbec7e 100644
--- a/compiler/rustc_codegen_llvm/src/errors.rs
+++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -24,23 +24,6 @@ pub(crate) struct UnknownCTargetFeature<'a> {
     pub rust_feature: PossibleFeature<'a>,
 }
 
-#[derive(Diagnostic)]
-#[diag(codegen_llvm_unstable_ctarget_feature)]
-#[note]
-pub(crate) struct UnstableCTargetFeature<'a> {
-    pub feature: &'a str,
-}
-
-#[derive(Diagnostic)]
-#[diag(codegen_llvm_forbidden_ctarget_feature)]
-#[note]
-#[note(codegen_llvm_forbidden_ctarget_feature_issue)]
-pub(crate) struct ForbiddenCTargetFeature<'a> {
-    pub feature: &'a str,
-    pub enabled: &'a str,
-    pub reason: &'a str,
-}
-
 #[derive(Subdiagnostic)]
 pub(crate) enum PossibleFeature<'a> {
     #[help(codegen_llvm_possible_feature)]
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 9718c95f38a..0e77bc43df8 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -16,6 +16,7 @@ use rustc_fs_util::path_to_c_string;
 use rustc_middle::bug;
 use rustc_session::Session;
 use rustc_session::config::{PrintKind, PrintRequest};
+use rustc_session::features::{StabilityExt, retpoline_features_by_flags};
 use rustc_span::Symbol;
 use rustc_target::spec::{MergeFunctions, PanicStrategy, SmallDataThresholdSupport};
 use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES};
@@ -23,8 +24,7 @@ use smallvec::{SmallVec, smallvec};
 
 use crate::back::write::create_informational_target_machine;
 use crate::errors::{
-    FixedX18InvalidArch, ForbiddenCTargetFeature, PossibleFeature, UnknownCTargetFeature,
-    UnknownCTargetFeaturePrefix, UnstableCTargetFeature,
+    FixedX18InvalidArch, PossibleFeature, UnknownCTargetFeature, UnknownCTargetFeaturePrefix,
 };
 use crate::llvm;
 
@@ -707,6 +707,12 @@ pub(crate) fn target_cpu(sess: &Session) -> &str {
     handle_native(cpu_name)
 }
 
+fn llvm_features_by_flags(sess: &Session) -> Vec<&str> {
+    let mut features: Vec<&str> = Vec::new();
+    retpoline_features_by_flags(sess, &mut features);
+    features
+}
+
 /// The list of LLVM features computed from CLI flags (`-Ctarget-cpu`, `-Ctarget-feature`,
 /// `--target` and similar).
 pub(crate) fn global_llvm_features(
@@ -787,7 +793,7 @@ pub(crate) fn global_llvm_features(
 
         // Compute implied features
         let mut all_rust_features = vec![];
-        for feature in sess.opts.cg.target_feature.split(',') {
+        for feature in sess.opts.cg.target_feature.split(',').chain(llvm_features_by_flags(sess)) {
             if let Some(feature) = feature.strip_prefix('+') {
                 all_rust_features.extend(
                     UnordSet::from(sess.target.implied_target_features(feature))
@@ -840,18 +846,7 @@ pub(crate) fn global_llvm_features(
                         sess.dcx().emit_warn(unknown_feature);
                     }
                     Some((_, stability, _)) => {
-                        if let Err(reason) = stability.toggle_allowed() {
-                            sess.dcx().emit_warn(ForbiddenCTargetFeature {
-                                feature,
-                                enabled: if enable { "enabled" } else { "disabled" },
-                                reason,
-                            });
-                        } else if stability.requires_nightly().is_some() {
-                            // An unstable feature. Warn about using it. It makes little sense
-                            // to hard-error here since we just warn about fully unknown
-                            // features above.
-                            sess.dcx().emit_warn(UnstableCTargetFeature { feature });
-                        }
+                        stability.verify_feature_enabled_by_flag(sess, enable, feature);
                     }
                 }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 168077260a6..18b76b33757 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -1065,11 +1065,11 @@ fn link_natively(
         match strip {
             Strip::Debuginfo => {
                 // FIXME: AIX's strip utility only offers option to strip line number information.
-                strip_with_external_utility(sess, stripcmd, out_filename, &["-X32_64", "-l"])
+                strip_with_external_utility(sess, stripcmd, temp_filename, &["-X32_64", "-l"])
             }
             Strip::Symbols => {
                 // Must be noted this option might remove symbol __aix_rust_metadata and thus removes .info section which contains metadata.
-                strip_with_external_utility(sess, stripcmd, out_filename, &["-X32_64", "-r"])
+                strip_with_external_utility(sess, stripcmd, temp_filename, &["-X32_64", "-r"])
             }
             Strip::None => {}
         }
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index e217c09939e..27fcab8ed2d 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -118,7 +118,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 let (llsize, _) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta);
                 llsize
             }
-            sym::min_align_of_val => {
+            sym::align_of_val => {
                 let tp_ty = fn_args.type_at(0);
                 let (_, meta) = args[0].val.pointer_parts();
                 let (_, llalign) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta);
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 5c14fe5cd10..b62ac89661f 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -278,7 +278,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 {
                     let from_backend_ty = bx.backend_type(operand.layout);
                     let to_backend_ty = bx.backend_type(cast);
-                    Some(OperandValue::Immediate(self.transmute_immediate(
+                    Some(OperandValue::Immediate(transmute_immediate(
                         bx,
                         imm,
                         from_scalar,
@@ -303,8 +303,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     let out_a_ibty = bx.scalar_pair_element_backend_type(cast, 0, false);
                     let out_b_ibty = bx.scalar_pair_element_backend_type(cast, 1, false);
                     Some(OperandValue::Pair(
-                        self.transmute_immediate(bx, imm_a, in_a, in_a_ibty, out_a, out_a_ibty),
-                        self.transmute_immediate(bx, imm_b, in_b, in_b_ibty, out_b, out_b_ibty),
+                        transmute_immediate(bx, imm_a, in_a, in_a_ibty, out_a, out_a_ibty),
+                        transmute_immediate(bx, imm_b, in_b, in_b_ibty, out_b, out_b_ibty),
                     ))
                 } else {
                     None
@@ -332,7 +332,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         // valid ranges. For example, `char`s are passed as just `i32`, with no
         // way for LLVM to know that they're 0x10FFFF at most. Thus we assume
         // the range of the input value too, not just the output range.
-        self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
+        assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
 
         imm = match (from_scalar.primitive(), to_scalar.primitive()) {
             (Int(_, is_signed), Int(..)) => bx.intcast(imm, to_backend_ty, is_signed),
@@ -365,98 +365,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         Some(imm)
     }
 
-    /// Transmutes one of the immediates from an [`OperandValue::Immediate`]
-    /// or an [`OperandValue::Pair`] to an immediate of the target type.
-    ///
-    /// `to_backend_ty` must be the *non*-immediate backend type (so it will be
-    /// `i8`, not `i1`, for `bool`-like types.)
-    fn transmute_immediate(
-        &self,
-        bx: &mut Bx,
-        mut imm: Bx::Value,
-        from_scalar: abi::Scalar,
-        from_backend_ty: Bx::Type,
-        to_scalar: abi::Scalar,
-        to_backend_ty: Bx::Type,
-    ) -> Bx::Value {
-        assert_eq!(from_scalar.size(self.cx), to_scalar.size(self.cx));
-
-        // While optimizations will remove no-op transmutes, they might still be
-        // there in debug or things that aren't no-op in MIR because they change
-        // the Rust type but not the underlying layout/niche.
-        if from_scalar == to_scalar && from_backend_ty == to_backend_ty {
-            return imm;
-        }
-
-        use abi::Primitive::*;
-        imm = bx.from_immediate(imm);
-
-        // If we have a scalar, we must already know its range. Either
-        //
-        // 1) It's a parameter with `range` parameter metadata,
-        // 2) It's something we `load`ed with `!range` metadata, or
-        // 3) After a transmute we `assume`d the range (see below).
-        //
-        // That said, last time we tried removing this, it didn't actually help
-        // the rustc-perf results, so might as well keep doing it
-        // <https://github.com/rust-lang/rust/pull/135610#issuecomment-2599275182>
-        self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
-
-        imm = match (from_scalar.primitive(), to_scalar.primitive()) {
-            (Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty),
-            (Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
-            (Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm),
-            (Pointer(..), Int(..)) => {
-                // FIXME: this exposes the provenance, which shouldn't be necessary.
-                bx.ptrtoint(imm, to_backend_ty)
-            }
-            (Float(_), Pointer(..)) => {
-                let int_imm = bx.bitcast(imm, bx.cx().type_isize());
-                bx.ptradd(bx.const_null(bx.type_ptr()), int_imm)
-            }
-            (Pointer(..), Float(_)) => {
-                // FIXME: this exposes the provenance, which shouldn't be necessary.
-                let int_imm = bx.ptrtoint(imm, bx.cx().type_isize());
-                bx.bitcast(int_imm, to_backend_ty)
-            }
-        };
-
-        // This `assume` remains important for cases like (a conceptual)
-        //    transmute::<u32, NonZeroU32>(x) == 0
-        // since it's never passed to something with parameter metadata (especially
-        // after MIR inlining) so the only way to tell the backend about the
-        // constraint that the `transmute` introduced is to `assume` it.
-        self.assume_scalar_range(bx, imm, to_scalar, to_backend_ty);
-
-        imm = bx.to_immediate_scalar(imm, to_scalar);
-        imm
-    }
-
-    fn assume_scalar_range(
-        &self,
-        bx: &mut Bx,
-        imm: Bx::Value,
-        scalar: abi::Scalar,
-        backend_ty: Bx::Type,
-    ) {
-        if matches!(self.cx.sess().opts.optimize, OptLevel::No) || scalar.is_always_valid(self.cx) {
-            return;
-        }
-
-        match scalar.primitive() {
-            abi::Primitive::Int(..) => {
-                let range = scalar.valid_range(self.cx);
-                bx.assume_integer_range(imm, backend_ty, range);
-            }
-            abi::Primitive::Pointer(abi::AddressSpace::DATA)
-                if !scalar.valid_range(self.cx).contains(0) =>
-            {
-                bx.assume_nonnull(imm);
-            }
-            abi::Primitive::Pointer(..) | abi::Primitive::Float(..) => {}
-        }
-    }
-
     pub(crate) fn codegen_rvalue_unsized(
         &mut self,
         bx: &mut Bx,
@@ -1231,3 +1139,93 @@ impl OperandValueKind {
         })
     }
 }
+
+/// Transmutes one of the immediates from an [`OperandValue::Immediate`]
+/// or an [`OperandValue::Pair`] to an immediate of the target type.
+///
+/// `to_backend_ty` must be the *non*-immediate backend type (so it will be
+/// `i8`, not `i1`, for `bool`-like types.)
+fn transmute_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
+    bx: &mut Bx,
+    mut imm: Bx::Value,
+    from_scalar: abi::Scalar,
+    from_backend_ty: Bx::Type,
+    to_scalar: abi::Scalar,
+    to_backend_ty: Bx::Type,
+) -> Bx::Value {
+    assert_eq!(from_scalar.size(bx.cx()), to_scalar.size(bx.cx()));
+
+    // While optimizations will remove no-op transmutes, they might still be
+    // there in debug or things that aren't no-op in MIR because they change
+    // the Rust type but not the underlying layout/niche.
+    if from_scalar == to_scalar && from_backend_ty == to_backend_ty {
+        return imm;
+    }
+
+    use abi::Primitive::*;
+    imm = bx.from_immediate(imm);
+
+    // If we have a scalar, we must already know its range. Either
+    //
+    // 1) It's a parameter with `range` parameter metadata,
+    // 2) It's something we `load`ed with `!range` metadata, or
+    // 3) After a transmute we `assume`d the range (see below).
+    //
+    // That said, last time we tried removing this, it didn't actually help
+    // the rustc-perf results, so might as well keep doing it
+    // <https://github.com/rust-lang/rust/pull/135610#issuecomment-2599275182>
+    assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
+
+    imm = match (from_scalar.primitive(), to_scalar.primitive()) {
+        (Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty),
+        (Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
+        (Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm),
+        (Pointer(..), Int(..)) => {
+            // FIXME: this exposes the provenance, which shouldn't be necessary.
+            bx.ptrtoint(imm, to_backend_ty)
+        }
+        (Float(_), Pointer(..)) => {
+            let int_imm = bx.bitcast(imm, bx.cx().type_isize());
+            bx.ptradd(bx.const_null(bx.type_ptr()), int_imm)
+        }
+        (Pointer(..), Float(_)) => {
+            // FIXME: this exposes the provenance, which shouldn't be necessary.
+            let int_imm = bx.ptrtoint(imm, bx.cx().type_isize());
+            bx.bitcast(int_imm, to_backend_ty)
+        }
+    };
+
+    // This `assume` remains important for cases like (a conceptual)
+    //    transmute::<u32, NonZeroU32>(x) == 0
+    // since it's never passed to something with parameter metadata (especially
+    // after MIR inlining) so the only way to tell the backend about the
+    // constraint that the `transmute` introduced is to `assume` it.
+    assume_scalar_range(bx, imm, to_scalar, to_backend_ty);
+
+    imm = bx.to_immediate_scalar(imm, to_scalar);
+    imm
+}
+
+fn assume_scalar_range<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
+    bx: &mut Bx,
+    imm: Bx::Value,
+    scalar: abi::Scalar,
+    backend_ty: Bx::Type,
+) {
+    if matches!(bx.cx().sess().opts.optimize, OptLevel::No) || scalar.is_always_valid(bx.cx()) {
+        return;
+    }
+
+    match scalar.primitive() {
+        abi::Primitive::Int(..) => {
+            let range = scalar.valid_range(bx.cx());
+            bx.assume_integer_range(imm, backend_ty, range);
+        }
+        abi::Primitive::Pointer(abi::AddressSpace::DATA)
+            if !scalar.valid_range(bx.cx()).contains(0) =>
+        {
+            bx.assume_nonnull(imm);
+        }
+        abi::Primitive::Pointer(..) | abi::Primitive::Float(..) => {}
+    }
+}
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 6bb3150c1c5..640d197c219 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -8,6 +8,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
 use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
+use rustc_session::features::StabilityExt;
 use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON;
 use rustc_session::parse::feature_err;
 use rustc_span::{Span, Symbol, sym};
@@ -66,7 +67,7 @@ pub(crate) fn from_target_feature_attr(
 
             // Only allow target features whose feature gates have been enabled
             // and which are permitted to be toggled.
-            if let Err(reason) = stability.toggle_allowed() {
+            if let Err(reason) = stability.is_toggle_permitted(tcx.sess) {
                 tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
                     span: item.span(),
                     feature,
diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs
index c3fc21a9285..70331b72353 100644
--- a/compiler/rustc_codegen_ssa/src/traits/type_.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs
@@ -44,10 +44,10 @@ pub trait DerivedTypeCodegenMethods<'tcx>:
     BaseTypeCodegenMethods + MiscCodegenMethods<'tcx> + HasTyCtxt<'tcx> + HasTypingEnv<'tcx>
 {
     fn type_int(&self) -> Self::Type {
-        match &self.sess().target.c_int_width[..] {
-            "16" => self.type_i16(),
-            "32" => self.type_i32(),
-            "64" => self.type_i64(),
+        match &self.sess().target.c_int_width {
+            16 => self.type_i16(),
+            32 => self.type_i32(),
+            64 => self.type_i64(),
             width => bug!("Unsupported c_int_width: {}", width),
         }
     }
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_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index ab27182c211..754b2ba0d76 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -120,7 +120,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                 self.copy_op(&val, dest)?;
             }
 
-            sym::min_align_of_val | sym::size_of_val => {
+            sym::align_of_val | sym::size_of_val => {
                 // Avoid `deref_pointer` -- this is not a deref, the ptr does not have to be
                 // dereferenceable!
                 let place = self.ref_to_mplace(&self.read_immediate(&args[0])?)?;
@@ -129,7 +129,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
                     .ok_or_else(|| err_unsup_format!("`extern type` does not have known layout"))?;
 
                 let result = match intrinsic_name {
-                    sym::min_align_of_val => align.bytes(),
+                    sym::align_of_val => align.bytes(),
                     sym::size_of_val => size.bytes(),
                     _ => bug!(),
                 };
diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs
index 83a17092619..99add01f95c 100644
--- a/compiler/rustc_const_eval/src/interpret/util.rs
+++ b/compiler/rustc_const_eval/src/interpret/util.rs
@@ -58,9 +58,9 @@ pub enum MaybeEnteredSpan {
 macro_rules! enter_trace_span {
     ($machine:ident, $($tt:tt)*) => {
         if $machine::TRACING_ENABLED {
-            $crate::interpret::tracing_utils::MaybeEnteredSpan::Some(tracing::info_span!($($tt)*).entered())
+            $crate::interpret::util::MaybeEnteredSpan::Some(tracing::info_span!($($tt)*).entered())
         } else {
-            $crate::interpret::tracing_utils::MaybeEnteredSpan::None
+            $crate::interpret::util::MaybeEnteredSpan::None
         }
     }
 }
diff --git a/compiler/rustc_data_structures/src/thousands/mod.rs b/compiler/rustc_data_structures/src/thousands/mod.rs
index e7ab7ec2932..b251ebe58f6 100644
--- a/compiler/rustc_data_structures/src/thousands/mod.rs
+++ b/compiler/rustc_data_structures/src/thousands/mod.rs
@@ -1,16 +1,37 @@
-//! This is an extremely bare-bones alternative to the `thousands` crate on
-//! crates.io, for printing large numbers in a readable fashion.
+//! This is a bare-bones alternative to the `thousands` crate on crates.io, for
+//! printing large numbers in a readable fashion.
 
 #[cfg(test)]
 mod tests;
 
-// Converts the number to a string, with underscores as the thousands separator.
-pub fn format_with_underscores(n: usize) -> String {
-    let mut s = n.to_string();
-    let mut i = s.len();
-    while i > 3 {
+fn format_with_underscores(mut s: String) -> String {
+    // Ignore a leading '-'.
+    let start = if s.starts_with('-') { 1 } else { 0 };
+
+    // Stop after the first non-digit, e.g. '.' or 'e' for floats.
+    let non_digit = s[start..].find(|c: char| !c.is_digit(10));
+    let end = if let Some(non_digit) = non_digit { start + non_digit } else { s.len() };
+
+    // Insert underscores within `start..end`.
+    let mut i = end;
+    while i > start + 3 {
         i -= 3;
         s.insert(i, '_');
     }
     s
 }
+
+/// Print a `usize` with underscore separators.
+pub fn usize_with_underscores(n: usize) -> String {
+    format_with_underscores(format!("{n}"))
+}
+
+/// Print an `isize` with underscore separators.
+pub fn isize_with_underscores(n: isize) -> String {
+    format_with_underscores(format!("{n}"))
+}
+
+/// Print an `f64` with precision 1 (one decimal place) and underscore separators.
+pub fn f64p1_with_underscores(n: f64) -> String {
+    format_with_underscores(format!("{n:.1}"))
+}
diff --git a/compiler/rustc_data_structures/src/thousands/tests.rs b/compiler/rustc_data_structures/src/thousands/tests.rs
index 906605d9a93..0f9a648802b 100644
--- a/compiler/rustc_data_structures/src/thousands/tests.rs
+++ b/compiler/rustc_data_structures/src/thousands/tests.rs
@@ -2,13 +2,51 @@ use super::*;
 
 #[test]
 fn test_format_with_underscores() {
-    assert_eq!("0", format_with_underscores(0));
-    assert_eq!("1", format_with_underscores(1));
-    assert_eq!("99", format_with_underscores(99));
-    assert_eq!("345", format_with_underscores(345));
-    assert_eq!("1_000", format_with_underscores(1_000));
-    assert_eq!("12_001", format_with_underscores(12_001));
-    assert_eq!("999_999", format_with_underscores(999_999));
-    assert_eq!("1_000_000", format_with_underscores(1_000_000));
-    assert_eq!("12_345_678", format_with_underscores(12_345_678));
+    assert_eq!("", format_with_underscores("".to_string()));
+    assert_eq!("0", format_with_underscores("0".to_string()));
+    assert_eq!("12_345.67e14", format_with_underscores("12345.67e14".to_string()));
+    assert_eq!("-1_234.5678e10", format_with_underscores("-1234.5678e10".to_string()));
+    assert_eq!("------", format_with_underscores("------".to_string()));
+    assert_eq!("abcdefgh", format_with_underscores("abcdefgh".to_string()));
+    assert_eq!("-1b", format_with_underscores("-1b".to_string()));
+    assert_eq!("-3_456xyz", format_with_underscores("-3456xyz".to_string()));
+}
+
+#[test]
+fn test_usize_with_underscores() {
+    assert_eq!("0", usize_with_underscores(0));
+    assert_eq!("1", usize_with_underscores(1));
+    assert_eq!("99", usize_with_underscores(99));
+    assert_eq!("345", usize_with_underscores(345));
+    assert_eq!("1_000", usize_with_underscores(1_000));
+    assert_eq!("12_001", usize_with_underscores(12_001));
+    assert_eq!("999_999", usize_with_underscores(999_999));
+    assert_eq!("1_000_000", usize_with_underscores(1_000_000));
+    assert_eq!("12_345_678", usize_with_underscores(12_345_678));
+}
+
+#[test]
+fn test_isize_with_underscores() {
+    assert_eq!("0", isize_with_underscores(0));
+    assert_eq!("-1", isize_with_underscores(-1));
+    assert_eq!("99", isize_with_underscores(99));
+    assert_eq!("345", isize_with_underscores(345));
+    assert_eq!("-1_000", isize_with_underscores(-1_000));
+    assert_eq!("12_001", isize_with_underscores(12_001));
+    assert_eq!("-999_999", isize_with_underscores(-999_999));
+    assert_eq!("1_000_000", isize_with_underscores(1_000_000));
+    assert_eq!("-12_345_678", isize_with_underscores(-12_345_678));
+}
+
+#[test]
+fn test_f64p1_with_underscores() {
+    assert_eq!("0.0", f64p1_with_underscores(0f64));
+    assert_eq!("0.0", f64p1_with_underscores(0.00000001));
+    assert_eq!("-0.0", f64p1_with_underscores(-0.00000001));
+    assert_eq!("1.0", f64p1_with_underscores(0.9999999));
+    assert_eq!("-1.0", f64p1_with_underscores(-0.9999999));
+    assert_eq!("345.5", f64p1_with_underscores(345.4999999));
+    assert_eq!("-100_000.0", f64p1_with_underscores(-100_000f64));
+    assert_eq!("123_456_789.1", f64p1_with_underscores(123456789.123456789));
+    assert_eq!("-123_456_789.1", f64p1_with_underscores(-123456789.123456789));
 }
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 133bd361ee7..9f72fc4705a 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -60,8 +60,9 @@ pub use rustc_error_messages::{
     SubdiagMessage, fallback_fluent_bundle, fluent_bundle,
 };
 use rustc_hashes::Hash128;
-use rustc_lint_defs::LintExpectationId;
+use rustc_hir::HirId;
 pub use rustc_lint_defs::{Applicability, listify, pluralize};
+use rustc_lint_defs::{Lint, LintExpectationId};
 use rustc_macros::{Decodable, Encodable};
 pub use rustc_span::ErrorGuaranteed;
 pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
@@ -101,6 +102,19 @@ rustc_data_structures::static_assert_size!(PResult<'_, ()>, 24);
 #[cfg(target_pointer_width = "64")]
 rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24);
 
+/// Used to avoid depending on `rustc_middle` in `rustc_attr_parsing`.
+/// Always the `TyCtxt`.
+pub trait LintEmitter: Copy {
+    #[track_caller]
+    fn emit_node_span_lint(
+        self,
+        lint: &'static Lint,
+        hir_id: HirId,
+        span: impl Into<MultiSpan>,
+        decorator: impl for<'a> LintDiagnostic<'a, ()>,
+    );
+}
+
 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
 pub enum SuggestionStyle {
     /// Hide the suggested code when displaying this suggestion inline.
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index f26c7c1ba0b..8b7c47dad99 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 =
@@ -112,7 +113,7 @@ expand_meta_var_expr_unrecognized_var =
     variable `{$key}` is not recognized in meta-variable expression
 
 expand_missing_fragment_specifier = missing fragment specifier
-    .note = fragment specifiers must be specified in the 2024 edition
+    .note = fragment specifiers must be provided
     .suggestion_add_fragspec = try adding a specifier here
     .valid = {$valid}
 
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index c7b975d8f3e..311dadb53c4 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -12,7 +12,7 @@ use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{AssocCtxt, Visitor};
 use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind};
 use rustc_attr_data_structures::{AttributeKind, Deprecation, Stability, find_attr};
-use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_data_structures::sync;
 use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult};
 use rustc_feature::Features;
@@ -727,6 +727,7 @@ pub enum SyntaxExtensionKind {
     /// A trivial attribute "macro" that does nothing,
     /// only keeps the attribute and marks it as inert,
     /// thus making it ineligible for further expansion.
+    /// E.g. `#[default]`, `#[rustfmt::skip]`.
     NonMacroAttr,
 
     /// A token-based derive macro.
@@ -1189,6 +1190,8 @@ pub struct ExtCtxt<'a> {
     /// in the AST, but insert it here so that we know
     /// not to expand it again.
     pub(super) expanded_inert_attrs: MarkedAttrs,
+    /// `-Zmacro-stats` data.
+    pub macro_stats: FxHashMap<(Symbol, MacroKind), crate::stats::MacroStat>, // njn: quals
 }
 
 impl<'a> ExtCtxt<'a> {
@@ -1218,6 +1221,7 @@ impl<'a> ExtCtxt<'a> {
             expansions: FxIndexMap::default(),
             expanded_inert_attrs: MarkedAttrs::new(),
             buffered_early_lint: vec![],
+            macro_stats: Default::default(),
         }
     }
 
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_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 569165a64e5..3cfeb01ea47 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -42,13 +42,22 @@ use crate::module::{
     DirOwnership, ParsedExternalMod, mod_dir_path, mod_file_path_from_attr, parse_external_mod,
 };
 use crate::placeholders::{PlaceholderExpander, placeholder};
+use crate::stats::*;
 
 macro_rules! ast_fragments {
     (
         $($Kind:ident($AstTy:ty) {
             $kind_name:expr;
-            $(one fn $mut_visit_ast:ident; fn $visit_ast:ident;)?
-            $(many fn $flat_map_ast_elt:ident; fn $visit_ast_elt:ident($($args:tt)*);)?
+            $(one
+                fn $mut_visit_ast:ident;
+                fn $visit_ast:ident;
+                fn $ast_to_string:path;
+            )?
+            $(many
+                fn $flat_map_ast_elt:ident;
+                fn $visit_ast_elt:ident($($args:tt)*);
+                fn $ast_to_string_elt:path;
+            )?
             fn $make_ast:ident;
         })*
     ) => {
@@ -61,7 +70,7 @@ macro_rules! ast_fragments {
         }
 
         /// "Discriminant" of an AST fragment.
-        #[derive(Copy, Clone, PartialEq, Eq)]
+        #[derive(Copy, Clone, Debug, PartialEq, Eq)]
         pub enum AstFragmentKind {
             OptExpr,
             MethodReceiverExpr,
@@ -151,6 +160,21 @@ macro_rules! ast_fragments {
                 }
                 V::Result::output()
             }
+
+            pub(crate) fn to_string(&self) -> String {
+                match self {
+                    AstFragment::OptExpr(Some(expr)) => pprust::expr_to_string(expr),
+                    AstFragment::OptExpr(None) => unreachable!(),
+                    AstFragment::MethodReceiverExpr(expr) => pprust::expr_to_string(expr),
+                    $($(AstFragment::$Kind(ast) => $ast_to_string(ast),)?)*
+                    $($(
+                        AstFragment::$Kind(ast) => {
+                            // The closure unwraps a `P` if present, or does nothing otherwise.
+                            elems_to_string(&*ast, |ast| $ast_to_string_elt(&*ast))
+                        }
+                    )?)*
+                }
+            }
         }
 
         impl<'a> MacResult for crate::mbe::macro_rules::ParserAnyMacro<'a> {
@@ -163,76 +187,98 @@ macro_rules! ast_fragments {
 }
 
 ast_fragments! {
-    Expr(P<ast::Expr>) { "expression"; one fn visit_expr; fn visit_expr; fn make_expr; }
-    Pat(P<ast::Pat>) { "pattern"; one fn visit_pat; fn visit_pat; fn make_pat; }
-    Ty(P<ast::Ty>) { "type"; one fn visit_ty; fn visit_ty; fn make_ty; }
+    Expr(P<ast::Expr>) {
+        "expression";
+        one fn visit_expr; fn visit_expr; fn pprust::expr_to_string;
+        fn make_expr;
+    }
+    Pat(P<ast::Pat>) {
+        "pattern";
+        one fn visit_pat; fn visit_pat; fn pprust::pat_to_string;
+        fn make_pat;
+    }
+    Ty(P<ast::Ty>) {
+        "type";
+        one fn visit_ty; fn visit_ty; fn pprust::ty_to_string;
+        fn make_ty;
+    }
     Stmts(SmallVec<[ast::Stmt; 1]>) {
-        "statement"; many fn flat_map_stmt; fn visit_stmt(); fn make_stmts;
+        "statement";
+        many fn flat_map_stmt; fn visit_stmt(); fn pprust::stmt_to_string;
+        fn make_stmts;
     }
     Items(SmallVec<[P<ast::Item>; 1]>) {
-        "item"; many fn flat_map_item; fn visit_item(); fn make_items;
+        "item";
+        many fn flat_map_item; fn visit_item(); fn pprust::item_to_string;
+        fn make_items;
     }
     TraitItems(SmallVec<[P<ast::AssocItem>; 1]>) {
         "trait item";
-        many fn flat_map_assoc_item;
-        fn visit_assoc_item(AssocCtxt::Trait);
+        many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Trait);
+            fn pprust::assoc_item_to_string;
         fn make_trait_items;
     }
     ImplItems(SmallVec<[P<ast::AssocItem>; 1]>) {
         "impl item";
-        many fn flat_map_assoc_item;
-        fn visit_assoc_item(AssocCtxt::Impl { of_trait: false });
+        many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Impl { of_trait: false });
+            fn pprust::assoc_item_to_string;
         fn make_impl_items;
     }
     TraitImplItems(SmallVec<[P<ast::AssocItem>; 1]>) {
         "impl item";
-        many fn flat_map_assoc_item;
-        fn visit_assoc_item(AssocCtxt::Impl { of_trait: true });
+        many fn flat_map_assoc_item; fn visit_assoc_item(AssocCtxt::Impl { of_trait: true });
+            fn pprust::assoc_item_to_string;
         fn make_trait_impl_items;
     }
     ForeignItems(SmallVec<[P<ast::ForeignItem>; 1]>) {
         "foreign item";
-        many fn flat_map_foreign_item;
-        fn visit_foreign_item();
+        many fn flat_map_foreign_item; fn visit_foreign_item(); fn pprust::foreign_item_to_string;
         fn make_foreign_items;
     }
     Arms(SmallVec<[ast::Arm; 1]>) {
-        "match arm"; many fn flat_map_arm; fn visit_arm(); fn make_arms;
+        "match arm";
+        many fn flat_map_arm; fn visit_arm(); fn unreachable_to_string;
+        fn make_arms;
     }
     ExprFields(SmallVec<[ast::ExprField; 1]>) {
-        "field expression"; many fn flat_map_expr_field; fn visit_expr_field(); fn make_expr_fields;
+        "field expression";
+        many fn flat_map_expr_field; fn visit_expr_field(); fn unreachable_to_string;
+        fn make_expr_fields;
     }
     PatFields(SmallVec<[ast::PatField; 1]>) {
         "field pattern";
-        many fn flat_map_pat_field;
-        fn visit_pat_field();
+        many fn flat_map_pat_field; fn visit_pat_field(); fn unreachable_to_string;
         fn make_pat_fields;
     }
     GenericParams(SmallVec<[ast::GenericParam; 1]>) {
         "generic parameter";
-        many fn flat_map_generic_param;
-        fn visit_generic_param();
+        many fn flat_map_generic_param; fn visit_generic_param(); fn unreachable_to_string;
         fn make_generic_params;
     }
     Params(SmallVec<[ast::Param; 1]>) {
-        "function parameter"; many fn flat_map_param; fn visit_param(); fn make_params;
+        "function parameter";
+        many fn flat_map_param; fn visit_param(); fn unreachable_to_string;
+        fn make_params;
     }
     FieldDefs(SmallVec<[ast::FieldDef; 1]>) {
         "field";
-        many fn flat_map_field_def;
-        fn visit_field_def();
+        many fn flat_map_field_def; fn visit_field_def(); fn unreachable_to_string;
         fn make_field_defs;
     }
     Variants(SmallVec<[ast::Variant; 1]>) {
-        "variant"; many fn flat_map_variant; fn visit_variant(); fn make_variants;
+        "variant"; many fn flat_map_variant; fn visit_variant(); fn unreachable_to_string;
+        fn make_variants;
     }
     WherePredicates(SmallVec<[ast::WherePredicate; 1]>) {
         "where predicate";
-        many fn flat_map_where_predicate;
-        fn visit_where_predicate();
+        many fn flat_map_where_predicate; fn visit_where_predicate(); fn unreachable_to_string;
         fn make_where_predicates;
-     }
-    Crate(ast::Crate) { "crate"; one fn visit_crate; fn visit_crate; fn make_crate; }
+    }
+    Crate(ast::Crate) {
+        "crate";
+        one fn visit_crate; fn visit_crate; fn unreachable_to_string;
+        fn make_crate;
+    }
 }
 
 pub enum SupportsMacroExpansion {
@@ -270,7 +316,7 @@ impl AstFragmentKind {
         }
     }
 
-    fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>(
+    pub(crate) fn expect_from_annotatables<I: IntoIterator<Item = Annotatable>>(
         self,
         items: I,
     ) -> AstFragment {
@@ -686,13 +732,26 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             return ExpandResult::Ready(invoc.fragment_kind.dummy(invoc.span(), guar));
         }
 
+        let macro_stats = self.cx.sess.opts.unstable_opts.macro_stats;
+
         let (fragment_kind, span) = (invoc.fragment_kind, invoc.span());
         ExpandResult::Ready(match invoc.kind {
             InvocationKind::Bang { mac, span } => match ext {
                 SyntaxExtensionKind::Bang(expander) => {
                     match expander.expand(self.cx, span, mac.args.tokens.clone()) {
                         Ok(tok_result) => {
-                            self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span)
+                            let fragment =
+                                self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span);
+                            if macro_stats {
+                                update_bang_macro_stats(
+                                    self.cx,
+                                    fragment_kind,
+                                    span,
+                                    mac,
+                                    &fragment,
+                                );
+                            }
+                            fragment
                         }
                         Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)),
                     }
@@ -708,13 +767,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                             });
                         }
                     };
-                    let result = if let Some(result) = fragment_kind.make_from(tok_result) {
-                        result
+                    if let Some(fragment) = fragment_kind.make_from(tok_result) {
+                        if macro_stats {
+                            update_bang_macro_stats(self.cx, fragment_kind, span, mac, &fragment);
+                        }
+                        fragment
                     } else {
                         let guar = self.error_wrong_fragment_kind(fragment_kind, &mac, span);
                         fragment_kind.dummy(span, guar)
-                    };
-                    result
+                    }
                 }
                 _ => unreachable!(),
             },
@@ -746,24 +807,39 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         }
                         _ => item.to_tokens(),
                     };
-                    let attr_item = attr.unwrap_normal_item();
+                    let attr_item = attr.get_normal_item();
                     if let AttrArgs::Eq { .. } = attr_item.args {
                         self.cx.dcx().emit_err(UnsupportedKeyValue { span });
                     }
                     let inner_tokens = attr_item.args.inner_tokens();
                     match expander.expand(self.cx, span, inner_tokens, tokens) {
-                        Ok(tok_result) => self.parse_ast_fragment(
-                            tok_result,
-                            fragment_kind,
-                            &attr_item.path,
-                            span,
-                        ),
+                        Ok(tok_result) => {
+                            let fragment = self.parse_ast_fragment(
+                                tok_result,
+                                fragment_kind,
+                                &attr_item.path,
+                                span,
+                            );
+                            if macro_stats {
+                                update_attr_macro_stats(
+                                    self.cx,
+                                    fragment_kind,
+                                    span,
+                                    &attr_item.path,
+                                    &attr,
+                                    item,
+                                    &fragment,
+                                );
+                            }
+                            fragment
+                        }
                         Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)),
                     }
                 }
                 SyntaxExtensionKind::LegacyAttr(expander) => {
                     match validate_attr::parse_meta(&self.cx.sess.psess, &attr) {
                         Ok(meta) => {
+                            let item_clone = macro_stats.then(|| item.clone());
                             let items = match expander.expand(self.cx, span, &meta, item, false) {
                                 ExpandResult::Ready(items) => items,
                                 ExpandResult::Retry(item) => {
@@ -782,7 +858,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                                 let guar = self.cx.dcx().emit_err(RemoveExprNotSupported { span });
                                 fragment_kind.dummy(span, guar)
                             } else {
-                                fragment_kind.expect_from_annotatables(items)
+                                let fragment = fragment_kind.expect_from_annotatables(items);
+                                if macro_stats {
+                                    update_attr_macro_stats(
+                                        self.cx,
+                                        fragment_kind,
+                                        span,
+                                        &meta.path,
+                                        &attr,
+                                        item_clone.unwrap(),
+                                        &fragment,
+                                    );
+                                }
+                                fragment
                             }
                         }
                         Err(err) => {
@@ -792,6 +880,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     }
                 }
                 SyntaxExtensionKind::NonMacroAttr => {
+                    // `-Zmacro-stats` ignores these because they don't do any real expansion.
                     self.cx.expanded_inert_attrs.mark(&attr);
                     item.visit_attrs(|attrs| attrs.insert(pos, attr));
                     fragment_kind.expect_from_annotatables(iter::once(item))
@@ -822,7 +911,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                             });
                         }
                     };
-                    fragment_kind.expect_from_annotatables(items)
+                    let fragment = fragment_kind.expect_from_annotatables(items);
+                    if macro_stats {
+                        update_derive_macro_stats(
+                            self.cx,
+                            fragment_kind,
+                            span,
+                            &meta.path,
+                            &fragment,
+                        );
+                    }
+                    fragment
                 }
                 _ => unreachable!(),
             },
@@ -852,6 +951,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 let single_delegations = build_single_delegations::<Node>(
                     self.cx, deleg, &item, &suffixes, item.span, true,
                 );
+                // `-Zmacro-stats` ignores these because they don't seem important.
                 fragment_kind.expect_from_annotatables(
                     single_delegations
                         .map(|item| Annotatable::AssocItem(P(item), AssocCtxt::Impl { of_trait })),
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index 515d82296ca..64be7649775 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -20,6 +20,7 @@ mod errors;
 mod mbe;
 mod placeholders;
 mod proc_macro_server;
+mod stats;
 
 pub use mbe::macro_rules::compile_declarative_macro;
 pub mod base;
diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs
index 1a2db233b7a..3cd803c3e84 100644
--- a/compiler/rustc_expand/src/mbe/macro_check.rs
+++ b/compiler/rustc_expand/src/mbe/macro_check.rs
@@ -112,9 +112,8 @@ use rustc_ast::{DUMMY_NODE_ID, NodeId};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::MultiSpan;
 use rustc_lint_defs::BuiltinLintDiag;
-use rustc_session::lint::builtin::{META_VARIABLE_MISUSE, MISSING_FRAGMENT_SPECIFIER};
+use rustc_session::lint::builtin::META_VARIABLE_MISUSE;
 use rustc_session::parse::ParseSess;
-use rustc_span::edition::Edition;
 use rustc_span::{ErrorGuaranteed, MacroRulesNormalizedIdent, Span, kw};
 use smallvec::SmallVec;
 
@@ -266,23 +265,11 @@ fn check_binders(
         // Similarly, this can only happen when checking a toplevel macro.
         TokenTree::MetaVarDecl(span, name, kind) => {
             if kind.is_none() && node_id != DUMMY_NODE_ID {
-                // FIXME: Report this as a hard error eventually and remove equivalent errors from
-                // `parse_tt_inner` and `nameize`. Until then the error may be reported twice, once
-                // as a hard error and then once as a buffered lint.
-                if span.edition() >= Edition::Edition2024 {
-                    psess.dcx().emit_err(errors::MissingFragmentSpecifier {
-                        span,
-                        add_span: span.shrink_to_hi(),
-                        valid: VALID_FRAGMENT_NAMES_MSG,
-                    });
-                } else {
-                    psess.buffer_lint(
-                        MISSING_FRAGMENT_SPECIFIER,
-                        span,
-                        node_id,
-                        BuiltinLintDiag::MissingFragmentSpecifier,
-                    );
-                }
+                psess.dcx().emit_err(errors::MissingFragmentSpecifier {
+                    span,
+                    add_span: span.shrink_to_hi(),
+                    valid: VALID_FRAGMENT_NAMES_MSG,
+                });
             }
             if !macros.is_empty() {
                 psess.dcx().span_bug(span, "unexpected MetaVarDecl in nested lhs");
diff --git a/compiler/rustc_expand/src/stats.rs b/compiler/rustc_expand/src/stats.rs
new file mode 100644
index 00000000000..6b2ad30dffd
--- /dev/null
+++ b/compiler/rustc_expand/src/stats.rs
@@ -0,0 +1,171 @@
+use std::iter;
+
+use rustc_ast::ptr::P;
+use rustc_ast::{self as ast, DUMMY_NODE_ID, Expr, ExprKind};
+use rustc_ast_pretty::pprust;
+use rustc_span::hygiene::{ExpnKind, MacroKind};
+use rustc_span::{Span, Symbol, kw, sym};
+use smallvec::SmallVec;
+
+use crate::base::{Annotatable, ExtCtxt};
+use crate::expand::{AstFragment, AstFragmentKind};
+
+#[derive(Default)]
+pub struct MacroStat {
+    /// Number of uses of the macro.
+    pub uses: usize,
+
+    /// Net increase in number of lines of code (when pretty-printed), i.e.
+    /// `lines(output) - lines(invocation)`. Can be negative because a macro
+    /// output may be smaller than the invocation.
+    pub lines: isize,
+
+    /// Net increase in number of lines of code (when pretty-printed), i.e.
+    /// `bytes(output) - bytes(invocation)`. Can be negative because a macro
+    /// output may be smaller than the invocation.
+    pub bytes: isize,
+}
+
+pub(crate) fn elems_to_string<T>(elems: &SmallVec<[T; 1]>, f: impl Fn(&T) -> String) -> String {
+    let mut s = String::new();
+    for (i, elem) in elems.iter().enumerate() {
+        if i > 0 {
+            s.push('\n');
+        }
+        s.push_str(&f(elem));
+    }
+    s
+}
+
+pub(crate) fn unreachable_to_string<T>(_: &T) -> String {
+    unreachable!()
+}
+
+pub(crate) fn update_bang_macro_stats(
+    ecx: &mut ExtCtxt<'_>,
+    fragment_kind: AstFragmentKind,
+    span: Span,
+    mac: P<ast::MacCall>,
+    fragment: &AstFragment,
+) {
+    // Does this path match any of the include macros, e.g. `include!`?
+    // Ignore them. They would have large numbers but are entirely
+    // unsurprising and uninteresting.
+    let is_include_path = mac.path == sym::include
+        || mac.path == sym::include_bytes
+        || mac.path == sym::include_str
+        || mac.path == [sym::std, sym::include].as_slice() // std::include
+        || mac.path == [sym::std, sym::include_bytes].as_slice() // std::include_bytes
+        || mac.path == [sym::std, sym::include_str].as_slice(); // std::include_str
+    if is_include_path {
+        return;
+    }
+
+    // The call itself (e.g. `println!("hi")`) is the input. Need to wrap
+    // `mac` in something printable; `ast::Expr` is as good as anything
+    // else.
+    let expr = Expr {
+        id: DUMMY_NODE_ID,
+        kind: ExprKind::MacCall(mac),
+        span: Default::default(),
+        attrs: Default::default(),
+        tokens: None,
+    };
+    let input = pprust::expr_to_string(&expr);
+
+    // Get `mac` back out of `expr`.
+    let ast::Expr { kind: ExprKind::MacCall(mac), .. } = expr else { unreachable!() };
+
+    update_macro_stats(ecx, MacroKind::Bang, fragment_kind, span, &mac.path, &input, fragment);
+}
+
+pub(crate) fn update_attr_macro_stats(
+    ecx: &mut ExtCtxt<'_>,
+    fragment_kind: AstFragmentKind,
+    span: Span,
+    path: &ast::Path,
+    attr: &ast::Attribute,
+    item: Annotatable,
+    fragment: &AstFragment,
+) {
+    // Does this path match `#[derive(...)]` in any of its forms? If so,
+    // ignore it because the individual derives will go through the
+    // `Invocation::Derive` handling separately.
+    let is_derive_path = *path == sym::derive
+        // ::core::prelude::v1::derive
+        || *path == [kw::PathRoot, sym::core, sym::prelude, sym::v1, sym::derive].as_slice();
+    if is_derive_path {
+        return;
+    }
+
+    // The attribute plus the item itself constitute the input, which we
+    // measure.
+    let input = format!(
+        "{}\n{}",
+        pprust::attribute_to_string(attr),
+        fragment_kind.expect_from_annotatables(iter::once(item)).to_string(),
+    );
+    update_macro_stats(ecx, MacroKind::Attr, fragment_kind, span, path, &input, fragment);
+}
+
+pub(crate) fn update_derive_macro_stats(
+    ecx: &mut ExtCtxt<'_>,
+    fragment_kind: AstFragmentKind,
+    span: Span,
+    path: &ast::Path,
+    fragment: &AstFragment,
+) {
+    // Use something like `#[derive(Clone)]` for the measured input, even
+    // though it may have actually appeared in a multi-derive attribute
+    // like `#[derive(Clone, Copy, Debug)]`.
+    let input = format!("#[derive({})]", pprust::path_to_string(path));
+    update_macro_stats(ecx, MacroKind::Derive, fragment_kind, span, path, &input, fragment);
+}
+
+pub(crate) fn update_macro_stats(
+    ecx: &mut ExtCtxt<'_>,
+    macro_kind: MacroKind,
+    fragment_kind: AstFragmentKind,
+    span: Span,
+    path: &ast::Path,
+    input: &str,
+    fragment: &AstFragment,
+) {
+    fn lines_and_bytes(s: &str) -> (usize, usize) {
+        (s.trim_end().split('\n').count(), s.len())
+    }
+
+    // Measure the size of the output by pretty-printing it and counting
+    // the lines and bytes.
+    let name = Symbol::intern(&pprust::path_to_string(path));
+    let output = fragment.to_string();
+    let (in_l, in_b) = lines_and_bytes(input);
+    let (out_l, out_b) = lines_and_bytes(&output);
+
+    // This code is useful for debugging `-Zmacro-stats`. For every
+    // invocation it prints the full input and output.
+    if false {
+        let name = ExpnKind::Macro(macro_kind, name).descr();
+        let crate_name = &ecx.ecfg.crate_name;
+        let span = ecx
+            .sess
+            .source_map()
+            .span_to_string(span, rustc_span::FileNameDisplayPreference::Local);
+        eprint!(
+            "\
+            -------------------------------\n\
+            {name}: [{crate_name}] ({fragment_kind:?}) {span}\n\
+            -------------------------------\n\
+            {input}\n\
+            -- ({in_l} lines, {in_b} bytes) --> ({out_l} lines, {out_b} bytes) --\n\
+            {output}\n\
+        "
+        );
+    }
+
+    // The recorded size is the difference between the input and the output.
+    let entry = ecx.macro_stats.entry((name, macro_kind)).or_insert(MacroStat::default());
+    entry.uses += 1;
+    entry.lines += out_l as isize - in_l as isize;
+    entry.bytes += out_b as isize - in_b as isize;
+}
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/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index c117e0fcf7c..73a21789c5d 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -9,7 +9,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_span::edition::Edition;
 use rustc_span::{Symbol, sym};
 
-use crate::{Features, Stability};
+use crate::Features;
 
 type GateFn = fn(&Features) -> bool;
 
@@ -94,34 +94,23 @@ pub enum AttributeSafety {
     Unsafe { unsafe_since: Option<Edition> },
 }
 
-#[derive(Clone, Copy)]
+#[derive(Clone, Debug, Copy)]
 pub enum AttributeGate {
-    /// Is gated by a given feature gate, reason
-    /// and function to check if enabled
-    Gated(Stability, Symbol, &'static str, fn(&Features) -> bool),
-
+    /// A gated attribute which requires a feature gate to be enabled.
+    Gated {
+        /// The feature gate, for example `#![feature(rustc_attrs)]` for rustc_* attributes.
+        feature: Symbol,
+        /// The error message displayed when an attempt is made to use the attribute without its feature gate.
+        message: &'static str,
+        /// Check function to be called during the `PostExpansionVisitor` pass.
+        check: fn(&Features) -> bool,
+        /// Notes to be displayed when an attempt is made to use the attribute without its feature gate.
+        notes: &'static [&'static str],
+    },
     /// Ungated attribute, can be used on all release channels
     Ungated,
 }
 
-// fn() is not Debug
-impl std::fmt::Debug for AttributeGate {
-    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match *self {
-            Self::Gated(ref stab, name, expl, _) => {
-                write!(fmt, "Gated({stab:?}, {name}, {expl})")
-            }
-            Self::Ungated => write!(fmt, "Ungated"),
-        }
-    }
-}
-
-impl AttributeGate {
-    fn is_deprecated(&self) -> bool {
-        matches!(*self, Self::Gated(Stability::Deprecated(_, _), ..))
-    }
-}
-
 /// A template that the attribute input must match.
 /// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
 #[derive(Clone, Copy, Default)]
@@ -247,7 +236,7 @@ macro_rules! ungated {
 }
 
 macro_rules! gated {
-    (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => {
+    (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $message:expr $(,)?) => {
         BuiltinAttribute {
             name: sym::$attr,
             encode_cross_crate: $encode_cross_crate,
@@ -255,10 +244,15 @@ macro_rules! gated {
             safety: AttributeSafety::Unsafe { unsafe_since: None },
             template: $tpl,
             duplicates: $duplicates,
-            gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate),
+            gate: Gated {
+                feature: sym::$gate,
+                message: $message,
+                check: Features::$gate,
+                notes: &[],
+            },
         }
     };
-    (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => {
+    (unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $message:expr $(,)?) => {
         BuiltinAttribute {
             name: sym::$attr,
             encode_cross_crate: $encode_cross_crate,
@@ -266,10 +260,15 @@ macro_rules! gated {
             safety: AttributeSafety::Unsafe { unsafe_since: None },
             template: $tpl,
             duplicates: $duplicates,
-            gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr),
+            gate: Gated {
+                feature: sym::$attr,
+                message: $message,
+                check: Features::$attr,
+                notes: &[],
+            },
         }
     };
-    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $msg:expr $(,)?) => {
+    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $message:expr $(,)?) => {
         BuiltinAttribute {
             name: sym::$attr,
             encode_cross_crate: $encode_cross_crate,
@@ -277,10 +276,15 @@ macro_rules! gated {
             safety: AttributeSafety::Normal,
             template: $tpl,
             duplicates: $duplicates,
-            gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate),
+            gate: Gated {
+                feature: sym::$gate,
+                message: $message,
+                check: Features::$gate,
+                notes: &[],
+            },
         }
     };
-    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => {
+    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $message:expr $(,)?) => {
         BuiltinAttribute {
             name: sym::$attr,
             encode_cross_crate: $encode_cross_crate,
@@ -288,7 +292,12 @@ macro_rules! gated {
             safety: AttributeSafety::Normal,
             template: $tpl,
             duplicates: $duplicates,
-            gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr),
+            gate: Gated {
+                feature: sym::$attr,
+                message: $message,
+                check: Features::$attr,
+                notes: &[],
+            },
         }
     };
 }
@@ -304,12 +313,11 @@ macro_rules! rustc_attr {
             concat!(
                 "the `#[",
                 stringify!($attr),
-                "]` attribute is just used for rustc unit tests \
-                and will never be stable",
+                "]` attribute is used for rustc unit tests"
             ),
         )
     };
-    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $msg:expr $(,)?) => {
+    ($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $($notes:expr),* $(,)?) => {
         BuiltinAttribute {
             name: sym::$attr,
             encode_cross_crate: $encode_cross_crate,
@@ -317,7 +325,17 @@ macro_rules! rustc_attr {
             safety: AttributeSafety::Normal,
             template: $tpl,
             duplicates: $duplicates,
-            gate: Gated(Stability::Unstable, sym::rustc_attrs, $msg, Features::rustc_attrs),
+            gate: Gated {
+                feature: sym::rustc_attrs,
+                message: "use of an internal attribute",
+                check: Features::rustc_attrs,
+                notes: &[
+                    concat!("the `#[",
+                    stringify!($attr),
+                    "]` attribute is an internal implementation detail that will never be stable"),
+                    $($notes),*
+                    ]
+            },
         }
     };
 }
@@ -328,9 +346,6 @@ macro_rules! experimental {
     };
 }
 
-const IMPL_DETAIL: &str = "internal implementation detail";
-const INTERNAL_UNSTABLE: &str = "this is an internal attribute that will never be stable";
-
 #[derive(PartialEq)]
 pub enum EncodeCrossCrate {
     Yes,
@@ -668,7 +683,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     rustc_attr!(
         rustc_deprecated_safe_2024, Normal, template!(List: r#"audit_that = "...""#),
         ErrorFollowing, EncodeCrossCrate::Yes,
-        "rustc_deprecated_safe_2024 is supposed to be used in libstd only",
+        "`#[rustc_deprecated_safe_2024]` is used to declare functions unsafe across the edition 2024 boundary",
     ),
     rustc_attr!(
         rustc_pub_transparent, Normal, template!(Word),
@@ -695,7 +710,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         ErrorFollowing,
         EncodeCrossCrate::No,
         "`rustc_never_type_options` is used to experiment with never type fallback and work on \
-         never type stabilization, and will never be stable"
+         never type stabilization"
     ),
 
     // ==========================================================================
@@ -704,23 +719,23 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
 
     rustc_attr!(
         rustc_allocator, Normal, template!(Word), WarnFollowing,
-        EncodeCrossCrate::No, IMPL_DETAIL
+        EncodeCrossCrate::No,
     ),
     rustc_attr!(
         rustc_nounwind, Normal, template!(Word), WarnFollowing,
-        EncodeCrossCrate::No, IMPL_DETAIL
+        EncodeCrossCrate::No,
     ),
     rustc_attr!(
         rustc_reallocator, Normal, template!(Word), WarnFollowing,
-        EncodeCrossCrate::No, IMPL_DETAIL
+        EncodeCrossCrate::No,
     ),
     rustc_attr!(
         rustc_deallocator, Normal, template!(Word), WarnFollowing,
-        EncodeCrossCrate::No, IMPL_DETAIL
+        EncodeCrossCrate::No,
     ),
     rustc_attr!(
         rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing,
-        EncodeCrossCrate::No, IMPL_DETAIL
+        EncodeCrossCrate::No,
     ),
     gated!(
         default_lib_allocator, Normal, template!(Word), WarnFollowing,
@@ -762,7 +777,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
     rustc_attr!(
         rustc_std_internal_symbol, Normal, template!(Word), WarnFollowing,
-        EncodeCrossCrate::No, INTERNAL_UNSTABLE
+        EncodeCrossCrate::No,
     ),
 
     // ==========================================================================
@@ -772,11 +787,11 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     rustc_attr!(
         rustc_builtin_macro, Normal,
         template!(Word, List: "name, /*opt*/ attributes(name1, name2, ...)"), ErrorFollowing,
-        EncodeCrossCrate::Yes, IMPL_DETAIL
+        EncodeCrossCrate::Yes,
     ),
     rustc_attr!(
         rustc_proc_macro_decls, Normal, template!(Word), WarnFollowing,
-        EncodeCrossCrate::No, INTERNAL_UNSTABLE
+        EncodeCrossCrate::No,
     ),
     rustc_attr!(
         rustc_macro_transparency, Normal,
@@ -786,7 +801,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     rustc_attr!(
         rustc_autodiff, Normal,
         template!(Word, List: r#""...""#), DuplicatesOk,
-        EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
+        EncodeCrossCrate::Yes,
     ),
     // Traces that are left when `cfg` and `cfg_attr` attributes are expanded.
     // The attributes are not gated, to avoid stability errors, but they cannot be used in stable
@@ -812,54 +827,53 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
             NameValueStr: "message"
         ),
         ErrorFollowing, EncodeCrossCrate::Yes,
-        INTERNAL_UNSTABLE
+        "see `#[diagnostic::on_unimplemented]` for the stable equivalent of this attribute"
     ),
     rustc_attr!(
         rustc_confusables, Normal,
         template!(List: r#""name1", "name2", ..."#),
         ErrorFollowing, EncodeCrossCrate::Yes,
-        INTERNAL_UNSTABLE,
     ),
     // Enumerates "identity-like" conversion methods to suggest on type mismatch.
     rustc_attr!(
         rustc_conversion_suggestion, Normal, template!(Word),
-        WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
+        WarnFollowing, EncodeCrossCrate::Yes,
     ),
     // Prevents field reads in the marked trait or method to be considered
     // during dead code analysis.
     rustc_attr!(
         rustc_trivial_field_reads, Normal, template!(Word),
-        WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
+        WarnFollowing, EncodeCrossCrate::Yes,
     ),
     // Used by the `rustc::potential_query_instability` lint to warn methods which
     // might not be stable during incremental compilation.
     rustc_attr!(
         rustc_lint_query_instability, Normal, template!(Word),
-        WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
+        WarnFollowing, EncodeCrossCrate::Yes,
     ),
     // Used by the `rustc::untracked_query_information` lint to warn methods which
     // might not be stable during incremental compilation.
     rustc_attr!(
         rustc_lint_untracked_query_information, Normal, template!(Word),
-        WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
+        WarnFollowing, EncodeCrossCrate::Yes,
     ),
     // Used by the `rustc::diagnostic_outside_of_impl` lints to assist in changes to diagnostic
     // APIs. Any function with this attribute will be checked by that lint.
     rustc_attr!(
         rustc_lint_diagnostics, Normal, template!(Word),
-        WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
+        WarnFollowing, EncodeCrossCrate::Yes,
     ),
     // Used by the `rustc::bad_opt_access` lint to identify `DebuggingOptions` and `CodegenOptions`
     // types (as well as any others in future).
     rustc_attr!(
         rustc_lint_opt_ty, Normal, template!(Word),
-        WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
+        WarnFollowing, EncodeCrossCrate::Yes,
     ),
     // Used by the `rustc::bad_opt_access` lint on fields
     // types (as well as any others in future).
     rustc_attr!(
         rustc_lint_opt_deny_field_access, Normal, template!(List: "message"),
-        WarnFollowing, EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
+        WarnFollowing, EncodeCrossCrate::Yes,
     ),
 
     // ==========================================================================
@@ -868,28 +882,30 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
 
     rustc_attr!(
         rustc_promotable, Normal, template!(Word), WarnFollowing,
-        EncodeCrossCrate::No, IMPL_DETAIL),
+        EncodeCrossCrate::No, ),
     rustc_attr!(
         rustc_legacy_const_generics, Normal, template!(List: "N"), ErrorFollowing,
-        EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
+        EncodeCrossCrate::Yes,
     ),
     // Do not const-check this function's body. It will always get replaced during CTFE.
     rustc_attr!(
         rustc_do_not_const_check, Normal, template!(Word), WarnFollowing,
-        EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
+        EncodeCrossCrate::Yes, "`#[rustc_do_not_const_check]` skips const-check for this function's body",
     ),
-    // Ensure the argument to this function is &&str during const-check.
     rustc_attr!(
         rustc_const_panic_str, Normal, template!(Word), WarnFollowing,
-        EncodeCrossCrate::Yes, INTERNAL_UNSTABLE
+        EncodeCrossCrate::Yes, "`#[rustc_const_panic_str]` ensures the argument to this function is &&str during const-check",
     ),
     rustc_attr!(
         rustc_const_stable_indirect, Normal,
-        template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL,
+        template!(Word),
+        WarnFollowing,
+        EncodeCrossCrate::No,
+        "this is an internal implementation detail",
     ),
     rustc_attr!(
         rustc_intrinsic_const_stable_indirect, Normal,
-        template!(Word), WarnFollowing, EncodeCrossCrate::No, IMPL_DETAIL,
+        template!(Word), WarnFollowing, EncodeCrossCrate::No,  "this is an internal implementation detail",
     ),
     gated!(
         rustc_allow_const_fn_unstable, Normal,
@@ -905,21 +921,21 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"), ErrorFollowing,
         EncodeCrossCrate::Yes,
         "the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \
-        niche optimizations in libcore and libstd and will never be stable",
+        niche optimizations in the standard library",
     ),
     rustc_attr!(
         rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"), ErrorFollowing,
         EncodeCrossCrate::Yes,
         "the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
-        niche optimizations in libcore and libstd and will never be stable",
+        niche optimizations in the standard library",
     ),
     rustc_attr!(
         rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing,
         EncodeCrossCrate::Yes,
         "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document \
-        guaranteed niche optimizations in libcore and libstd and will never be stable\n\
-        (note that the compiler does not even check whether the type indeed is being non-null-optimized; \
-        it is your responsibility to ensure that the attribute is only used on types that are optimized)",
+        guaranteed niche optimizations in the standard library",
+        "the compiler does not even check whether the type indeed is being non-null-optimized; \
+        it is your responsibility to ensure that the attribute is only used on types that are optimized",
     ),
 
     // ==========================================================================
@@ -932,17 +948,17 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     rustc_attr!(
         rustc_as_ptr, Normal, template!(Word), ErrorFollowing,
         EncodeCrossCrate::Yes,
-        "#[rustc_as_ptr] is used to mark functions returning pointers to their inner allocations."
+        "`#[rustc_as_ptr]` is used to mark functions returning pointers to their inner allocations."
     ),
     rustc_attr!(
         rustc_pass_by_value, Normal, template!(Word), ErrorFollowing,
         EncodeCrossCrate::Yes,
-        "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference."
+        "`#[rustc_pass_by_value]` is used to mark types that must be passed by value instead of reference."
     ),
     rustc_attr!(
         rustc_never_returns_null_ptr, Normal, template!(Word), ErrorFollowing,
         EncodeCrossCrate::Yes,
-        "#[rustc_never_returns_null_ptr] is used to mark functions returning non-null pointers."
+        "`#[rustc_never_returns_null_ptr]` is used to mark functions returning non-null pointers."
     ),
     rustc_attr!(
         rustc_no_implicit_autorefs, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes,
@@ -950,15 +966,15 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
     rustc_attr!(
         rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
-        "#![rustc_coherence_is_core] allows inherent methods on builtin types, only intended to be used in `core`."
+        "`#![rustc_coherence_is_core]` allows inherent methods on builtin types, only intended to be used in `core`."
     ),
     rustc_attr!(
         rustc_coinductive, AttributeType::Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
-        "#![rustc_coinductive] changes a trait to be coinductive, allowing cycles in the trait solver."
+        "`#[rustc_coinductive]` changes a trait to be coinductive, allowing cycles in the trait solver."
     ),
     rustc_attr!(
         rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
-        "#[rustc_allow_incoherent_impl] has to be added to all impl items of an incoherent inherent impl."
+        "`#[rustc_allow_incoherent_impl]` has to be added to all impl items of an incoherent inherent impl."
     ),
     rustc_attr!(
         rustc_preserve_ub_checks, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
@@ -970,7 +986,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         template!(Word),
         ErrorFollowing,
         EncodeCrossCrate::No,
-        "#[rustc_deny_explicit_impl] enforces that a trait can have no user-provided impls"
+        "`#[rustc_deny_explicit_impl]` enforces that a trait can have no user-provided impls"
     ),
     rustc_attr!(
         rustc_do_not_implement_via_object,
@@ -978,14 +994,14 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         template!(Word),
         ErrorFollowing,
         EncodeCrossCrate::No,
-        "#[rustc_do_not_implement_via_object] opts out of the automatic trait impl for trait objects \
+        "`#[rustc_do_not_implement_via_object]` opts out of the automatic trait impl for trait objects \
         (`impl Trait for dyn Trait`)"
     ),
     rustc_attr!(
         rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word),
         ErrorFollowing, EncodeCrossCrate::Yes,
-        "#[rustc_has_incoherent_inherent_impls] allows the addition of incoherent inherent impls for \
-         the given type by annotating all impl items with #[rustc_allow_incoherent_impl]."
+        "`#[rustc_has_incoherent_inherent_impls]` allows the addition of incoherent inherent impls for \
+         the given type by annotating all impl items with `#[rustc_allow_incoherent_impl]`."
     ),
 
     BuiltinAttribute {
@@ -996,12 +1012,13 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         safety: AttributeSafety::Normal,
         template: template!(NameValueStr: "name"),
         duplicates: ErrorFollowing,
-        gate: Gated(
-            Stability::Unstable,
-            sym::rustc_attrs,
-            "diagnostic items compiler internal support for linting",
-            Features::rustc_attrs,
-        ),
+        gate: Gated{
+            feature: sym::rustc_attrs,
+            message: "use of an internal attribute",
+            check: Features::rustc_attrs,
+            notes: &["the `#[rustc_diagnostic_item]` attribute allows the compiler to reference types \
+            from the standard library for diagnostic purposes"],
+        },
     },
     gated!(
         // Used in resolve:
@@ -1015,14 +1032,14 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     rustc_attr!(
         rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
         "the `#[rustc_inherit_overflow_checks]` attribute is just used to control \
-        overflow checking behavior of several libcore functions that are inlined \
-        across crates and will never be stable",
+        overflow checking behavior of several functions in the standard library that are inlined \
+        across crates",
     ),
     rustc_attr!(
         rustc_reservation_impl, Normal,
         template!(NameValueStr: "reservation message"), ErrorFollowing, EncodeCrossCrate::Yes,
         "the `#[rustc_reservation_impl]` attribute is internally used \
-         for reserving for `for<T> From<!> for T` impl"
+        for reserving `impl<T> From<!> for T` as part of the effort to stabilize `!`"
     ),
     rustc_attr!(
         rustc_test_marker, Normal, template!(NameValueStr: "name"), WarnFollowing,
@@ -1053,12 +1070,13 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."),
         ErrorFollowing, EncodeCrossCrate::No,
         "the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete \
-        definition of a trait, it's currently in experimental form and should be changed before \
-        being exposed outside of the std"
+        definition of a trait. Its syntax and semantics are highly experimental and will be \
+        subject to change before stabilization",
     ),
     rustc_attr!(
         rustc_doc_primitive, Normal, template!(NameValueStr: "primitive name"), ErrorFollowing,
-        EncodeCrossCrate::Yes, r#"`rustc_doc_primitive` is a rustc internal attribute"#,
+        EncodeCrossCrate::Yes, "the `#[rustc_doc_primitive]` attribute is used by the standard library \
+        to provide a way to generate documentation for primitive types",
     ),
     gated!(
         rustc_intrinsic, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, intrinsics,
@@ -1066,11 +1084,11 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
     rustc_attr!(
         rustc_no_mir_inline, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes,
-        "#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen"
+        "`#[rustc_no_mir_inline]` prevents the MIR inliner from inlining a function while not affecting codegen"
     ),
     rustc_attr!(
         rustc_force_inline, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, EncodeCrossCrate::Yes,
-        "#[rustc_force_inline] forces a free function to be inlined"
+        "`#[rustc_force_inline]` forces a free function to be inlined"
     ),
 
     // ==========================================================================
@@ -1209,10 +1227,6 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
 ];
 
-pub fn deprecated_attributes() -> Vec<&'static BuiltinAttribute> {
-    BUILTIN_ATTRIBUTES.iter().filter(|attr| attr.gate.is_deprecated()).collect()
-}
-
 pub fn is_builtin_attr_name(name: Symbol) -> bool {
     BUILTIN_ATTRIBUTE_MAP.get(&name).is_some()
 }
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index 25764755a8f..dbc0daa3d83 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -40,14 +40,6 @@ pub struct Feature {
     issue: Option<NonZero<u32>>,
 }
 
-#[derive(Copy, Clone, Debug)]
-pub enum Stability {
-    Unstable,
-    // First argument is tracking issue link; second argument is an optional
-    // help message, which defaults to "remove this attribute".
-    Deprecated(&'static str, Option<&'static str>),
-}
-
 #[derive(Clone, Copy, Debug, Hash)]
 pub enum UnstableFeatures {
     /// Disallow use of unstable features, as on beta/stable channels.
@@ -144,9 +136,8 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZero<u
 pub use accepted::ACCEPTED_LANG_FEATURES;
 pub use builtin_attrs::{
     AttributeDuplicates, AttributeGate, AttributeSafety, AttributeTemplate, AttributeType,
-    BUILTIN_ATTRIBUTE_MAP, BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg, deprecated_attributes,
-    encode_cross_crate, find_gated_cfg, is_builtin_attr_name, is_stable_diagnostic_attribute,
-    is_valid_for_get_attr,
+    BUILTIN_ATTRIBUTE_MAP, BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg, encode_cross_crate,
+    find_gated_cfg, is_builtin_attr_name, is_stable_diagnostic_attribute, is_valid_for_get_attr,
 };
 pub use removed::REMOVED_LANG_FEATURES;
 pub use unstable::{
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..cfdca8c48b0 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -353,6 +353,8 @@ declare_features! (
     (unstable, abi_avr_interrupt, "1.45.0", Some(69664)),
     /// Allows `extern "C-cmse-nonsecure-call" fn()`.
     (unstable, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391)),
+    /// Allows `extern "custom" fn()`.
+    (unstable, abi_custom, "CURRENT_RUSTC_VERSION", Some(140829)),
     /// Allows `extern "gpu-kernel" fn()`.
     (unstable, abi_gpu_kernel, "1.86.0", Some(135467)),
     /// Allows `extern "msp430-interrupt" fn()`.
@@ -546,8 +548,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/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 6f288bb39b9..336bf0d93fd 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -34,6 +34,7 @@ use crate::def::{CtorKind, DefKind, PerNS, Res};
 use crate::def_id::{DefId, LocalDefIdMap};
 pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId};
 use crate::intravisit::{FnKind, VisitorExt};
+use crate::lints::DelayedLints;
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)]
 pub enum AngleBrackets {
@@ -1526,6 +1527,10 @@ pub struct OwnerInfo<'hir> {
     /// Map indicating what traits are in scope for places where this
     /// is relevant; generated by resolve.
     pub trait_map: ItemLocalMap<Box<[TraitCandidate]>>,
+
+    /// Lints delayed during ast lowering to be emitted
+    /// after hir has completely built
+    pub delayed_lints: DelayedLints,
 }
 
 impl<'tcx> OwnerInfo<'tcx> {
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index c6fe475b460..dafd31336fb 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -27,6 +27,7 @@ mod hir;
 pub mod hir_id;
 pub mod intravisit;
 pub mod lang_items;
+pub mod lints;
 pub mod pat_util;
 mod stable_hash_impls;
 mod target;
diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs
new file mode 100644
index 00000000000..7be6c32e57e
--- /dev/null
+++ b/compiler/rustc_hir/src/lints.rs
@@ -0,0 +1,23 @@
+use rustc_attr_data_structures::lints::AttributeLint;
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_macros::HashStable_Generic;
+
+use crate::HirId;
+
+/// During ast lowering, no lints can be emitted.
+/// That is because lints attach to nodes either in the AST, or on the built HIR.
+/// When attached to AST nodes, they're emitted just before building HIR,
+/// and then there's a gap where no lints can be emitted until HIR is done.
+/// The variants in this enum represent lints that are temporarily stashed during
+/// AST lowering to be emitted once HIR is built.
+#[derive(Clone, Debug, HashStable_Generic)]
+pub enum DelayedLint {
+    AttributeParsing(AttributeLint<HirId>),
+}
+
+#[derive(Debug)]
+pub struct DelayedLints {
+    pub lints: Box<[DelayedLint]>,
+    // Only present when the crate hash is needed.
+    pub opt_hash: Option<Fingerprint>,
+}
diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs
index 91ea88cae47..6acf1524b60 100644
--- a/compiler/rustc_hir/src/stable_hash_impls.rs
+++ b/compiler/rustc_hir/src/stable_hash_impls.rs
@@ -6,6 +6,7 @@ use crate::hir::{
     AttributeMap, BodyId, Crate, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId,
 };
 use crate::hir_id::{HirId, ItemLocalId};
+use crate::lints::DelayedLints;
 
 /// Requirements for a `StableHashingContext` to be used in this crate.
 /// This is a hack to allow using the `HashStable_Generic` derive macro
@@ -102,6 +103,13 @@ impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for OwnerNodes<'
     }
 }
 
+impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for DelayedLints {
+    fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
+        let DelayedLints { opt_hash, .. } = *self;
+        opt_hash.unwrap().hash_stable(hcx, hasher);
+    }
+}
+
 impl<'tcx, HirCtx: crate::HashStableContext> HashStable<HirCtx> for AttributeMap<'tcx> {
     fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
         // We ignore the `map` since it refers to information included in `opt_hash` which is
diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml
index 899370b34e4..5d6c49ee862 100644
--- a/compiler/rustc_hir_analysis/Cargo.toml
+++ b/compiler/rustc_hir_analysis/Cargo.toml
@@ -14,6 +14,7 @@ rustc_abi = { path = "../rustc_abi" }
 rustc_arena = { path = "../rustc_arena" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
+rustc_attr_parsing = { path = "../rustc_attr_parsing" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_feature = { path = "../rustc_feature" }
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 4fcd9f8a646..3e98bd213d3 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -1,3 +1,7 @@
+hir_analysis_abi_custom_clothed_function =
+    items with the `"custom"` ABI can only be declared externally or defined via naked functions
+    .suggestion = convert this to an `#[unsafe(naked)]` function
+
 hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_ident}` in bounds of `{$qself}`
     .label = ambiguous associated {$assoc_kind} `{$assoc_ident}`
 
diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs
index 99e495d9266..c88c534e135 100644
--- a/compiler/rustc_hir_analysis/src/autoderef.rs
+++ b/compiler/rustc_hir_analysis/src/autoderef.rs
@@ -160,7 +160,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
             self.param_env,
             ty::Binder::dummy(trait_ref),
         );
-        if !self.infcx.predicate_may_hold(&obligation) {
+        if !self.infcx.next_trait_solver() && !self.infcx.predicate_may_hold(&obligation) {
             debug!("overloaded_deref_ty: cannot match obligation");
             return None;
         }
@@ -184,17 +184,17 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
             self.param_env,
             ty,
         ) else {
-            // We shouldn't have errors here, except for evaluate/fulfill mismatches,
-            // but that's not a reason for an ICE (`predicate_may_hold` is conservative
-            // by design).
-            // FIXME(-Znext-solver): This *actually* shouldn't happen then.
+            // We shouldn't have errors here in the old solver, except for
+            // evaluate/fulfill mismatches, but that's not a reason for an ICE.
             return None;
         };
         let errors = ocx.select_where_possible();
         if !errors.is_empty() {
-            // This shouldn't happen, except for evaluate/fulfill mismatches,
-            // but that's not a reason for an ICE (`predicate_may_hold` is conservative
-            // by design).
+            if self.infcx.next_trait_solver() {
+                unreachable!();
+            }
+            // We shouldn't have errors here in the old solver, except for
+            // evaluate/fulfill mismatches, but that's not a reason for an ICE.
             debug!(?errors, "encountered errors while fulfilling");
             return None;
         }
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 064b42413f0..32fec0604c0 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -21,7 +21,7 @@ use rustc_middle::ty::error::TypeErrorToStringExt;
 use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
 use rustc_middle::ty::util::Discr;
 use rustc_middle::ty::{
-    AdtDef, BottomUpFolder, GenericArgKind, RegionKind, TypeFoldable, TypeSuperVisitable,
+    AdtDef, BottomUpFolder, FnSig, GenericArgKind, RegionKind, TypeFoldable, TypeSuperVisitable,
     TypeVisitable, TypeVisitableExt, fold_regions,
 };
 use rustc_session::lint::builtin::UNINHABITED_STATIC;
@@ -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"
@@ -90,6 +100,18 @@ pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ex
     }
 }
 
+pub fn check_custom_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, fn_sig: FnSig<'_>, fn_sig_span: Span) {
+    if fn_sig.abi == ExternAbi::Custom {
+        // Function definitions that use `extern "custom"` must be naked functions.
+        if !tcx.has_attr(def_id, sym::naked) {
+            tcx.dcx().emit_err(crate::errors::AbiCustomClothedFunction {
+                span: fn_sig_span,
+                naked_span: tcx.def_span(def_id).shrink_to_lo(),
+            });
+        }
+    }
+}
+
 fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     let def = tcx.adt_def(def_id);
     let span = tcx.def_span(def_id);
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 481cdaa4c6c..060fc51b7bd 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -71,7 +71,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
         | sym::box_new
         | sym::breakpoint
         | sym::size_of
-        | sym::min_align_of
+        | sym::align_of
         | sym::needs_drop
         | sym::caller_location
         | sym::add_with_overflow
@@ -200,10 +200,8 @@ pub(crate) fn check_intrinsic_type(
         sym::abort => (0, 0, vec![], tcx.types.never),
         sym::unreachable => (0, 0, vec![], tcx.types.never),
         sym::breakpoint => (0, 0, vec![], tcx.types.unit),
-        sym::size_of | sym::pref_align_of | sym::min_align_of | sym::variant_count => {
-            (1, 0, vec![], tcx.types.usize)
-        }
-        sym::size_of_val | sym::min_align_of_val => {
+        sym::size_of | sym::align_of | sym::variant_count => (1, 0, vec![], tcx.types.usize),
+        sym::size_of_val | sym::align_of_val => {
             (1, 0, vec![Ty::new_imm_ptr(tcx, param(0))], tcx.types.usize)
         }
         sym::rustc_peek => (1, 0, vec![param(0)], param(0)),
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index fad8abf5fae..c5c7e6b2aa7 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -72,7 +72,7 @@ pub mod wfcheck;
 
 use std::num::NonZero;
 
-pub use check::{check_abi, check_abi_fn_ptr};
+pub use check::{check_abi, check_abi_fn_ptr, check_custom_abi};
 use rustc_abi::{ExternAbi, VariantIdx};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err};
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index e1df0d60452..6e22ac5a28a 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -494,7 +494,7 @@ impl<'tcx> HirTyLowerer<'tcx> for ItemCtxt<'tcx> {
 
                 // Only visit the type looking for `_` if we didn't fix the type above
                 visitor.visit_ty_unambig(a);
-                self.lowerer().lower_arg_ty(a, None)
+                self.lowerer().lower_ty(a)
             })
             .collect();
 
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index a27d1ed6c53..809cb311c1f 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1698,3 +1698,17 @@ pub(crate) struct SelfInTypeAlias {
     #[label]
     pub span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_abi_custom_clothed_function)]
+pub(crate) struct AbiCustomClothedFunction {
+    #[primary_span]
+    pub span: Span,
+    #[suggestion(
+        hir_analysis_suggestion,
+        applicability = "maybe-incorrect",
+        code = "#[unsafe(naked)]\n",
+        style = "short"
+    )]
+    pub naked_span: Span,
+}
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 4c65d0d0510..bf407cbaccb 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -805,7 +805,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                     ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity })
                 });
                 let bound = (bound.upcast(tcx), span);
-                // FIXME(-Znext-solver): We can likely remove this hack once the new trait solver lands.
+                // FIXME(-Znext-solver): We can likely remove this hack once the
+                // new trait solver lands. This fixed an overflow in the old solver.
+                // This may have performance implications, so please check perf when
+                // removing it.
+                // This was added in <https://github.com/rust-lang/rust/pull/123302>.
                 if tcx.is_lang_item(trait_def_id, rustc_hir::LangItem::Sized) {
                     bounds.insert(0, bound);
                 } else {
@@ -2704,16 +2708,6 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }
     }
 
-    pub fn lower_arg_ty(&self, ty: &hir::Ty<'tcx>, expected_ty: Option<Ty<'tcx>>) -> Ty<'tcx> {
-        match ty.kind {
-            hir::TyKind::Infer(()) if let Some(expected_ty) = expected_ty => {
-                self.record_ty(ty.hir_id, expected_ty, ty.span);
-                expected_ty
-            }
-            _ => self.lower_ty(ty),
-        }
-    }
-
     /// Lower a function type from the HIR to our internal notion of a function signature.
     #[instrument(level = "debug", skip(self, hir_id, safety, abi, decl, generics, hir_ty), ret)]
     pub fn lower_fn_ty(
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index a92ee89186c..007f3a6abf6 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -92,8 +92,9 @@ mod variance;
 
 pub use errors::NoVariantNamed;
 use rustc_abi::ExternAbi;
-use rustc_hir as hir;
 use rustc_hir::def::DefKind;
+use rustc_hir::lints::DelayedLint;
+use rustc_hir::{self as hir};
 use rustc_middle::middle;
 use rustc_middle::mir::interpret::GlobalId;
 use rustc_middle::query::Providers;
@@ -174,6 +175,14 @@ pub fn provide(providers: &mut Providers) {
     };
 }
 
+fn emit_delayed_lint(lint: &DelayedLint, tcx: TyCtxt<'_>) {
+    match lint {
+        DelayedLint::AttributeParsing(attribute_lint) => {
+            rustc_attr_parsing::emit_attribute_lint(attribute_lint, tcx)
+        }
+    }
+}
+
 pub fn check_crate(tcx: TyCtxt<'_>) {
     let _prof_timer = tcx.sess.timer("type_check_crate");
 
@@ -192,6 +201,14 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
         let _: R = tcx.ensure_ok().crate_inherent_impls_overlap_check(());
     });
 
+    for owner_id in tcx.hir_crate_items(()).owners() {
+        if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) {
+            for lint in &delayed_lints.lints {
+                emit_delayed_lint(lint, tcx);
+            }
+        }
+    }
+
     tcx.par_hir_body_owners(|item_def_id| {
         let def_kind = tcx.def_kind(item_def_id);
         // Make sure we evaluate all static and (non-associated) const items, even if unused.
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index 6c33dfb4ec0..ac7ff65528d 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -1,3 +1,7 @@
+hir_typeck_abi_custom_call =
+    functions with the `"custom"` ABI cannot be called
+    .note = an `extern "custom"` function can only be called from within inline assembly
+
 hir_typeck_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function
 
 hir_typeck_add_return_type_add = try adding a return type
@@ -17,6 +21,24 @@ hir_typeck_base_expression_double_dot_enable_default_field_values =
     add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields
 hir_typeck_base_expression_double_dot_remove = remove the `..` as all the fields are already present
 
+hir_typeck_break_inside_closure =
+    `{$name}` inside of a closure
+    .label = cannot `{$name}` inside of a closure
+    .closure_label = enclosing closure
+
+hir_typeck_break_inside_coroutine =
+    `{$name}` inside `{$kind}` {$source}
+    .label = cannot `{$name}` inside `{$kind}` {$source}
+    .coroutine_label = enclosing `{$kind}` {$source}
+
+hir_typeck_break_non_loop =
+    `break` with value from a `{$kind}` loop
+    .label = can only break with a value inside `loop` or breakable block
+    .label2 = you can't `break` with a value in a `{$kind}` loop
+    .suggestion = use `break` on its own without a value inside this `{$kind}` loop
+    .break_expr_suggestion = alternatively, you might have meant to use the available loop label
+
+
 hir_typeck_candidate_trait_note = `{$trait_name}` defines an item `{$item_name}`{$action_or_ty ->
     [NONE] {""}
     [implement] , perhaps you need to implement it
@@ -64,6 +86,12 @@ hir_typeck_const_select_must_be_fn = this argument must be a function item
     .note = expected a function item, found {$ty}
     .help = consult the documentation on `const_eval_select` for more information
 
+hir_typeck_continue_labeled_block =
+    `continue` pointing to a labeled block
+    .label = labeled blocks cannot be `continue`'d
+    .block_label = labeled block the `continue` points to
+
+
 hir_typeck_convert_to_str = try converting the passed type into a `&str`
 
 hir_typeck_convert_using_method = try using `{$sugg}` to convert `{$found}` to `{$expected}`
@@ -182,6 +210,19 @@ hir_typeck_option_result_asref = use `{$def_path}::as_ref` to convert `{$expecte
 hir_typeck_option_result_cloned = use `{$def_path}::cloned` to clone the value inside the `{$def_path}`
 hir_typeck_option_result_copied = use `{$def_path}::copied` to copy the value inside the `{$def_path}`
 
+hir_typeck_outside_loop =
+    `{$name}` outside of a loop{$is_break ->
+        [true] {" or labeled block"}
+        *[false] {""}
+    }
+    .label = cannot `{$name}` outside of a loop{$is_break ->
+        [true] {" or labeled block"}
+        *[false] {""}
+    }
+
+hir_typeck_outside_loop_suggestion = consider labeling this block to be able to break within it
+
+
 hir_typeck_params_not_allowed =
     referencing function parameters is not allowed in naked functions
     .help = follow the calling convention in asm block to use parameters
@@ -254,6 +295,13 @@ hir_typeck_union_pat_dotdot = `..` cannot be used in union patterns
 
 hir_typeck_union_pat_multiple_fields = union patterns should have exactly one field
 
+hir_typeck_unlabeled_cf_in_while_condition =
+    `break` or `continue` with no label in the condition of a `while` loop
+    .label = unlabeled `{$cf_type}` in the condition of a `while` loop
+
+hir_typeck_unlabeled_in_labeled_block =
+    unlabeled `{$cf_type}` inside of a labeled block
+    .label = `{$cf_type}` statements that would diverge to or through a labeled block need to bear a label
 hir_typeck_use_is_empty =
     consider using the `is_empty` method on `{$expr_ty}` to determine if it contains anything
 
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 61dd8c57307..4ac260cb15f 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -600,7 +600,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let (def_id, args) = match *expected_ty.kind() {
             // FIXME: Could also check that the RPIT is not defined
             ty::Alias(ty::Opaque, alias_ty) => (alias_ty.def_id.as_local()?, alias_ty.args),
-            // FIXME(-Znext-solver): Remove this branch once `replace_opaque_types_with_infer` is gone.
+            // FIXME(-Znext-solver=no): Remove this branch once `replace_opaque_types_with_infer` is gone.
             ty::Infer(ty::TyVar(_)) => self
                 .inner
                 .borrow_mut()
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index d173fe7c2c2..e915b4fc626 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -1,5 +1,6 @@
 use std::iter;
 
+use rustc_abi::ExternAbi;
 use rustc_ast::util::parser::ExprPrecedence;
 use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey};
 use rustc_hir::def::{self, CtorKind, Namespace, Res};
@@ -83,6 +84,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         while result.is_none() && autoderef.next().is_some() {
             result = self.try_overloaded_call_step(call_expr, callee_expr, arg_exprs, &autoderef);
         }
+        self.check_call_custom_abi(autoderef.final_ty(false), call_expr.span);
         self.register_predicates(autoderef.into_obligations());
 
         let output = match result {
@@ -135,6 +137,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         output
     }
 
+    /// Functions of type `extern "custom" fn(/* ... */)` cannot be called using `ExprKind::Call`.
+    ///
+    /// These functions have a calling convention that is unknown to rust, hence it cannot generate
+    /// code for the call. The only way to execute such a function is via inline assembly.
+    fn check_call_custom_abi(&self, callee_ty: Ty<'tcx>, span: Span) {
+        let abi = match callee_ty.kind() {
+            ty::FnDef(def_id, _) => self.tcx.fn_sig(def_id).skip_binder().skip_binder().abi,
+            ty::FnPtr(_, header) => header.abi,
+            _ => return,
+        };
+
+        if let ExternAbi::Custom = abi {
+            self.tcx.dcx().emit_err(errors::AbiCustomCall { span });
+        }
+    }
+
     #[instrument(level = "debug", skip(self, call_expr, callee_expr, arg_exprs, autoderef), ret)]
     fn try_overloaded_call_step(
         &self,
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 152c88ad92a..5b55fbe9150 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -260,7 +260,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         mut expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
         allow_two_phase: AllowTwoPhase,
     ) -> Result<Ty<'tcx>, Diag<'a>> {
-        let expected = self.resolve_vars_with_obligations(expected);
+        let expected = if self.next_trait_solver() {
+            expected
+        } else {
+            self.resolve_vars_with_obligations(expected)
+        };
 
         let e = match self.coerce(expr, checked_ty, expected, allow_two_phase, None) {
             Ok(ty) => return Ok(ty),
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 97a90548fc5..abb8cdc1cdf 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -2,11 +2,14 @@
 
 use std::borrow::Cow;
 
+use rustc_ast::Label;
 use rustc_errors::codes::*;
 use rustc_errors::{
     Applicability, Diag, DiagArgValue, DiagCtxtHandle, DiagSymbolList, Diagnostic,
     EmissionGuarantee, IntoDiagArg, Level, MultiSpan, Subdiagnostic,
 };
+use rustc_hir as hir;
+use rustc_hir::ExprKind;
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::{self, Ty};
 use rustc_span::edition::{Edition, LATEST_STABLE_EDITION};
@@ -721,6 +724,131 @@ pub(crate) struct TrivialCast<'tcx> {
     pub cast_ty: Ty<'tcx>,
 }
 
+pub(crate) struct BreakNonLoop<'a> {
+    pub span: Span,
+    pub head: Option<Span>,
+    pub kind: &'a str,
+    pub suggestion: String,
+    pub loop_label: Option<Label>,
+    pub break_label: Option<Label>,
+    pub break_expr_kind: &'a ExprKind<'a>,
+    pub break_expr_span: Span,
+}
+
+impl<'a, G: EmissionGuarantee> Diagnostic<'_, G> for BreakNonLoop<'a> {
+    #[track_caller]
+    fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
+        let mut diag = Diag::new(dcx, level, fluent::hir_typeck_break_non_loop);
+        diag.span(self.span);
+        diag.code(E0571);
+        diag.arg("kind", self.kind);
+        diag.span_label(self.span, fluent::hir_typeck_label);
+        if let Some(head) = self.head {
+            diag.span_label(head, fluent::hir_typeck_label2);
+        }
+        diag.span_suggestion(
+            self.span,
+            fluent::hir_typeck_suggestion,
+            self.suggestion,
+            Applicability::MaybeIncorrect,
+        );
+        if let (Some(label), None) = (self.loop_label, self.break_label) {
+            match self.break_expr_kind {
+                ExprKind::Path(hir::QPath::Resolved(
+                    None,
+                    hir::Path { segments: [segment], res: hir::def::Res::Err, .. },
+                )) if label.ident.to_string() == format!("'{}", segment.ident) => {
+                    // This error is redundant, we will have already emitted a
+                    // suggestion to use the label when `segment` wasn't found
+                    // (hence the `Res::Err` check).
+                    diag.downgrade_to_delayed_bug();
+                }
+                _ => {
+                    diag.span_suggestion(
+                        self.break_expr_span,
+                        fluent::hir_typeck_break_expr_suggestion,
+                        label.ident,
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+            }
+        }
+        diag
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_continue_labeled_block, code = E0696)]
+pub(crate) struct ContinueLabeledBlock {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(hir_typeck_block_label)]
+    pub block_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_break_inside_closure, code = E0267)]
+pub(crate) struct BreakInsideClosure<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(hir_typeck_closure_label)]
+    pub closure_span: Span,
+    pub name: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_break_inside_coroutine, code = E0267)]
+pub(crate) struct BreakInsideCoroutine<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    #[label(hir_typeck_coroutine_label)]
+    pub coroutine_span: Span,
+    pub name: &'a str,
+    pub kind: &'a str,
+    pub source: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_outside_loop, code = E0268)]
+pub(crate) struct OutsideLoop<'a> {
+    #[primary_span]
+    #[label]
+    pub spans: Vec<Span>,
+    pub name: &'a str,
+    pub is_break: bool,
+    #[subdiagnostic]
+    pub suggestion: Option<OutsideLoopSuggestion>,
+}
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(hir_typeck_outside_loop_suggestion, applicability = "maybe-incorrect")]
+pub(crate) struct OutsideLoopSuggestion {
+    #[suggestion_part(code = "'block: ")]
+    pub block_span: Span,
+    #[suggestion_part(code = " 'block")]
+    pub break_spans: Vec<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_unlabeled_in_labeled_block, code = E0695)]
+pub(crate) struct UnlabeledInLabeledBlock<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub cf_type: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_unlabeled_cf_in_while_condition, code = E0590)]
+pub(crate) struct UnlabeledCfInWhileCondition<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub cf_type: &'a str,
+}
+
 #[derive(Diagnostic)]
 #[diag(hir_typeck_no_associated_item, code = E0599)]
 pub(crate) struct NoAssociatedItem {
@@ -1035,3 +1163,10 @@ pub(crate) struct NakedFunctionsMustNakedAsm {
     #[label]
     pub span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_abi_custom_call)]
+pub(crate) struct AbiCustomCall {
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index dfc7935d02b..87682d52dbf 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -5,7 +5,7 @@
 //!
 //! See [`rustc_hir_analysis::check`] for more context on type checking in general.
 
-use rustc_abi::{FIRST_VARIANT, FieldIdx};
+use rustc_abi::{ExternAbi, FIRST_VARIANT, FieldIdx};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_data_structures::unord::UnordMap;
@@ -1627,6 +1627,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     Some(method.def_id),
                 );
 
+                // Functions of type `extern "custom" fn(/* ... */)` cannot be called using
+                // `ExprKind::MethodCall`. These functions have a calling convention that is
+                // unknown to rust, hence it cannot generate code for the call. The only way
+                // to execute such a function is via inline assembly.
+                if let ExternAbi::Custom = method.sig.abi {
+                    self.tcx.dcx().emit_err(crate::errors::AbiCustomCall { span: expr.span });
+                }
+
                 method.sig.output()
             }
             Err(error) => {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 8a90e768d70..a43449a8f99 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1436,8 +1436,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// in this case.
     #[instrument(level = "debug", skip(self, sp), ret)]
     pub(crate) fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
-        let ty = self.resolve_vars_with_obligations(ty);
-
         if self.next_trait_solver()
             && let ty::Alias(..) = ty.kind()
         {
@@ -1455,7 +1453,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
         } else {
-            ty
+            self.resolve_vars_with_obligations(ty)
         }
     }
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
index 7f1f3c3c802..e4c62bf027b 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
@@ -120,15 +120,7 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for NestedObligationsForSelfTy<'a, 'tcx> {
     fn visit_goal(&mut self, inspect_goal: &InspectGoal<'_, 'tcx>) {
         // No need to walk into goal subtrees that certainly hold, since they
         // wouldn't then be stalled on an infer var.
-        // FIXME: We also walk into normalizes-to goals since their certainty
-        // is forced to `Certainty::Yes` since they pass down ambiguous subgoals
-        // to their parent.
-        if inspect_goal.result() == Ok(Certainty::Yes)
-            && !matches!(
-                inspect_goal.goal().predicate.kind().skip_binder(),
-                ty::PredicateKind::NormalizesTo(_)
-            )
-        {
+        if inspect_goal.result() == Ok(Certainty::Yes) {
             return;
         }
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index a5c0829b8d9..e979798a402 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -382,7 +382,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> {
         _hir_id: rustc_hir::HirId,
         _hir_ty: Option<&hir::Ty<'_>>,
     ) -> (Vec<Ty<'tcx>>, Ty<'tcx>) {
-        let input_tys = decl.inputs.iter().map(|a| self.lowerer().lower_arg_ty(a, None)).collect();
+        let input_tys = decl.inputs.iter().map(|a| self.lowerer().lower_ty(a)).collect();
 
         let output_ty = match decl.output {
             hir::FnRetTy::Return(output) => self.lowerer().lower_ty(output),
@@ -412,9 +412,10 @@ pub(crate) struct LoweredTy<'tcx> {
 
 impl<'tcx> LoweredTy<'tcx> {
     fn from_raw(fcx: &FnCtxt<'_, 'tcx>, span: Span, raw: Ty<'tcx>) -> LoweredTy<'tcx> {
-        // FIXME(-Znext-solver): We're still figuring out how to best handle
-        // normalization and this doesn't feel too great. We should look at this
-        // code again before stabilizing it.
+        // FIXME(-Znext-solver=no): This is easier than requiring all uses of `LoweredTy`
+        // to call `try_structurally_resolve_type` instead. This seems like a lot of
+        // effort, especially as we're still supporting the old solver. We may revisit
+        // this in the future.
         let normalized = if fcx.next_trait_solver() {
             fcx.try_structurally_resolve_type(span, raw)
         } else {
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 741a616631a..043a687914b 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -28,6 +28,7 @@ mod fallback;
 mod fn_ctxt;
 mod gather_locals;
 mod intrinsicck;
+mod loops;
 mod method;
 mod naked_functions;
 mod op;
@@ -47,7 +48,7 @@ use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_e
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{HirId, HirIdMap, Node};
-use rustc_hir_analysis::check::check_abi;
+use rustc_hir_analysis::check::{check_abi, check_custom_abi};
 use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
 use rustc_infer::traits::{ObligationCauseCode, ObligationInspector, WellFormedLoc};
 use rustc_middle::query::Providers;
@@ -137,7 +138,7 @@ fn typeck_with_inspect<'tcx>(
         // for visit the asm expr of the body.
         let ty = fcx.check_expr(body.value);
         fcx.write_ty(id, ty);
-    } else if let Some(hir::FnSig { header, decl, .. }) = node.fn_sig() {
+    } else if let Some(hir::FnSig { header, decl, span: fn_sig_span }) = node.fn_sig() {
         let fn_sig = if decl.output.is_suggestable_infer_ty().is_some() {
             // In the case that we're recovering `fn() -> W<_>` or some other return
             // type that has an infer in it, lower the type directly so that it'll
@@ -149,6 +150,9 @@ fn typeck_with_inspect<'tcx>(
         };
 
         check_abi(tcx, id, span, fn_sig.abi());
+        check_custom_abi(tcx, def_id, fn_sig.skip_binder(), *fn_sig_span);
+
+        loops::check(tcx, def_id, body);
 
         // Compute the function signature from point of view of inside the fn.
         let mut fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
@@ -189,6 +193,8 @@ fn typeck_with_inspect<'tcx>(
             tcx.type_of(def_id).instantiate_identity()
         };
 
+        loops::check(tcx, def_id, body);
+
         let expected_type = fcx.normalize(body.value.span, expected_type);
 
         let wf_code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(def_id)));
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_hir_typeck/src/loops.rs
index b06f16cc7bd..b06e0704b6f 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_hir_typeck/src/loops.rs
@@ -3,11 +3,11 @@ use std::fmt;
 
 use Context::*;
 use rustc_hir as hir;
-use rustc_hir::def_id::{LocalDefId, LocalModDefId};
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Destination, Node};
 use rustc_middle::hir::nested_filter;
-use rustc_middle::query::Providers;
 use rustc_middle::span_bug;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::hygiene::DesugaringKind;
@@ -73,17 +73,17 @@ struct CheckLoopVisitor<'tcx> {
     block_breaks: BTreeMap<Span, BlockInfo>,
 }
 
-fn check_mod_loops(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
+pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<'tcx>) {
     let mut check =
         CheckLoopVisitor { tcx, cx_stack: vec![Normal], block_breaks: Default::default() };
-    tcx.hir_visit_item_likes_in_module(module_def_id, &mut check);
+    let cx = match tcx.def_kind(def_id) {
+        DefKind::AnonConst => AnonConst,
+        _ => Fn,
+    };
+    check.with_context(cx, |v| v.visit_body(body));
     check.report_outside_loop_error();
 }
 
-pub(crate) fn provide(providers: &mut Providers) {
-    *providers = Providers { check_mod_loops, ..*providers };
-}
-
 impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
     type NestedFilter = nested_filter::OnlyBodies;
 
@@ -91,33 +91,14 @@ impl<'hir> Visitor<'hir> for CheckLoopVisitor<'hir> {
         self.tcx
     }
 
-    fn visit_anon_const(&mut self, c: &'hir hir::AnonConst) {
-        self.with_context(AnonConst, |v| intravisit::walk_anon_const(v, c));
+    fn visit_anon_const(&mut self, _: &'hir hir::AnonConst) {
+        // Typecked on its own.
     }
 
     fn visit_inline_const(&mut self, c: &'hir hir::ConstBlock) {
         self.with_context(ConstBlock, |v| intravisit::walk_inline_const(v, c));
     }
 
-    fn visit_fn(
-        &mut self,
-        fk: hir::intravisit::FnKind<'hir>,
-        fd: &'hir hir::FnDecl<'hir>,
-        b: hir::BodyId,
-        _: Span,
-        id: LocalDefId,
-    ) {
-        self.with_context(Fn, |v| intravisit::walk_fn(v, fk, fd, b, id));
-    }
-
-    fn visit_trait_item(&mut self, trait_item: &'hir hir::TraitItem<'hir>) {
-        self.with_context(Fn, |v| intravisit::walk_trait_item(v, trait_item));
-    }
-
-    fn visit_impl_item(&mut self, impl_item: &'hir hir::ImplItem<'hir>) {
-        self.with_context(Fn, |v| intravisit::walk_impl_item(v, impl_item));
-    }
-
     fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
         match e.kind {
             hir::ExprKind::If(cond, then, else_opt) => {
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 725240b480b..a3fdf200c8e 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -1913,8 +1913,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                         ty::Binder::dummy(trait_ref),
                     );
 
-                    // FIXME(-Znext-solver): We only need this hack to deal with fatal
-                    // overflow in the old solver.
+                    // We only need this hack to deal with fatal overflow in the old solver.
                     if self.infcx.next_trait_solver() || self.infcx.predicate_may_hold(&obligation)
                     {
                         ocx.register_obligation(obligation);
@@ -1955,17 +1954,17 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 }
             }
 
-            // FIXME(-Znext-solver): See the linked issue below.
-            // <https://github.com/rust-lang/trait-system-refactor-initiative/issues/134>
+            // See <https://github.com/rust-lang/trait-system-refactor-initiative/issues/134>.
             //
             // In the new solver, check the well-formedness of the return type.
             // This emulates, in a way, the predicates that fall out of
             // normalizing the return type in the old solver.
             //
-            // We alternatively could check the predicates of the method itself hold,
-            // but we intentionally do not do this in the old solver b/c of cycles,
-            // and doing it in the new solver would be stronger. This should be fixed
-            // in the future, since it likely leads to much better method winnowing.
+            // FIXME(-Znext-solver): We alternatively could check the predicates of
+            // the method itself hold, but we intentionally do not do this in the old
+            // solver b/c of cycles, and doing it in the new solver would be stronger.
+            // This should be fixed in the future, since it likely leads to much better
+            // method winnowing.
             if let Some(xform_ret_ty) = xform_ret_ty
                 && self.infcx.next_trait_solver()
             {
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 2fac13b7201..6cb53bbd745 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -14,7 +14,9 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::codes::*;
-use rustc_errors::{Applicability, Diag, MultiSpan, StashKey, pluralize, struct_span_code_err};
+use rustc_errors::{
+    Applicability, Diag, DiagStyledString, MultiSpan, StashKey, pluralize, struct_span_code_err,
+};
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{self, Visitor};
@@ -1569,7 +1571,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             );
         }
 
-        if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params || suggested_derive {
+        if rcvr_ty.is_numeric() && rcvr_ty.is_fresh()
+            || restrict_type_params
+            || suggested_derive
+            || self.lookup_alternative_tuple_impls(&mut err, &unsatisfied_predicates)
+        {
         } else {
             self.suggest_traits_to_import(
                 &mut err,
@@ -1744,6 +1750,119 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         err.emit()
     }
 
+    /// If the predicate failure is caused by an unmet bound on a tuple, recheck if the bound would
+    /// succeed if all the types on the tuple had no borrows. This is a common problem for libraries
+    /// like Bevy and ORMs, which rely heavily on traits being implemented on tuples.
+    fn lookup_alternative_tuple_impls(
+        &self,
+        err: &mut Diag<'_>,
+        unsatisfied_predicates: &[(
+            ty::Predicate<'tcx>,
+            Option<ty::Predicate<'tcx>>,
+            Option<ObligationCause<'tcx>>,
+        )],
+    ) -> bool {
+        let mut found_tuple = false;
+        for (pred, root, _ob) in unsatisfied_predicates {
+            let mut preds = vec![pred];
+            if let Some(root) = root {
+                // We will look at both the current predicate and the root predicate that caused it
+                // to be needed. If calling something like `<(A, &B)>::default()`, then `pred` is
+                // `&B: Default` and `root` is `(A, &B): Default`, which is the one we are checking
+                // for further down, so we check both.
+                preds.push(root);
+            }
+            for pred in preds {
+                if let Some(clause) = pred.as_clause()
+                    && let Some(clause) = clause.as_trait_clause()
+                    && let ty = clause.self_ty().skip_binder()
+                    && let ty::Tuple(types) = ty.kind()
+                {
+                    let path = clause.skip_binder().trait_ref.print_only_trait_path();
+                    let def_id = clause.def_id();
+                    let ty = Ty::new_tup(
+                        self.tcx,
+                        self.tcx.mk_type_list_from_iter(types.iter().map(|ty| ty.peel_refs())),
+                    );
+                    let args = ty::GenericArgs::for_item(self.tcx, def_id, |param, _| {
+                        if param.index == 0 {
+                            ty.into()
+                        } else {
+                            self.infcx.var_for_def(DUMMY_SP, param)
+                        }
+                    });
+                    if self
+                        .infcx
+                        .type_implements_trait(def_id, args, self.param_env)
+                        .must_apply_modulo_regions()
+                    {
+                        // "`Trait` is implemented for `(A, B)` but not for `(A, &B)`"
+                        let mut msg = DiagStyledString::normal(format!("`{path}` "));
+                        msg.push_highlighted("is");
+                        msg.push_normal(" implemented for `(");
+                        let len = types.len();
+                        for (i, t) in types.iter().enumerate() {
+                            msg.push(
+                                format!("{}", with_forced_trimmed_paths!(t.peel_refs())),
+                                t.peel_refs() != t,
+                            );
+                            if i < len - 1 {
+                                msg.push_normal(", ");
+                            }
+                        }
+                        msg.push_normal(")` but ");
+                        msg.push_highlighted("not");
+                        msg.push_normal(" for `(");
+                        for (i, t) in types.iter().enumerate() {
+                            msg.push(
+                                format!("{}", with_forced_trimmed_paths!(t)),
+                                t.peel_refs() != t,
+                            );
+                            if i < len - 1 {
+                                msg.push_normal(", ");
+                            }
+                        }
+                        msg.push_normal(")`");
+
+                        // Find the span corresponding to the impl that was found to point at it.
+                        if let Some(impl_span) = self
+                            .tcx
+                            .all_impls(def_id)
+                            .filter(|&impl_def_id| {
+                                let header = self.tcx.impl_trait_header(impl_def_id).unwrap();
+                                let trait_ref = header.trait_ref.instantiate(
+                                    self.tcx,
+                                    self.infcx.fresh_args_for_item(DUMMY_SP, impl_def_id),
+                                );
+
+                                let value = ty::fold_regions(self.tcx, ty, |_, _| {
+                                    self.tcx.lifetimes.re_erased
+                                });
+                                // FIXME: Don't bother dealing with non-lifetime binders here...
+                                if value.has_escaping_bound_vars() {
+                                    return false;
+                                }
+                                self.infcx.can_eq(ty::ParamEnv::empty(), trait_ref.self_ty(), value)
+                                    && header.polarity == ty::ImplPolarity::Positive
+                            })
+                            .map(|impl_def_id| self.tcx.def_span(impl_def_id))
+                            .next()
+                        {
+                            err.highlighted_span_note(impl_span, msg.0);
+                        } else {
+                            err.highlighted_note(msg.0);
+                        }
+                        found_tuple = true;
+                    }
+                    // If `pred` was already on the tuple, we don't need to look at the root
+                    // obligation too.
+                    break;
+                }
+            }
+        }
+        found_tuple
+    }
+
     /// If an appropriate error source is not found, check method chain for possible candidates
     fn lookup_segments_chain_for_no_match_method(
         &self,
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index 10827c9fd03..db937b3e83e 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -198,8 +198,11 @@ impl<'tcx> InferCtxt<'tcx> {
             }
 
             if !self.tcx.recursion_limit().value_within_limit(iteration) {
+                // This may actually be reachable. If so, we should convert
+                // this to a proper error/consider whether we should detect
+                // this somewhere else.
                 bug!(
-                    "FIXME(-Znext-solver): Overflowed when processing region obligations: {my_region_obligations:#?}"
+                    "unexpected overflowed when processing region obligations: {my_region_obligations:#?}"
                 );
             }
 
diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs
index 2086483b94a..6f6791804d3 100644
--- a/compiler/rustc_infer/src/infer/type_variable.rs
+++ b/compiler/rustc_infer/src/infer/type_variable.rs
@@ -238,6 +238,9 @@ impl<'tcx> ut::UnifyKey for TyVidEqKey<'tcx> {
     fn tag() -> &'static str {
         "TyVidEqKey"
     }
+    fn order_roots(a: Self, _: &Self::Value, b: Self, _: &Self::Value) -> Option<(Self, Self)> {
+        if a.vid.as_u32() < b.vid.as_u32() { Some((a, b)) } else { Some((b, a)) }
+    }
 }
 
 impl<'tcx> ut::UnifyValue for TypeVariableValue<'tcx> {
diff --git a/compiler/rustc_infer/src/infer/unify_key.rs b/compiler/rustc_infer/src/infer/unify_key.rs
index 3ba8aea1d3a..5e5d0e063a0 100644
--- a/compiler/rustc_infer/src/infer/unify_key.rs
+++ b/compiler/rustc_infer/src/infer/unify_key.rs
@@ -137,6 +137,9 @@ impl<'tcx> UnifyKey for ConstVidKey<'tcx> {
     fn tag() -> &'static str {
         "ConstVidKey"
     }
+    fn order_roots(a: Self, _: &Self::Value, b: Self, _: &Self::Value) -> Option<(Self, Self)> {
+        if a.vid.as_u32() < b.vid.as_u32() { Some((a, b)) } else { Some((b, a)) }
+    }
 }
 
 impl<'tcx> UnifyValue for ConstVariableValue<'tcx> {
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 2643e5c1926..0238d6a3947 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -8,9 +8,9 @@ use std::{env, fs, iter};
 use rustc_ast as ast;
 use rustc_codegen_ssa::traits::CodegenBackend;
 use rustc_data_structures::jobserver::Proxy;
-use rustc_data_structures::parallel;
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::sync::{AppendOnlyIndexVec, FreezeLock, WorkerLocal};
+use rustc_data_structures::{parallel, thousands};
 use rustc_expand::base::{ExtCtxt, LintStoreExpand};
 use rustc_feature::Features;
 use rustc_fs_util::try_canonicalize;
@@ -35,7 +35,8 @@ use rustc_session::parse::feature_err;
 use rustc_session::search_paths::PathKind;
 use rustc_session::{Limit, Session};
 use rustc_span::{
-    DUMMY_SP, ErrorGuaranteed, FileName, SourceFileHash, SourceFileHashAlgorithm, Span, Symbol, sym,
+    DUMMY_SP, ErrorGuaranteed, ExpnKind, FileName, SourceFileHash, SourceFileHashAlgorithm, Span,
+    Symbol, sym,
 };
 use rustc_target::spec::PanicStrategy;
 use rustc_trait_selection::traits;
@@ -205,7 +206,7 @@ fn configure_and_expand(
         // Expand macros now!
         let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate));
 
-        // The rest is error reporting
+        // The rest is error reporting and stats
 
         sess.psess.buffered_lints.with_lock(|buffered_lints: &mut Vec<BufferedEarlyLint>| {
             buffered_lints.append(&mut ecx.buffered_early_lint);
@@ -228,6 +229,10 @@ fn configure_and_expand(
             }
         }
 
+        if ecx.sess.opts.unstable_opts.macro_stats {
+            print_macro_stats(&ecx);
+        }
+
         krate
     });
 
@@ -288,6 +293,76 @@ fn configure_and_expand(
     krate
 }
 
+fn print_macro_stats(ecx: &ExtCtxt<'_>) {
+    use std::fmt::Write;
+
+    // No instability because we immediately sort the produced vector.
+    #[allow(rustc::potential_query_instability)]
+    let mut macro_stats: Vec<_> = ecx
+        .macro_stats
+        .iter()
+        .map(|((name, kind), stat)| {
+            // This gives the desired sort order: sort by bytes, then lines, etc.
+            (stat.bytes, stat.lines, stat.uses, name, *kind)
+        })
+        .collect();
+    macro_stats.sort_unstable();
+    macro_stats.reverse(); // bigger items first
+
+    let prefix = "macro-stats";
+    let name_w = 32;
+    let uses_w = 7;
+    let lines_w = 11;
+    let avg_lines_w = 11;
+    let bytes_w = 11;
+    let avg_bytes_w = 11;
+    let banner_w = name_w + uses_w + lines_w + avg_lines_w + bytes_w + avg_bytes_w;
+
+    // We write all the text into a string and print it with a single
+    // `eprint!`. This is an attempt to minimize interleaved text if multiple
+    // rustc processes are printing macro-stats at the same time (e.g. with
+    // `RUSTFLAGS='-Zmacro-stats' cargo build`). It still doesn't guarantee
+    // non-interleaving, though.
+    let mut s = String::new();
+    _ = writeln!(s, "{prefix} {}", "=".repeat(banner_w));
+    _ = writeln!(s, "{prefix} MACRO EXPANSION STATS: {}", ecx.ecfg.crate_name);
+    _ = writeln!(
+        s,
+        "{prefix} {:<name_w$}{:>uses_w$}{:>lines_w$}{:>avg_lines_w$}{:>bytes_w$}{:>avg_bytes_w$}",
+        "Macro Name", "Uses", "Lines", "Avg Lines", "Bytes", "Avg Bytes",
+    );
+    _ = writeln!(s, "{prefix} {}", "-".repeat(banner_w));
+    // It's helpful to print something when there are no entries, otherwise it
+    // might look like something went wrong.
+    if macro_stats.is_empty() {
+        _ = writeln!(s, "{prefix} (none)");
+    }
+    for (bytes, lines, uses, name, kind) in macro_stats {
+        let mut name = ExpnKind::Macro(kind, *name).descr();
+        let avg_lines = lines as f64 / uses as f64;
+        let avg_bytes = bytes as f64 / uses as f64;
+        if name.len() >= name_w {
+            // If the name is long, print it on a line by itself, then
+            // set the name to empty and print things normally, to show the
+            // stats on the next line.
+            _ = writeln!(s, "{prefix} {:<name_w$}", name);
+            name = String::new();
+        }
+        _ = writeln!(
+            s,
+            "{prefix} {:<name_w$}{:>uses_w$}{:>lines_w$}{:>avg_lines_w$}{:>bytes_w$}{:>avg_bytes_w$}",
+            name,
+            thousands::usize_with_underscores(uses),
+            thousands::isize_with_underscores(lines),
+            thousands::f64p1_with_underscores(avg_lines),
+            thousands::isize_with_underscores(bytes),
+            thousands::f64p1_with_underscores(avg_bytes),
+        );
+    }
+    _ = writeln!(s, "{prefix} {}", "=".repeat(banner_w));
+    eprint!("{s}");
+}
+
 fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) {
     let sess = tcx.sess;
     let (resolver, krate) = &*tcx.resolver_for_lowering().borrow();
@@ -954,7 +1029,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
                 tcx.ensure_ok().exportable_items(LOCAL_CRATE);
                 tcx.ensure_ok().stable_order_of_exportable_impls(LOCAL_CRATE);
                 tcx.par_hir_for_each_module(|module| {
-                    tcx.ensure_ok().check_mod_loops(module);
                     tcx.ensure_ok().check_mod_attrs(module);
                     tcx.ensure_ok().check_mod_unstable_api_usage(module);
                 });
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 558f13a832c..5419d688caa 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -709,6 +709,7 @@ fn test_unstable_options_tracking_hash() {
     untracked!(llvm_time_trace, true);
     untracked!(ls, vec!["all".to_owned()]);
     untracked!(macro_backtrace, true);
+    untracked!(macro_stats, true);
     untracked!(meta_stats, true);
     untracked!(mir_include_spans, MirIncludeSpans::On);
     untracked!(nll_facts, true);
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index fd2e2ba39ac..46ae4146528 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -72,9 +72,6 @@ lint_builtin_const_no_mangle = const items should never be `#[no_mangle]`
 lint_builtin_decl_unsafe_fn = declaration of an `unsafe` function
 lint_builtin_decl_unsafe_method = declaration of an `unsafe` method
 
-lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$reason}. See {$link}
-    .msg_suggestion = {$msg}
-    .default_suggestion = remove this attribute
 lint_builtin_deref_nullptr = dereferencing a null pointer
     .label = this code causes undefined behavior when executed
 
@@ -533,8 +530,6 @@ lint_mismatched_lifetime_syntaxes_suggestion_implicit =
 lint_mismatched_lifetime_syntaxes_suggestion_mixed =
     one option is to remove the lifetime for references and use the anonymous lifetime for paths
 
-lint_missing_fragment_specifier = missing fragment specifier
-
 lint_missing_unsafe_on_extern = extern blocks should be unsafe
     .suggestion = needs `unsafe` before the extern keyword
 
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 69e9f8e1b2c..dedea54f8e0 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -22,7 +22,7 @@ use rustc_ast::visit::{FnCtxt, FnKind};
 use rustc_ast::{self as ast, *};
 use rustc_ast_pretty::pprust::expr_to_string;
 use rustc_errors::{Applicability, LintDiagnostic};
-use rustc_feature::{AttributeGate, BuiltinAttribute, GateIssue, Stability, deprecated_attributes};
+use rustc_feature::GateIssue;
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
@@ -48,8 +48,7 @@ use rustc_trait_selection::traits::{self};
 
 use crate::errors::BuiltinEllipsisInclusiveRangePatterns;
 use crate::lints::{
-    BuiltinAnonymousParams, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink,
-    BuiltinDeprecatedAttrLinkSuggestion, BuiltinDerefNullptr, BuiltinDoubleNegations,
+    BuiltinAnonymousParams, BuiltinConstNoMangle, BuiltinDerefNullptr, BuiltinDoubleNegations,
     BuiltinDoubleNegationsAddParens, BuiltinEllipsisInclusiveRangePatternsLint,
     BuiltinExplicitOutlives, BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote,
     BuiltinIncompleteFeatures, BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures,
@@ -799,53 +798,6 @@ impl EarlyLintPass for AnonymousParameters {
     }
 }
 
-/// Check for use of attributes which have been deprecated.
-#[derive(Clone)]
-pub struct DeprecatedAttr {
-    // This is not free to compute, so we want to keep it around, rather than
-    // compute it for every attribute.
-    depr_attrs: Vec<&'static BuiltinAttribute>,
-}
-
-impl_lint_pass!(DeprecatedAttr => []);
-
-impl Default for DeprecatedAttr {
-    fn default() -> Self {
-        DeprecatedAttr { depr_attrs: deprecated_attributes() }
-    }
-}
-
-impl EarlyLintPass for DeprecatedAttr {
-    fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
-        for BuiltinAttribute { name, gate, .. } in &self.depr_attrs {
-            if attr.ident().map(|ident| ident.name) == Some(*name) {
-                if let &AttributeGate::Gated(
-                    Stability::Deprecated(link, suggestion),
-                    name,
-                    reason,
-                    _,
-                ) = gate
-                {
-                    let suggestion = match suggestion {
-                        Some(msg) => {
-                            BuiltinDeprecatedAttrLinkSuggestion::Msg { suggestion: attr.span, msg }
-                        }
-                        None => {
-                            BuiltinDeprecatedAttrLinkSuggestion::Default { suggestion: attr.span }
-                        }
-                    };
-                    cx.emit_span_lint(
-                        DEPRECATED,
-                        attr.span,
-                        BuiltinDeprecatedAttrLink { name, reason, link, suggestion },
-                    );
-                }
-                return;
-            }
-        }
-    }
-}
-
 fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &[ast::Attribute]) {
     use rustc_ast::token::CommentKind;
 
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 4978f293ab7..12666d383f9 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -136,7 +136,6 @@ impl<'ast, 'ecx, 'tcx, T: EarlyLintPass> ast_visit::Visitor<'ast>
         // the AST struct that they wrap (e.g. an item)
         self.with_lint_attrs(s.id, s.attrs(), |cx| {
             lint_callback!(cx, check_stmt, s);
-            cx.check_id(s.id);
         });
         // The visitor for the AST struct wrapped
         // by the statement (e.g. `Item`) will call
@@ -147,7 +146,6 @@ impl<'ast, 'ecx, 'tcx, T: EarlyLintPass> ast_visit::Visitor<'ast>
 
     fn visit_fn(&mut self, fk: ast_visit::FnKind<'ast>, span: Span, id: ast::NodeId) {
         lint_callback!(self, check_fn, fk, span, id);
-        self.check_id(id);
         ast_visit::walk_fn(self, fk);
     }
 
diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs
index 60c477dd6c7..3b0a36186b6 100644
--- a/compiler/rustc_lint/src/early/diagnostics.rs
+++ b/compiler/rustc_lint/src/early/diagnostics.rs
@@ -432,9 +432,6 @@ pub fn decorate_builtin_lint(
         BuiltinLintDiag::CfgAttrNoAttributes => {
             lints::CfgAttrNoAttributes.decorate_lint(diag);
         }
-        BuiltinLintDiag::MissingFragmentSpecifier => {
-            lints::MissingFragmentSpecifier.decorate_lint(diag);
-        }
         BuiltinLintDiag::MetaVariableStillRepeating(name) => {
             lints::MetaVariableStillRepeating { name }.decorate_lint(diag);
         }
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 72bfeaddbf1..e84cdb581b5 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -174,7 +174,6 @@ early_lint_methods!(
             AnonymousParameters: AnonymousParameters,
             EllipsisInclusiveRangePatterns: EllipsisInclusiveRangePatterns::default(),
             NonCamelCaseTypes: NonCamelCaseTypes,
-            DeprecatedAttr: DeprecatedAttr::default(),
             WhileTrue: WhileTrue,
             NonAsciiIdents: NonAsciiIdents,
             IncompleteInternalFeatures: IncompleteInternalFeatures,
@@ -619,6 +618,11 @@ fn register_builtins(store: &mut LintStore) {
         "converted into hard error, \
          see <https://github.com/rust-lang/rust/issues/116558> for more information",
     );
+    store.register_removed(
+        "missing_fragment_specifier",
+        "converted into hard error, \
+         see <https://github.com/rust-lang/rust/issues/40107> for more information",
+    );
 }
 
 fn register_internals(store: &mut LintStore) {
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 9d3c74a9a2b..3d17dfbc451 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -199,32 +199,6 @@ pub(crate) struct BuiltinAnonymousParams<'a> {
     pub ty_snip: &'a str,
 }
 
-// FIXME(davidtwco) translatable deprecated attr
-#[derive(LintDiagnostic)]
-#[diag(lint_builtin_deprecated_attr_link)]
-pub(crate) struct BuiltinDeprecatedAttrLink<'a> {
-    pub name: Symbol,
-    pub reason: &'a str,
-    pub link: &'a str,
-    #[subdiagnostic]
-    pub suggestion: BuiltinDeprecatedAttrLinkSuggestion<'a>,
-}
-
-#[derive(Subdiagnostic)]
-pub(crate) enum BuiltinDeprecatedAttrLinkSuggestion<'a> {
-    #[suggestion(lint_msg_suggestion, code = "", applicability = "machine-applicable")]
-    Msg {
-        #[primary_span]
-        suggestion: Span,
-        msg: &'a str,
-    },
-    #[suggestion(lint_default_suggestion, code = "", applicability = "machine-applicable")]
-    Default {
-        #[primary_span]
-        suggestion: Span,
-    },
-}
-
 #[derive(LintDiagnostic)]
 #[diag(lint_builtin_unused_doc_comment)]
 pub(crate) struct BuiltinUnusedDocComment<'a> {
@@ -2617,10 +2591,6 @@ pub(crate) struct DuplicateMacroAttribute;
 pub(crate) struct CfgAttrNoAttributes;
 
 #[derive(LintDiagnostic)]
-#[diag(lint_missing_fragment_specifier)]
-pub(crate) struct MissingFragmentSpecifier;
-
-#[derive(LintDiagnostic)]
 #[diag(lint_metavariable_still_repeating)]
 pub(crate) struct MetaVariableStillRepeating {
     pub name: MacroRulesNormalizedIdent,
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 31c18074466..1b60466a589 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -164,7 +164,7 @@ impl NonCamelCaseTypes {
 impl EarlyLintPass for NonCamelCaseTypes {
     fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
         let has_repr_c = matches!(
-            AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, true),
+            AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, it.id),
             Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(r, _)| r == &ReprAttr::ReprC)
         );
 
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index fec23354c91..aaba0c14b1c 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -196,7 +196,8 @@ declare_lint! {
     /// same address after being merged together.
     UNPREDICTABLE_FUNCTION_POINTER_COMPARISONS,
     Warn,
-    "detects unpredictable function pointer comparisons"
+    "detects unpredictable function pointer comparisons",
+    report_in_external_macro
 }
 
 #[derive(Copy, Clone, Default)]
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 777118e69fb..295dd82fead 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -65,7 +65,6 @@ declare_lint_pass! {
         MACRO_USE_EXTERN_CRATE,
         META_VARIABLE_MISUSE,
         MISSING_ABI,
-        MISSING_FRAGMENT_SPECIFIER,
         MISSING_UNSAFE_ON_EXTERN,
         MUST_NOT_SUSPEND,
         NAMED_ARGUMENTS_USED_POSITIONALLY,
@@ -1418,51 +1417,6 @@ declare_lint! {
 }
 
 declare_lint! {
-    /// The `missing_fragment_specifier` lint is issued when an unused pattern in a
-    /// `macro_rules!` macro definition has a meta-variable (e.g. `$e`) that is not
-    /// followed by a fragment specifier (e.g. `:expr`).
-    ///
-    /// This warning can always be fixed by removing the unused pattern in the
-    /// `macro_rules!` macro definition.
-    ///
-    /// ### Example
-    ///
-    /// ```rust,compile_fail,edition2021
-    /// macro_rules! foo {
-    ///    () => {};
-    ///    ($name) => { };
-    /// }
-    ///
-    /// fn main() {
-    ///    foo!();
-    /// }
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// To fix this, remove the unused pattern from the `macro_rules!` macro definition:
-    ///
-    /// ```rust
-    /// macro_rules! foo {
-    ///     () => {};
-    /// }
-    /// fn main() {
-    ///     foo!();
-    /// }
-    /// ```
-    pub MISSING_FRAGMENT_SPECIFIER,
-    Deny,
-    "detects missing fragment specifiers in unused `macro_rules!` patterns",
-    @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::FutureReleaseError,
-        reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>",
-        report_in_deps: true,
-    };
-}
-
-declare_lint! {
     /// The `late_bound_lifetime_arguments` lint detects generic lifetime
     /// arguments in path segments with late bound lifetime parameters.
     ///
@@ -3664,7 +3618,7 @@ declare_lint! {
     "use of unsupported calling convention",
     @future_incompatible = FutureIncompatibleInfo {
         reason: FutureIncompatibilityReason::FutureReleaseError,
-        report_in_deps: true,
+        report_in_deps: false,
         reference: "issue #137018 <https://github.com/rust-lang/rust/issues/137018>",
     };
 }
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 1d9b7a7fcb9..cd402c9234f 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -778,7 +778,6 @@ pub enum BuiltinLintDiag {
     UnnameableTestItems,
     DuplicateMacroAttribute,
     CfgAttrNoAttributes,
-    MissingFragmentSpecifier,
     MetaVariableStillRepeating(MacroRulesNormalizedIdent),
     MetaVariableWrongOperator,
     DuplicateMatcherBinding,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 1dae858b7ef..1953eef8170 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1649,34 +1649,7 @@ impl<'a> CrateMetadataRef<'a> {
                         old_name
                     && let Ok(rest) = virtual_name.strip_prefix(virtual_dir)
                 {
-                    // The std library crates are in
-                    // `$sysroot/lib/rustlib/src/rust/library`, whereas other crates
-                    // may be in `$sysroot/lib/rustlib/src/rust/` directly. So we
-                    // detect crates from the std libs and handle them specially.
-                    const STD_LIBS: &[&str] = &[
-                        "core",
-                        "alloc",
-                        "std",
-                        "test",
-                        "term",
-                        "unwind",
-                        "proc_macro",
-                        "panic_abort",
-                        "panic_unwind",
-                        "profiler_builtins",
-                        "rtstartup",
-                        "rustc-std-workspace-core",
-                        "rustc-std-workspace-alloc",
-                        "rustc-std-workspace-std",
-                        "backtrace",
-                    ];
-                    let is_std_lib = STD_LIBS.iter().any(|l| rest.starts_with(l));
-
-                    let new_path = if is_std_lib {
-                        real_dir.join("library").join(rest)
-                    } else {
-                        real_dir.join(rest)
-                    };
+                    let new_path = real_dir.join(rest);
 
                     debug!(
                         "try_to_translate_virtual_to_real: `{}` -> `{}`",
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 3ab989d2d3b..00bd32eb0eb 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -10,7 +10,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::memmap::{Mmap, MmapMut};
 use rustc_data_structures::sync::{join, par_for_each_in};
 use rustc_data_structures::temp_dir::MaybeTempDir;
-use rustc_data_structures::thousands::format_with_underscores;
+use rustc_data_structures::thousands::usize_with_underscores;
 use rustc_feature::Features;
 use rustc_hir as hir;
 use rustc_hir::def_id::{CRATE_DEF_ID, CRATE_DEF_INDEX, LOCAL_CRATE, LocalDefId, LocalDefIdSet};
@@ -789,7 +789,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                     "{} {:<23}{:>10} ({:4.1}%)",
                     prefix,
                     label,
-                    format_with_underscores(size),
+                    usize_with_underscores(size),
                     perc(size)
                 );
             }
@@ -798,7 +798,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 "{} {:<23}{:>10} (of which {:.1}% are zero bytes)",
                 prefix,
                 "Total",
-                format_with_underscores(total_bytes),
+                usize_with_underscores(total_bytes),
                 perc(zero_bytes)
             );
             eprintln!("{prefix}");
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index d1f5caaafb2..cb4760c18de 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -12,6 +12,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::{DynSend, DynSync, try_par_for_each_in};
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
+use rustc_hir::lints::DelayedLint;
 use rustc_hir::*;
 use rustc_macros::{Decodable, Encodable, HashStable};
 use rustc_span::{ErrorGuaranteed, ExpnId, Span};
@@ -161,8 +162,9 @@ impl<'tcx> TyCtxt<'tcx> {
         node: OwnerNode<'_>,
         bodies: &SortedMap<ItemLocalId, &Body<'_>>,
         attrs: &SortedMap<ItemLocalId, &[Attribute]>,
+        delayed_lints: &[DelayedLint],
         define_opaque: Option<&[(Span, LocalDefId)]>,
-    ) -> (Option<Fingerprint>, Option<Fingerprint>) {
+    ) -> (Option<Fingerprint>, Option<Fingerprint>, Option<Fingerprint>) {
         if self.needs_crate_hash() {
             self.with_stable_hashing_context(|mut hcx| {
                 let mut stable_hasher = StableHasher::new();
@@ -178,10 +180,16 @@ impl<'tcx> TyCtxt<'tcx> {
                 define_opaque.hash_stable(&mut hcx, &mut stable_hasher);
 
                 let h2 = stable_hasher.finish();
-                (Some(h1), Some(h2))
+
+                // hash lints emitted during ast lowering
+                let mut stable_hasher = StableHasher::new();
+                delayed_lints.hash_stable(&mut hcx, &mut stable_hasher);
+                let h3 = stable_hasher.finish();
+
+                (Some(h1), Some(h2), Some(h3))
             })
         } else {
-            (None, None)
+            (None, None, None)
         }
     }
 }
@@ -214,6 +222,8 @@ pub fn provide(providers: &mut Providers) {
     providers.hir_attr_map = |tcx, id| {
         tcx.hir_crate(()).owners[id.def_id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs)
     };
+    providers.opt_ast_lowering_delayed_lints =
+        |tcx, id| tcx.hir_crate(()).owners[id.def_id].as_owner().map(|o| &o.delayed_lints);
     providers.def_span = |tcx, def_id| tcx.hir_span(tcx.local_def_id_to_hir_id(def_id));
     providers.def_ident_span = |tcx, def_id| {
         let hir_id = tcx.local_def_id_to_hir_id(def_id);
diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs
index 4587dcaddc4..6ca1e620704 100644
--- a/compiler/rustc_middle/src/middle/mod.rs
+++ b/compiler/rustc_middle/src/middle/mod.rs
@@ -12,7 +12,7 @@ pub mod lib_features {
     #[derive(HashStable, TyEncodable, TyDecodable)]
     pub enum FeatureStability {
         AcceptedSince(Symbol),
-        Unstable,
+        Unstable { old_name: Option<Symbol> },
     }
 
     #[derive(HashStable, Debug, Default)]
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 454ab8c107f..ab6a65ed526 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -411,7 +411,7 @@ impl<'tcx> TyCtxt<'tcx> {
 
         match stability {
             Some(Stability {
-                level: attrs::StabilityLevel::Unstable { reason, issue, is_soft, implied_by },
+                level: attrs::StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. },
                 feature,
                 ..
             }) => {
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_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index 6035056baaf..7c998761a9d 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -389,6 +389,7 @@ tcx_lifetime! {
     rustc_middle::ty::layout::FnAbiError,
     rustc_middle::ty::layout::LayoutError,
     rustc_middle::ty::ParamEnv,
+    rustc_middle::ty::TypingEnv,
     rustc_middle::ty::Predicate,
     rustc_middle::ty::SymbolName,
     rustc_middle::ty::TraitRef,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index d03f01bf863..15e8c1ef3cc 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -221,6 +221,14 @@ rustc_queries! {
         feedable
     }
 
+    /// Gives access to lints emitted during ast lowering.
+    ///
+    /// This can be conveniently accessed by `tcx.hir_*` methods.
+    /// Avoid calling this query directly.
+    query opt_ast_lowering_delayed_lints(key: hir::OwnerId) -> Option<&'tcx hir::lints::DelayedLints> {
+        desc { |tcx| "getting AST lowering delayed lints in `{}`", tcx.def_path_str(key) }
+    }
+
     /// Returns the *default* of the const pararameter given by `DefId`.
     ///
     /// E.g., given `struct Ty<const N: usize = 3>;` this returns `3` for `N`.
@@ -1115,11 +1123,6 @@ rustc_queries! {
         desc { |tcx| "checking for unstable API usage in {}", describe_as_module(key, tcx) }
     }
 
-    /// Checks the loops in the module.
-    query check_mod_loops(key: LocalModDefId) {
-        desc { |tcx| "checking loops in {}", describe_as_module(key, tcx) }
-    }
-
     query check_mod_privacy(key: LocalModDefId) {
         desc { |tcx| "checking privacy in {}", describe_as_module(key.to_local_def_id(), tcx) }
     }
@@ -1571,7 +1574,7 @@ rustc_queries! {
     /// Like `param_env`, but returns the `ParamEnv` after all opaque types have been
     /// replaced with their hidden type. This is used in the old trait solver
     /// when in `PostAnalysis` mode and should not be called directly.
-    query param_env_normalized_for_post_analysis(def_id: DefId) -> ty::ParamEnv<'tcx> {
+    query typing_env_normalized_for_post_analysis(def_id: DefId) -> ty::TypingEnv<'tcx> {
         desc { |tcx| "computing revealed normalized predicates of `{}`", tcx.def_path_str(def_id) }
     }
 
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 0b1e9852d2a..6a47000fc85 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -30,7 +30,7 @@ use rustc_data_structures::sync::{
     self, DynSend, DynSync, FreezeReadGuard, Lock, RwLock, WorkerLocal,
 };
 use rustc_errors::{
-    Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, MultiSpan,
+    Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, LintDiagnostic, LintEmitter, MultiSpan,
 };
 use rustc_hir::def::{CtorKind, DefKind};
 use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId};
@@ -86,6 +86,10 @@ use crate::ty::{
 
 #[allow(rustc::usage_of_ty_tykind)]
 impl<'tcx> Interner for TyCtxt<'tcx> {
+    fn next_trait_solver_globally(self) -> bool {
+        self.next_trait_solver_globally()
+    }
+
     type DefId = DefId;
     type LocalDefId = LocalDefId;
     type Span = Span;
@@ -179,6 +183,17 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         f(&mut *self.new_solver_evaluation_cache.lock())
     }
 
+    fn canonical_param_env_cache_get_or_insert<R>(
+        self,
+        param_env: ty::ParamEnv<'tcx>,
+        f: impl FnOnce() -> ty::CanonicalParamEnvCacheEntry<Self>,
+        from_entry: impl FnOnce(&ty::CanonicalParamEnvCacheEntry<Self>) -> R,
+    ) -> R {
+        let mut cache = self.new_solver_canonical_param_env_cache.lock();
+        let entry = cache.entry(param_env).or_insert_with(f);
+        from_entry(entry)
+    }
+
     fn evaluation_is_concurrent(&self) -> bool {
         self.sess.threads() > 1
     }
@@ -1335,8 +1350,8 @@ impl<'tcx> TyCtxtFeed<'tcx, LocalDefId> {
         let bodies = Default::default();
         let attrs = hir::AttributeMap::EMPTY;
 
-        let (opt_hash_including_bodies, _) =
-            self.tcx.hash_owner_nodes(node, &bodies, &attrs.map, attrs.define_opaque);
+        let (opt_hash_including_bodies, _, _) =
+            self.tcx.hash_owner_nodes(node, &bodies, &attrs.map, &[], attrs.define_opaque);
         let node = node.into();
         self.opt_hir_owner_nodes(Some(self.tcx.arena.alloc(hir::OwnerNodes {
             opt_hash_including_bodies,
@@ -1374,6 +1389,18 @@ pub struct TyCtxt<'tcx> {
     gcx: &'tcx GlobalCtxt<'tcx>,
 }
 
+impl<'tcx> LintEmitter for TyCtxt<'tcx> {
+    fn emit_node_span_lint(
+        self,
+        lint: &'static Lint,
+        hir_id: HirId,
+        span: impl Into<MultiSpan>,
+        decorator: impl for<'a> LintDiagnostic<'a, ()>,
+    ) {
+        self.emit_node_span_lint(lint, hir_id, span, decorator);
+    }
+}
+
 // Explicitly implement `DynSync` and `DynSend` for `TyCtxt` to short circuit trait resolution. Its
 // field are asserted to implement these traits below, so this is trivially safe, and it greatly
 // speeds-up compilation of this crate and its dependents.
@@ -1444,6 +1471,8 @@ pub struct GlobalCtxt<'tcx> {
 
     /// Caches the results of goal evaluation in the new solver.
     pub new_solver_evaluation_cache: Lock<search_graph::GlobalCache<TyCtxt<'tcx>>>,
+    pub new_solver_canonical_param_env_cache:
+        Lock<FxHashMap<ty::ParamEnv<'tcx>, ty::CanonicalParamEnvCacheEntry<TyCtxt<'tcx>>>>,
 
     pub canonical_param_env_cache: CanonicalParamEnvCache<'tcx>,
 
@@ -1692,6 +1721,7 @@ impl<'tcx> TyCtxt<'tcx> {
             selection_cache: Default::default(),
             evaluation_cache: Default::default(),
             new_solver_evaluation_cache: Default::default(),
+            new_solver_canonical_param_env_cache: Default::default(),
             canonical_param_env_cache: Default::default(),
             data_layout,
             alloc_map: interpret::AllocMap::new(),
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index c2ae6b06192..9bce2845680 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1266,6 +1266,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi)
         | RiscvInterruptS
         | CCmseNonSecureCall
         | CCmseNonSecureEntry
+        | Custom
         | Unadjusted => false,
         Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind,
     }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index af31f7ed33b..dc3f2844e5a 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1116,10 +1116,7 @@ impl<'tcx> TypingEnv<'tcx> {
     }
 
     pub fn post_analysis(tcx: TyCtxt<'tcx>, def_id: impl IntoQueryParam<DefId>) -> TypingEnv<'tcx> {
-        TypingEnv {
-            typing_mode: TypingMode::PostAnalysis,
-            param_env: tcx.param_env_normalized_for_post_analysis(def_id),
-        }
+        tcx.typing_env_normalized_for_post_analysis(def_id)
     }
 
     /// Modify the `typing_mode` to `PostAnalysis` and eagerly reveal all
@@ -1133,7 +1130,7 @@ impl<'tcx> TypingEnv<'tcx> {
         // No need to reveal opaques with the new solver enabled,
         // since we have lazy norm.
         let param_env = if tcx.next_trait_solver_globally() {
-            ParamEnv::new(param_env.caller_bounds())
+            param_env
         } else {
             ParamEnv::new(tcx.reveal_opaque_types_in_bounds(param_env.caller_bounds()))
         };
diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
index c7feb9e949b..da88e5c698b 100644
--- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
+++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
@@ -128,28 +128,20 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch {
 
             let mut patch = MirPatch::new(body);
 
-            let (second_discriminant_temp, second_operand) = if opt_data.need_hoist_discriminant {
+            let second_operand = if opt_data.need_hoist_discriminant {
                 // create temp to store second discriminant in, `_s` in example above
                 let second_discriminant_temp =
                     patch.new_temp(opt_data.child_ty, opt_data.child_source.span);
 
-                patch.add_statement(
-                    parent_end,
-                    StatementKind::StorageLive(second_discriminant_temp),
-                );
-
                 // create assignment of discriminant
                 patch.add_assign(
                     parent_end,
                     Place::from(second_discriminant_temp),
                     Rvalue::Discriminant(opt_data.child_place),
                 );
-                (
-                    Some(second_discriminant_temp),
-                    Operand::Move(Place::from(second_discriminant_temp)),
-                )
+                Operand::Move(Place::from(second_discriminant_temp))
             } else {
-                (None, Operand::Copy(opt_data.child_place))
+                Operand::Copy(opt_data.child_place)
             };
 
             // create temp to store inequality comparison between the two discriminants, `_t` in
@@ -157,7 +149,6 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch {
             let nequal = BinOp::Ne;
             let comp_res_type = nequal.ty(tcx, parent_ty, opt_data.child_ty);
             let comp_temp = patch.new_temp(comp_res_type, opt_data.child_source.span);
-            patch.add_statement(parent_end, StatementKind::StorageLive(comp_temp));
 
             // create inequality comparison
             let comp_rvalue =
@@ -200,23 +191,6 @@ impl<'tcx> crate::MirPass<'tcx> for EarlyOtherwiseBranch {
                 TerminatorKind::if_(Operand::Move(Place::from(comp_temp)), true_case, false_case),
             );
 
-            if let Some(second_discriminant_temp) = second_discriminant_temp {
-                // generate StorageDead for the second_discriminant_temp not in use anymore
-                patch.add_statement(
-                    parent_end,
-                    StatementKind::StorageDead(second_discriminant_temp),
-                );
-            }
-
-            // Generate a StorageDead for comp_temp in each of the targets, since we moved it into
-            // the switch
-            for bb in [false_case, true_case].iter() {
-                patch.add_statement(
-                    Location { block: *bb, statement_index: 0 },
-                    StatementKind::StorageDead(comp_temp),
-                );
-            }
-
             patch.apply(body);
         }
 
diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs
index 292278800f8..a944960ce4a 100644
--- a/compiler/rustc_mir_transform/src/inline/cycle.rs
+++ b/compiler/rustc_mir_transform/src/inline/cycle.rs
@@ -138,7 +138,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
         }
         false
     }
-    // FIXME(-Znext-solver): Remove this hack when trait solver overflow can return an error.
+    // FIXME(-Znext-solver=no): Remove this hack when trait solver overflow can return an error.
     // In code like that pointed out in #128887, the type complexity we ask the solver to deal with
     // grows as we recurse into the call graph. If we use the same recursion limit here and in the
     // solver, the solver hits the limit first and emits a fatal error. But if we use a reduced
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index 52f4c39c09b..fa29ab985b7 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -150,12 +150,12 @@ impl<'tcx> crate::MirPass<'tcx> for LowerIntrinsics {
                         });
                         terminator.kind = TerminatorKind::Goto { target };
                     }
-                    sym::size_of | sym::min_align_of => {
+                    sym::size_of | sym::align_of => {
                         let target = target.unwrap();
                         let tp_ty = generic_args.type_at(0);
                         let null_op = match intrinsic.name {
                             sym::size_of => NullOp::SizeOf,
-                            sym::min_align_of => NullOp::AlignOf,
+                            sym::align_of => NullOp::AlignOf,
                             _ => bug!("unexpected intrinsic"),
                         };
                         block.statements.push(Statement {
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_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index a87ae5284b1..cea77533178 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -4,8 +4,9 @@ use rustc_type_ir::data_structures::{HashMap, ensure_sufficient_stack};
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::solve::{Goal, QueryInput};
 use rustc_type_ir::{
-    self as ty, Canonical, CanonicalTyVarKind, CanonicalVarKind, Flags, InferCtxtLike, Interner,
-    TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
+    self as ty, Canonical, CanonicalParamEnvCacheEntry, CanonicalTyVarKind, CanonicalVarKind,
+    Flags, InferCtxtLike, Interner, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable,
+    TypeVisitableExt,
 };
 
 use crate::delegate::SolverDelegate;
@@ -100,6 +101,76 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
         Canonical { max_universe, variables, value }
     }
 
+    fn canonicalize_param_env(
+        delegate: &'a D,
+        variables: &'a mut Vec<I::GenericArg>,
+        param_env: I::ParamEnv,
+    ) -> (I::ParamEnv, HashMap<I::GenericArg, usize>, Vec<CanonicalVarKind<I>>) {
+        if !param_env.has_type_flags(NEEDS_CANONICAL) {
+            return (param_env, Default::default(), Vec::new());
+        }
+
+        // Check whether we can use the global cache for this param_env. As we only use
+        // the `param_env` itself as the cache key, considering any additional information
+        // durnig its canonicalization would be incorrect. We always canonicalize region
+        // inference variables in a separate universe, so these are fine. However, we do
+        // track the universe of type and const inference variables so these must not be
+        // globally cached. We don't rely on any additional information when canonicalizing
+        // placeholders.
+        if !param_env.has_non_region_infer() {
+            delegate.cx().canonical_param_env_cache_get_or_insert(
+                param_env,
+                || {
+                    let mut variables = Vec::new();
+                    let mut env_canonicalizer = Canonicalizer {
+                        delegate,
+                        canonicalize_mode: CanonicalizeMode::Input { keep_static: true },
+
+                        variables: &mut variables,
+                        variable_lookup_table: Default::default(),
+                        var_kinds: Vec::new(),
+                        binder_index: ty::INNERMOST,
+
+                        cache: Default::default(),
+                    };
+                    let param_env = param_env.fold_with(&mut env_canonicalizer);
+                    debug_assert_eq!(env_canonicalizer.binder_index, ty::INNERMOST);
+                    CanonicalParamEnvCacheEntry {
+                        param_env,
+                        variable_lookup_table: env_canonicalizer.variable_lookup_table,
+                        var_kinds: env_canonicalizer.var_kinds,
+                        variables,
+                    }
+                },
+                |&CanonicalParamEnvCacheEntry {
+                     param_env,
+                     variables: ref cache_variables,
+                     ref variable_lookup_table,
+                     ref var_kinds,
+                 }| {
+                    debug_assert!(variables.is_empty());
+                    variables.extend(cache_variables.iter().copied());
+                    (param_env, variable_lookup_table.clone(), var_kinds.clone())
+                },
+            )
+        } else {
+            let mut env_canonicalizer = Canonicalizer {
+                delegate,
+                canonicalize_mode: CanonicalizeMode::Input { keep_static: true },
+
+                variables,
+                variable_lookup_table: Default::default(),
+                var_kinds: Vec::new(),
+                binder_index: ty::INNERMOST,
+
+                cache: Default::default(),
+            };
+            let param_env = param_env.fold_with(&mut env_canonicalizer);
+            debug_assert_eq!(env_canonicalizer.binder_index, ty::INNERMOST);
+            (param_env, env_canonicalizer.variable_lookup_table, env_canonicalizer.var_kinds)
+        }
+    }
+
     /// When canonicalizing query inputs, we keep `'static` in the `param_env`
     /// but erase it everywhere else. We generally don't want to depend on region
     /// identity, so while it should not matter whether `'static` is kept in the
@@ -114,37 +185,17 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> {
         input: QueryInput<I, P>,
     ) -> ty::Canonical<I, QueryInput<I, P>> {
         // First canonicalize the `param_env` while keeping `'static`
-        let mut env_canonicalizer = Canonicalizer {
-            delegate,
-            canonicalize_mode: CanonicalizeMode::Input { keep_static: true },
-
-            variables,
-            variable_lookup_table: Default::default(),
-            var_kinds: Vec::new(),
-            binder_index: ty::INNERMOST,
-
-            cache: Default::default(),
-        };
-
-        let param_env = input.goal.param_env;
-        let param_env = if param_env.has_type_flags(NEEDS_CANONICAL) {
-            param_env.fold_with(&mut env_canonicalizer)
-        } else {
-            param_env
-        };
-
-        debug_assert_eq!(env_canonicalizer.binder_index, ty::INNERMOST);
+        let (param_env, variable_lookup_table, var_kinds) =
+            Canonicalizer::canonicalize_param_env(delegate, variables, input.goal.param_env);
         // Then canonicalize the rest of the input without keeping `'static`
         // while *mostly* reusing the canonicalizer from above.
         let mut rest_canonicalizer = Canonicalizer {
             delegate,
             canonicalize_mode: CanonicalizeMode::Input { keep_static: false },
 
-            variables: env_canonicalizer.variables,
-            // We're able to reuse the `variable_lookup_table` as whether or not
-            // it already contains an entry for `'static` does not matter.
-            variable_lookup_table: env_canonicalizer.variable_lookup_table,
-            var_kinds: env_canonicalizer.var_kinds,
+            variables,
+            variable_lookup_table,
+            var_kinds,
             binder_index: ty::INNERMOST,
 
             // We do not reuse the cache as it may contain entries whose canonicalized
diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs
index a7a984181d7..e4e0aba7b50 100644
--- a/compiler/rustc_next_trait_solver/src/solve/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs
@@ -237,8 +237,8 @@ where
             return None;
         }
 
-        // FIXME(-Znext-solver): We should instead try to find a `Certainty::Yes` response with
-        // a subset of the constraints that all the other responses have.
+        // FIXME(-Znext-solver): Add support to merge region constraints in
+        // responses to deal with trait-system-refactor-initiative#27.
         let one = responses[0];
         if responses[1..].iter().all(|&resp| resp == one) {
             return Some(one);
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs
index 2640238f5a9..26443c54e18 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs
@@ -41,6 +41,9 @@ where
         // and we tag the impl bounds with `GoalSource::ImplWhereBound`?
         // Right now this includes both the impl and the assoc item where bounds,
         // and I don't think the assoc item where-bounds are allowed to be coinductive.
+        //
+        // Projecting to the IAT also "steps out the impl contructor", so we would have
+        // to be very careful when changing the impl where-clauses to be productive.
         self.add_goals(
             GoalSource::Misc,
             cx.predicates_of(inherent.def_id)
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 7c4e1dc2c12..110c67a8e21 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -235,7 +235,11 @@ where
                 .predicates_of(goal.predicate.def_id())
                 .iter_instantiated(cx, goal.predicate.trait_ref.args)
                 .map(|p| goal.with(cx, p));
-            // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
+            // While you could think of trait aliases to have a single builtin impl
+            // which uses its implied trait bounds as where-clauses, using
+            // `GoalSource::ImplWhereClause` here would be incorrect, as we also
+            // impl them, which means we're "stepping out of the impl constructor"
+            // again. To handle this, we treat these cycles as ambiguous for now.
             ecx.add_goals(GoalSource::Misc, nested_obligations);
             ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
         })
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index a298c4d4dec..93489aa8ee9 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1520,22 +1520,20 @@ impl<'a> Parser<'a> {
                 Ok(this.mk_expr(this.prev_token.span, ExprKind::Underscore))
             } else if this.token_uninterpolated_span().at_least_rust_2018() {
                 // `Span::at_least_rust_2018()` is somewhat expensive; don't get it repeatedly.
+                let at_async = this.check_keyword(exp!(Async));
+                // check for `gen {}` and `gen move {}`
+                // or `async gen {}` and `async gen move {}`
+                // FIXME: (async) gen closures aren't yet parsed.
+                // FIXME(gen_blocks): Parse `gen async` and suggest swap
                 if this.token_uninterpolated_span().at_least_rust_2024()
-                    // check for `gen {}` and `gen move {}`
-                    // or `async gen {}` and `async gen move {}`
-                    && (this.is_gen_block(kw::Gen, 0)
-                        || (this.check_keyword(exp!(Async)) && this.is_gen_block(kw::Gen, 1)))
+                    && this.is_gen_block(kw::Gen, at_async as usize)
                 {
-                    // FIXME: (async) gen closures aren't yet parsed.
                     this.parse_gen_block()
-                } else if this.check_keyword(exp!(Async)) {
-                    // FIXME(gen_blocks): Parse `gen async` and suggest swap
-                    if this.is_gen_block(kw::Async, 0) {
-                        // Check for `async {` and `async move {`,
-                        this.parse_gen_block()
-                    } else {
-                        this.parse_expr_closure()
-                    }
+                // Check for `async {` and `async move {`,
+                } else if this.is_gen_block(kw::Async, 0) {
+                    this.parse_gen_block()
+                } else if at_async {
+                    this.parse_expr_closure()
                 } else if this.eat_keyword_noexpect(kw::Await) {
                     this.recover_incorrect_await_syntax(lo)
                 } else {
@@ -2407,6 +2405,14 @@ impl<'a> Parser<'a> {
             None
         };
 
+        if let ClosureBinder::NotPresent = binder
+            && coroutine_kind.is_some()
+        {
+            // coroutine closures and generators can have the same qualifiers, so we might end up
+            // in here if there is a missing `|` but also no `{`. Adjust the expectations in that case.
+            self.expected_token_types.insert(TokenType::OpenBrace);
+        }
+
         let capture_clause = self.parse_capture_clause()?;
         let (fn_decl, fn_arg_span) = self.parse_fn_block_decl()?;
         let decl_hi = self.prev_token.span;
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 378cbb84637..555ab3cdb2b 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -180,9 +180,14 @@ pub fn check_attribute_safety(
             let diag_span = attr_item.span();
 
             // Attributes can be safe in earlier editions, and become unsafe in later ones.
+            //
+            // Use the span of the attribute's name to determine the edition: the span of the
+            // attribute as a whole may be inaccurate if it was emitted by a macro.
+            //
+            // See https://github.com/rust-lang/rust/issues/142182.
             let emit_error = match unsafe_since {
                 None => true,
-                Some(unsafe_since) => attr.span.edition() >= unsafe_since,
+                Some(unsafe_since) => path_span.edition() >= unsafe_since,
             };
 
             if emit_error {
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 9dd064aca66..42bd0f5d847 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -29,58 +29,45 @@ pub enum ParseMode {
     Format,
     /// An inline assembly template string for `asm!`.
     InlineAsm,
+    /// A format string for use in diagnostic attributes.
+    ///
+    /// Similar to `format_args!`, however only named ("captured") arguments
+    /// are allowed, and no format modifiers are permitted.
+    Diagnostic,
 }
 
 /// A piece is a portion of the format string which represents the next part
 /// to emit. These are emitted as a stream by the `Parser` class.
 #[derive(Clone, Debug, PartialEq)]
-pub enum Piece<'a> {
+pub enum Piece<'input> {
     /// A literal string which should directly be emitted
-    Lit(&'a str),
+    Lit(&'input str),
     /// This describes that formatting should process the next argument (as
     /// specified inside) for emission.
-    NextArgument(Box<Argument<'a>>),
+    NextArgument(Box<Argument<'input>>),
 }
 
 /// Representation of an argument specification.
 #[derive(Clone, Debug, PartialEq)]
-pub struct Argument<'a> {
+pub struct Argument<'input> {
     /// Where to find this argument
-    pub position: Position<'a>,
+    pub position: Position<'input>,
     /// The span of the position indicator. Includes any whitespace in implicit
     /// positions (`{  }`).
     pub position_span: Range<usize>,
     /// How to format the argument
-    pub format: FormatSpec<'a>,
+    pub format: FormatSpec<'input>,
 }
 
-impl<'a> Argument<'a> {
+impl<'input> Argument<'input> {
     pub fn is_identifier(&self) -> bool {
-        matches!(self.position, Position::ArgumentNamed(_))
-            && matches!(
-                self.format,
-                FormatSpec {
-                    fill: None,
-                    fill_span: None,
-                    align: AlignUnknown,
-                    sign: None,
-                    alternate: false,
-                    zero_pad: false,
-                    debug_hex: None,
-                    precision: CountImplied,
-                    precision_span: None,
-                    width: CountImplied,
-                    width_span: None,
-                    ty: "",
-                    ty_span: None,
-                },
-            )
+        matches!(self.position, Position::ArgumentNamed(_)) && self.format == FormatSpec::default()
     }
 }
 
 /// Specification for the formatting of an argument in the format string.
-#[derive(Clone, Debug, PartialEq)]
-pub struct FormatSpec<'a> {
+#[derive(Clone, Debug, PartialEq, Default)]
+pub struct FormatSpec<'input> {
     /// Optionally specified character to fill alignment with.
     pub fill: Option<char>,
     /// Span of the optionally specified fill character.
@@ -96,30 +83,30 @@ pub struct FormatSpec<'a> {
     /// The `x` or `X` flag. (Only for `Debug`.)
     pub debug_hex: Option<DebugHex>,
     /// The integer precision to use.
-    pub precision: Count<'a>,
+    pub precision: Count<'input>,
     /// The span of the precision formatting flag (for diagnostics).
     pub precision_span: Option<Range<usize>>,
     /// The string width requested for the resulting format.
-    pub width: Count<'a>,
+    pub width: Count<'input>,
     /// The span of the width formatting flag (for diagnostics).
     pub width_span: Option<Range<usize>>,
     /// The descriptor string representing the name of the format desired for
     /// this argument, this can be empty or any number of characters, although
     /// it is required to be one word.
-    pub ty: &'a str,
+    pub ty: &'input str,
     /// The span of the descriptor string (for diagnostics).
     pub ty_span: Option<Range<usize>>,
 }
 
 /// Enum describing where an argument for a format can be located.
 #[derive(Clone, Debug, PartialEq)]
-pub enum Position<'a> {
+pub enum Position<'input> {
     /// The argument is implied to be located at an index
     ArgumentImplicitlyIs(usize),
     /// The argument is located at a specific index given in the format,
     ArgumentIs(usize),
     /// The argument has a name.
-    ArgumentNamed(&'a str),
+    ArgumentNamed(&'input str),
 }
 
 impl Position<'_> {
@@ -132,7 +119,7 @@ impl Position<'_> {
 }
 
 /// Enum of alignments which are supported.
-#[derive(Copy, Clone, Debug, PartialEq)]
+#[derive(Copy, Clone, Debug, PartialEq, Default)]
 pub enum Alignment {
     /// The value will be aligned to the left.
     AlignLeft,
@@ -141,6 +128,7 @@ pub enum Alignment {
     /// The value will be aligned in the center.
     AlignCenter,
     /// The value will take on a default alignment.
+    #[default]
     AlignUnknown,
 }
 
@@ -164,17 +152,18 @@ pub enum DebugHex {
 
 /// A count is used for the precision and width parameters of an integer, and
 /// can reference either an argument or a literal integer.
-#[derive(Clone, Debug, PartialEq)]
-pub enum Count<'a> {
+#[derive(Clone, Debug, PartialEq, Default)]
+pub enum Count<'input> {
     /// The count is specified explicitly.
     CountIs(u16),
     /// The count is specified by the argument with the given name.
-    CountIsName(&'a str, Range<usize>),
+    CountIsName(&'input str, Range<usize>),
     /// The count is specified by the argument at the given index.
     CountIsParam(usize),
     /// The count is specified by a star (like in `{:.*}`) that refers to the argument at the given index.
     CountIsStar(usize),
     /// The count is implied and cannot be explicitly specified.
+    #[default]
     CountImplied,
 }
 
@@ -208,10 +197,10 @@ pub enum Suggestion {
 ///
 /// This is a recursive-descent parser for the sake of simplicity, and if
 /// necessary there's probably lots of room for improvement performance-wise.
-pub struct Parser<'a> {
+pub struct Parser<'input> {
     mode: ParseMode,
     /// Input to be parsed
-    input: &'a str,
+    input: &'input str,
     /// Tuples of the span in the code snippet (input as written before being unescaped), the pos in input, and the char in input
     input_vec: Vec<(Range<usize>, usize, char)>,
     /// Index into input_vec
@@ -237,15 +226,15 @@ pub struct Parser<'a> {
     pub line_spans: Vec<Range<usize>>,
 }
 
-impl<'a> Iterator for Parser<'a> {
-    type Item = Piece<'a>;
+impl<'input> Iterator for Parser<'input> {
+    type Item = Piece<'input>;
 
-    fn next(&mut self) -> Option<Piece<'a>> {
-        if let Some(&(Range { start, end }, idx, ch)) = self.input_vec.get(self.input_vec_index) {
+    fn next(&mut self) -> Option<Piece<'input>> {
+        if let Some((Range { start, end }, idx, ch)) = self.peek() {
             match ch {
                 '{' => {
                     self.input_vec_index += 1;
-                    if let Some(&(_, i, '{')) = self.input_vec.get(self.input_vec_index) {
+                    if let Some((_, i, '{')) = self.peek() {
                         self.input_vec_index += 1;
                         // double open brace escape: "{{"
                         // next state after this is either end-of-input or seen-a-brace
@@ -254,25 +243,21 @@ impl<'a> Iterator for Parser<'a> {
                         // single open brace
                         self.last_open_brace = Some(start..end);
                         let arg = self.argument();
-                        if let Some(close_brace_range) = self.consume_closing_brace(&arg) {
+                        self.ws();
+                        if let Some((close_brace_range, _)) = self.consume_pos('}') {
                             if self.is_source_literal {
                                 self.arg_places.push(start..close_brace_range.end);
                             }
-                        } else if let Some(&(_, _, c)) = self.input_vec.get(self.input_vec_index) {
-                            match c {
-                                '?' => self.suggest_format_debug(),
-                                '<' | '^' | '>' => self.suggest_format_align(c),
-                                _ => {
-                                    self.suggest_positional_arg_instead_of_captured_arg(arg.clone())
-                                }
-                            }
+                        } else {
+                            self.missing_closing_brace(&arg);
                         }
+
                         Some(Piece::NextArgument(Box::new(arg)))
                     }
                 }
                 '}' => {
                     self.input_vec_index += 1;
-                    if let Some(&(_, i, '}')) = self.input_vec.get(self.input_vec_index) {
+                    if let Some((_, i, '}')) = self.peek() {
                         self.input_vec_index += 1;
                         // double close brace escape: "}}"
                         // next state after this is either end-of-input or start
@@ -307,14 +292,14 @@ impl<'a> Iterator for Parser<'a> {
     }
 }
 
-impl<'a> Parser<'a> {
+impl<'input> Parser<'input> {
     /// Creates a new parser for the given unescaped input string and
     /// optional code snippet (the input as written before being unescaped),
     /// where `style` is `Some(nr_hashes)` when the snippet is a raw string with that many hashes.
     /// If the input comes via `println` or `panic`, then it has a newline already appended,
     /// which is reflected in the `appended_newline` parameter.
     pub fn new(
-        input: &'a str,
+        input: &'input str,
         style: Option<usize>,
         snippet: Option<String>,
         appended_newline: bool,
@@ -406,6 +391,16 @@ impl<'a> Parser<'a> {
         }
     }
 
+    /// Peeks at the current position, without incrementing the pointer.
+    pub fn peek(&self) -> Option<(Range<usize>, usize, char)> {
+        self.input_vec.get(self.input_vec_index).cloned()
+    }
+
+    /// Peeks at the current position + 1, without incrementing the pointer.
+    pub fn peek_ahead(&self) -> Option<(Range<usize>, usize, char)> {
+        self.input_vec.get(self.input_vec_index + 1).cloned()
+    }
+
     /// Optionally consumes the specified character. If the character is not at
     /// the current position, then the current iterator isn't moved and `false` is
     /// returned, otherwise the character is consumed and `true` is returned.
@@ -418,27 +413,19 @@ impl<'a> Parser<'a> {
     /// returned, otherwise the character is consumed and the current position is
     /// returned.
     fn consume_pos(&mut self, ch: char) -> Option<(Range<usize>, usize)> {
-        if let Some((r, i, c)) = self.input_vec.get(self.input_vec_index) {
-            if ch == *c {
-                self.input_vec_index += 1;
-                return Some((r.clone(), *i));
-            }
+        if let Some((r, i, c)) = self.peek()
+            && ch == c
+        {
+            self.input_vec_index += 1;
+            return Some((r, i));
         }
+
         None
     }
 
-    /// Forces consumption of the specified character. If the character is not
-    /// found, an error is emitted.
-    fn consume_closing_brace(&mut self, arg: &Argument<'_>) -> Option<Range<usize>> {
-        self.ws();
-
-        let (range, description) = if let Some((r, _, c)) = self.input_vec.get(self.input_vec_index)
-        {
-            if *c == '}' {
-                self.input_vec_index += 1;
-                return Some(r.clone());
-            }
-            // or r.clone()?
+    /// Called if a closing brace was not found.
+    fn missing_closing_brace(&mut self, arg: &Argument<'_>) {
+        let (range, description) = if let Some((r, _, c)) = self.peek() {
             (r.start..r.start, format!("expected `}}`, found `{}`", c.escape_debug()))
         } else {
             (
@@ -471,7 +458,13 @@ impl<'a> Parser<'a> {
             suggestion: Suggestion::None,
         });
 
-        None
+        if let Some((_, _, c)) = self.peek() {
+            match c {
+                '?' => self.suggest_format_debug(),
+                '<' | '^' | '>' => self.suggest_format_align(c),
+                _ => self.suggest_positional_arg_instead_of_captured_arg(arg),
+            }
+        }
     }
 
     /// Consumes all whitespace characters until the first non-whitespace character
@@ -483,11 +476,11 @@ impl<'a> Parser<'a> {
 
     /// Parses all of a string which is to be considered a "raw literal" in a
     /// format string. This is everything outside of the braces.
-    fn string(&mut self, start: usize) -> &'a str {
-        while let Some((r, i, c)) = self.input_vec.get(self.input_vec_index) {
+    fn string(&mut self, start: usize) -> &'input str {
+        while let Some((r, i, c)) = self.peek() {
             match c {
                 '{' | '}' => {
-                    return &self.input[start..*i];
+                    return &self.input[start..i];
                 }
                 '\n' if self.is_source_literal => {
                     self.input_vec_index += 1;
@@ -507,7 +500,7 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses an `Argument` structure, or what's contained within braces inside the format string.
-    fn argument(&mut self) -> Argument<'a> {
+    fn argument(&mut self) -> Argument<'input> {
         let start_idx = self.input_vec_index;
 
         let position = self.position();
@@ -518,6 +511,7 @@ impl<'a> Parser<'a> {
         let format = match self.mode {
             ParseMode::Format => self.format(),
             ParseMode::InlineAsm => self.inline_asm(),
+            ParseMode::Diagnostic => self.diagnostic(),
         };
 
         // Resolve position after parsing format spec.
@@ -536,31 +530,27 @@ impl<'a> Parser<'a> {
     /// integer index of an argument, a named argument, or a blank string.
     /// Returns `Some(parsed_position)` if the position is not implicitly
     /// consuming a macro argument, `None` if it's the case.
-    fn position(&mut self) -> Option<Position<'a>> {
+    fn position(&mut self) -> Option<Position<'input>> {
         if let Some(i) = self.integer() {
             Some(ArgumentIs(i.into()))
         } else {
-            match self.input_vec.get(self.input_vec_index) {
-                Some((range, _, c)) if rustc_lexer::is_id_start(*c) => {
+            match self.peek() {
+                Some((range, _, c)) if rustc_lexer::is_id_start(c) => {
                     let start = range.start;
                     let word = self.word();
 
                     // Recover from `r#ident` in format strings.
-                    // FIXME: use a let chain
-                    if word == "r" {
-                        if let Some((r, _, '#')) = self.input_vec.get(self.input_vec_index) {
-                            if self
-                                .input_vec
-                                .get(self.input_vec_index + 1)
-                                .is_some_and(|(_, _, c)| rustc_lexer::is_id_start(*c))
-                            {
-                                self.input_vec_index += 1;
-                                let prefix_end = r.end;
-                                let word = self.word();
-                                let prefix_span = start..prefix_end;
-                                let full_span =
-                                    start..self.input_vec_index2range(self.input_vec_index).start;
-                                self.errors.insert(0, ParseError {
+                    if word == "r"
+                        && let Some((r, _, '#')) = self.peek()
+                        && self.peek_ahead().is_some_and(|(_, _, c)| rustc_lexer::is_id_start(c))
+                    {
+                        self.input_vec_index += 1;
+                        let prefix_end = r.end;
+                        let word = self.word();
+                        let prefix_span = start..prefix_end;
+                        let full_span =
+                            start..self.input_vec_index2range(self.input_vec_index).start;
+                        self.errors.insert(0, ParseError {
                                     description: "raw identifiers are not supported".to_owned(),
                                     note: Some("identifiers in format strings can be keywords and don't need to be prefixed with `r#`".to_string()),
                                     label: "raw identifier used here".to_owned(),
@@ -568,9 +558,7 @@ impl<'a> Parser<'a> {
                                     secondary_label: None,
                                     suggestion: Suggestion::RemoveRawIdent(prefix_span),
                                 });
-                                return Some(ArgumentNamed(word));
-                            }
-                        }
+                        return Some(ArgumentNamed(word));
                     }
 
                     Some(ArgumentNamed(word))
@@ -584,7 +572,7 @@ impl<'a> Parser<'a> {
     }
 
     fn input_vec_index2pos(&self, index: usize) -> usize {
-        if let Some(&(_, pos, _)) = self.input_vec.get(index) { pos } else { self.input.len() }
+        if let Some((_, pos, _)) = self.input_vec.get(index) { *pos } else { self.input.len() }
     }
 
     fn input_vec_index2range(&self, index: usize) -> Range<usize> {
@@ -597,33 +585,18 @@ impl<'a> Parser<'a> {
 
     /// Parses a format specifier at the current position, returning all of the
     /// relevant information in the `FormatSpec` struct.
-    fn format(&mut self) -> FormatSpec<'a> {
-        let mut spec = FormatSpec {
-            fill: None,
-            fill_span: None,
-            align: AlignUnknown,
-            sign: None,
-            alternate: false,
-            zero_pad: false,
-            debug_hex: None,
-            precision: CountImplied,
-            precision_span: None,
-            width: CountImplied,
-            width_span: None,
-            ty: &self.input[..0],
-            ty_span: None,
-        };
+    fn format(&mut self) -> FormatSpec<'input> {
+        let mut spec = FormatSpec::default();
+
         if !self.consume(':') {
             return spec;
         }
 
         // fill character
-        if let Some(&(ref r, _, c)) = self.input_vec.get(self.input_vec_index) {
-            if let Some((_, _, '>' | '<' | '^')) = self.input_vec.get(self.input_vec_index + 1) {
-                self.input_vec_index += 1;
-                spec.fill = Some(c);
-                spec.fill_span = Some(r.clone());
-            }
+        if let (Some((r, _, c)), Some((_, _, '>' | '<' | '^'))) = (self.peek(), self.peek_ahead()) {
+            self.input_vec_index += 1;
+            spec.fill = Some(c);
+            spec.fill_span = Some(r);
         }
         // Alignment
         if self.consume('<') {
@@ -701,24 +674,21 @@ impl<'a> Parser<'a> {
             }
         } else if let Some((range, _)) = self.consume_pos('?') {
             spec.ty = "?";
-            if let Some((r, _, c)) = self.input_vec.get(self.input_vec_index) {
-                match c {
-                    '#' | 'x' | 'X' => self.errors.insert(
-                        0,
-                        ParseError {
-                            description: format!("expected `}}`, found `{c}`"),
-                            note: None,
-                            label: "expected `'}'`".into(),
-                            span: r.clone(),
-                            secondary_label: None,
-                            suggestion: Suggestion::ReorderFormatParameter(
-                                range.start..r.end,
-                                format!("{c}?"),
-                            ),
-                        },
-                    ),
-                    _ => (),
-                }
+            if let Some((r, _, c @ ('#' | 'x' | 'X'))) = self.peek() {
+                self.errors.insert(
+                    0,
+                    ParseError {
+                        description: format!("expected `}}`, found `{c}`"),
+                        note: None,
+                        label: "expected `'}'`".into(),
+                        span: r.clone(),
+                        secondary_label: None,
+                        suggestion: Suggestion::ReorderFormatParameter(
+                            range.start..r.end,
+                            format!("{c}?"),
+                        ),
+                    },
+                );
             }
         } else {
             spec.ty = self.word();
@@ -733,22 +703,9 @@ impl<'a> Parser<'a> {
 
     /// Parses an inline assembly template modifier at the current position, returning the modifier
     /// in the `ty` field of the `FormatSpec` struct.
-    fn inline_asm(&mut self) -> FormatSpec<'a> {
-        let mut spec = FormatSpec {
-            fill: None,
-            fill_span: None,
-            align: AlignUnknown,
-            sign: None,
-            alternate: false,
-            zero_pad: false,
-            debug_hex: None,
-            precision: CountImplied,
-            precision_span: None,
-            width: CountImplied,
-            width_span: None,
-            ty: &self.input[..0],
-            ty_span: None,
-        };
+    fn inline_asm(&mut self) -> FormatSpec<'input> {
+        let mut spec = FormatSpec::default();
+
         if !self.consume(':') {
             return spec;
         }
@@ -764,10 +721,26 @@ impl<'a> Parser<'a> {
         spec
     }
 
+    /// Always returns an empty `FormatSpec`
+    fn diagnostic(&mut self) -> FormatSpec<'input> {
+        let mut spec = FormatSpec::default();
+
+        let Some((Range { start, .. }, start_idx)) = self.consume_pos(':') else {
+            return spec;
+        };
+
+        spec.ty = self.string(start_idx);
+        spec.ty_span = {
+            let end = self.input_vec_index2range(self.input_vec_index).start;
+            Some(start..end)
+        };
+        spec
+    }
+
     /// Parses a `Count` parameter at the current position. This does not check
     /// for 'CountIsNextParam' because that is only used in precision, not
     /// width.
-    fn count(&mut self) -> Count<'a> {
+    fn count(&mut self) -> Count<'input> {
         if let Some(i) = self.integer() {
             if self.consume('$') { CountIsParam(i.into()) } else { CountIs(i) }
         } else {
@@ -786,10 +759,10 @@ impl<'a> Parser<'a> {
 
     /// Parses a word starting at the current position. A word is the same as a
     /// Rust identifier, except that it can't start with `_` character.
-    fn word(&mut self) -> &'a str {
+    fn word(&mut self) -> &'input str {
         let index = self.input_vec_index;
-        match self.input_vec.get(self.input_vec_index) {
-            Some(&(ref r, i, c)) if rustc_lexer::is_id_start(c) => {
+        match self.peek() {
+            Some((ref r, i, c)) if rustc_lexer::is_id_start(c) => {
                 self.input_vec_index += 1;
                 (r.start, i)
             }
@@ -798,7 +771,7 @@ impl<'a> Parser<'a> {
             }
         };
         let (err_end, end): (usize, usize) = loop {
-            if let Some(&(ref r, i, c)) = self.input_vec.get(self.input_vec_index) {
+            if let Some((ref r, i, c)) = self.peek() {
                 if rustc_lexer::is_id_continue(c) {
                     self.input_vec_index += 1;
                 } else {
@@ -828,7 +801,7 @@ impl<'a> Parser<'a> {
         let mut found = false;
         let mut overflow = false;
         let start_index = self.input_vec_index;
-        while let Some(&(_, _, c)) = self.input_vec.get(self.input_vec_index) {
+        while let Some((_, _, c)) = self.peek() {
             if let Some(i) = c.to_digit(10) {
                 self.input_vec_index += 1;
                 let (tmp, mul_overflow) = cur.overflowing_mul(10);
@@ -897,7 +870,7 @@ impl<'a> Parser<'a> {
         }
     }
 
-    fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: Argument<'a>) {
+    fn suggest_positional_arg_instead_of_captured_arg(&mut self, arg: &Argument<'_>) {
         // If the argument is not an identifier, it is not a field access.
         if !arg.is_identifier() {
             return;
diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs
index e6a7f24034a..a6c7e1890ab 100644
--- a/compiler/rustc_parse_format/src/tests.rs
+++ b/compiler/rustc_parse_format/src/tests.rs
@@ -553,3 +553,45 @@ fn asm_concat() {
     assert_eq!(parser.by_ref().collect::<Vec<Piece<'static>>>(), &[Lit(asm)]);
     assert_eq!(parser.line_spans, &[]);
 }
+
+#[test]
+fn diagnostic_format_flags() {
+    let lit = "{thing:blah}";
+    let mut parser = Parser::new(lit, None, None, false, ParseMode::Diagnostic);
+    assert!(!parser.is_source_literal);
+
+    let [NextArgument(arg)] = &*parser.by_ref().collect::<Vec<Piece<'static>>>() else { panic!() };
+
+    assert_eq!(
+        **arg,
+        Argument {
+            position: ArgumentNamed("thing"),
+            position_span: 2..7,
+            format: FormatSpec { ty: ":blah", ty_span: Some(7..12), ..Default::default() },
+        }
+    );
+
+    assert_eq!(parser.line_spans, &[]);
+    assert!(parser.errors.is_empty());
+}
+
+#[test]
+fn diagnostic_format_mod() {
+    let lit = "{thing:+}";
+    let mut parser = Parser::new(lit, None, None, false, ParseMode::Diagnostic);
+    assert!(!parser.is_source_literal);
+
+    let [NextArgument(arg)] = &*parser.by_ref().collect::<Vec<Piece<'static>>>() else { panic!() };
+
+    assert_eq!(
+        **arg,
+        Argument {
+            position: ArgumentNamed("thing"),
+            position_span: 2..7,
+            format: FormatSpec { ty: ":+", ty_span: Some(7..9), ..Default::default() },
+        }
+    );
+
+    assert_eq!(parser.line_spans, &[]);
+    assert!(parser.errors.is_empty());
+}
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 983e562cdf3..7c237d708c0 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -56,23 +56,6 @@ passes_autodiff_attr =
 passes_both_ffi_const_and_pure =
     `#[ffi_const]` function cannot be `#[ffi_pure]`
 
-passes_break_inside_closure =
-    `{$name}` inside of a closure
-    .label = cannot `{$name}` inside of a closure
-    .closure_label = enclosing closure
-
-passes_break_inside_coroutine =
-    `{$name}` inside `{$kind}` {$source}
-    .label = cannot `{$name}` inside `{$kind}` {$source}
-    .coroutine_label = enclosing `{$kind}` {$source}
-
-passes_break_non_loop =
-    `break` with value from a `{$kind}` loop
-    .label = can only break with a value inside `loop` or breakable block
-    .label2 = you can't `break` with a value in a `{$kind}` loop
-    .suggestion = use `break` on its own without a value inside this `{$kind}` loop
-    .break_expr_suggestion = alternatively, you might have meant to use the available loop label
-
 passes_cannot_stabilize_deprecated =
     an API can't be stabilized after it is deprecated
     .label = invalid version
@@ -103,10 +86,6 @@ passes_const_stable_not_stable =
     attribute `#[rustc_const_stable]` can only be applied to functions that are declared `#[stable]`
     .label = attribute specified here
 
-passes_continue_labeled_block =
-    `continue` pointing to a labeled block
-    .label = labeled blocks cannot be `continue`'d
-    .block_label = labeled block the `continue` points to
 
 passes_coroutine_on_non_closure =
     attribute should be applied to closures
@@ -311,6 +290,9 @@ passes_duplicate_lang_item_crate_depends =
     .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path}
     .second_definition_path = second definition in `{$crate_name}` loaded from {$path}
 
+passes_enum_variant_same_name =
+    it is impossible to refer to the {$descr} `{$dead_name}` because it is shadowed by this enum variant with the same name
+
 passes_export_name =
     attribute should be applied to a free function, impl method or static
     .label = not a free function, impl method or static
@@ -574,17 +556,6 @@ passes_optimize_invalid_target =
 passes_outer_crate_level_attr =
     crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
 
-passes_outside_loop =
-    `{$name}` outside of a loop{$is_break ->
-        [true] {" or labeled block"}
-        *[false] {""}
-    }
-    .label = cannot `{$name}` outside of a loop{$is_break ->
-        [true] {" or labeled block"}
-        *[false] {""}
-    }
-
-passes_outside_loop_suggestion = consider labeling this block to be able to break within it
 
 passes_panic_unwind_without_std =
     unwinding panics are not supported without std
@@ -748,18 +719,13 @@ passes_unknown_external_lang_item =
 passes_unknown_feature =
     unknown feature `{$feature}`
 
+passes_unknown_feature_alias =
+    feature `{$alias}` has been renamed to `{$feature}`
+
 passes_unknown_lang_item =
     definition of an unknown lang item: `{$name}`
     .label = definition of unknown lang item `{$name}`
 
-passes_unlabeled_cf_in_while_condition =
-    `break` or `continue` with no label in the condition of a `while` loop
-    .label = unlabeled `{$cf_type}` in the condition of a `while` loop
-
-passes_unlabeled_in_labeled_block =
-    unlabeled `{$cf_type}` inside of a labeled block
-    .label = `{$cf_type}` statements that would diverge to or through a labeled block need to bear a label
-
 passes_unnecessary_partial_stable_feature = the feature `{$feature}` has been partially stabilized since {$since} and is succeeded by the feature `{$implies}`
     .suggestion = if you are using features which are still unstable, change to using `{$implies}`
     .suggestion_remove = if you are using features which are now stable, remove this line
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_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index e597c819a3a..4257d8e8d16 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -14,7 +14,7 @@ use rustc_errors::MultiSpan;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{self as hir, Node, PatKind, QPath, TyKind};
+use rustc_hir::{self as hir, ImplItem, ImplItemKind, Node, PatKind, QPath, TyKind};
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::privacy::Level;
 use rustc_middle::query::Providers;
@@ -936,7 +936,9 @@ enum ShouldWarnAboutField {
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 enum ReportOn {
+    /// Report on something that hasn't got a proper name to refer to
     TupleField,
+    /// Report on something that has got a name, which could be a field but also a method
     NamedField,
 }
 
@@ -1061,6 +1063,31 @@ impl<'tcx> DeadVisitor<'tcx> {
                 None
             };
 
+        let enum_variants_with_same_name = dead_codes
+            .iter()
+            .filter_map(|dead_item| {
+                if let Node::ImplItem(ImplItem {
+                    kind: ImplItemKind::Fn(..) | ImplItemKind::Const(..),
+                    ..
+                }) = tcx.hir_node_by_def_id(dead_item.def_id)
+                    && let Some(impl_did) = tcx.opt_parent(dead_item.def_id.to_def_id())
+                    && let DefKind::Impl { of_trait: false } = tcx.def_kind(impl_did)
+                    && let ty::Adt(maybe_enum, _) = tcx.type_of(impl_did).skip_binder().kind()
+                    && maybe_enum.is_enum()
+                    && let Some(variant) =
+                        maybe_enum.variants().iter().find(|i| i.name == dead_item.name)
+                {
+                    Some(crate::errors::EnumVariantSameName {
+                        descr: tcx.def_descr(dead_item.def_id.to_def_id()),
+                        dead_name: dead_item.name,
+                        variant_span: tcx.def_span(variant.def_id),
+                    })
+                } else {
+                    None
+                }
+            })
+            .collect();
+
         let diag = match report_on {
             ReportOn::TupleField => {
                 let tuple_fields = if let Some(parent_id) = parent_item
@@ -1114,6 +1141,7 @@ impl<'tcx> DeadVisitor<'tcx> {
                 name_list,
                 parent_info,
                 ignored_derived_impls,
+                enum_variants_with_same_name,
             },
         };
 
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index b995781719b..f0d4b610f63 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -1,13 +1,12 @@
 use std::io::Error;
 use std::path::{Path, PathBuf};
 
-use rustc_ast::Label;
 use rustc_errors::codes::*;
 use rustc_errors::{
     Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level,
     MultiSpan, Subdiagnostic,
 };
-use rustc_hir::{self as hir, ExprKind, Target};
+use rustc_hir::Target;
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::{MainDefinition, Ty};
 use rustc_span::{DUMMY_SP, Span, Symbol};
@@ -1071,131 +1070,6 @@ pub(crate) struct FeaturePreviouslyDeclared<'a> {
     pub prev_declared: &'a str,
 }
 
-pub(crate) struct BreakNonLoop<'a> {
-    pub span: Span,
-    pub head: Option<Span>,
-    pub kind: &'a str,
-    pub suggestion: String,
-    pub loop_label: Option<Label>,
-    pub break_label: Option<Label>,
-    pub break_expr_kind: &'a ExprKind<'a>,
-    pub break_expr_span: Span,
-}
-
-impl<'a, G: EmissionGuarantee> Diagnostic<'_, G> for BreakNonLoop<'a> {
-    #[track_caller]
-    fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> {
-        let mut diag = Diag::new(dcx, level, fluent::passes_break_non_loop);
-        diag.span(self.span);
-        diag.code(E0571);
-        diag.arg("kind", self.kind);
-        diag.span_label(self.span, fluent::passes_label);
-        if let Some(head) = self.head {
-            diag.span_label(head, fluent::passes_label2);
-        }
-        diag.span_suggestion(
-            self.span,
-            fluent::passes_suggestion,
-            self.suggestion,
-            Applicability::MaybeIncorrect,
-        );
-        if let (Some(label), None) = (self.loop_label, self.break_label) {
-            match self.break_expr_kind {
-                ExprKind::Path(hir::QPath::Resolved(
-                    None,
-                    hir::Path { segments: [segment], res: hir::def::Res::Err, .. },
-                )) if label.ident.to_string() == format!("'{}", segment.ident) => {
-                    // This error is redundant, we will have already emitted a
-                    // suggestion to use the label when `segment` wasn't found
-                    // (hence the `Res::Err` check).
-                    diag.downgrade_to_delayed_bug();
-                }
-                _ => {
-                    diag.span_suggestion(
-                        self.break_expr_span,
-                        fluent::passes_break_expr_suggestion,
-                        label.ident,
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-            }
-        }
-        diag
-    }
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_continue_labeled_block, code = E0696)]
-pub(crate) struct ContinueLabeledBlock {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-    #[label(passes_block_label)]
-    pub block_span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_break_inside_closure, code = E0267)]
-pub(crate) struct BreakInsideClosure<'a> {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-    #[label(passes_closure_label)]
-    pub closure_span: Span,
-    pub name: &'a str,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_break_inside_coroutine, code = E0267)]
-pub(crate) struct BreakInsideCoroutine<'a> {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-    #[label(passes_coroutine_label)]
-    pub coroutine_span: Span,
-    pub name: &'a str,
-    pub kind: &'a str,
-    pub source: &'a str,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_outside_loop, code = E0268)]
-pub(crate) struct OutsideLoop<'a> {
-    #[primary_span]
-    #[label]
-    pub spans: Vec<Span>,
-    pub name: &'a str,
-    pub is_break: bool,
-    #[subdiagnostic]
-    pub suggestion: Option<OutsideLoopSuggestion>,
-}
-#[derive(Subdiagnostic)]
-#[multipart_suggestion(passes_outside_loop_suggestion, applicability = "maybe-incorrect")]
-pub(crate) struct OutsideLoopSuggestion {
-    #[suggestion_part(code = "'block: ")]
-    pub block_span: Span,
-    #[suggestion_part(code = " 'block")]
-    pub break_spans: Vec<Span>,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_unlabeled_in_labeled_block, code = E0695)]
-pub(crate) struct UnlabeledInLabeledBlock<'a> {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-    pub cf_type: &'a str,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_unlabeled_cf_in_while_condition, code = E0590)]
-pub(crate) struct UnlabeledCfInWhileCondition<'a> {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-    pub cf_type: &'a str,
-}
-
 #[derive(Diagnostic)]
 #[diag(passes_naked_functions_incompatible_attribute, code = E0736)]
 pub(crate) struct NakedFunctionIncompatibleAttribute {
@@ -1561,6 +1435,15 @@ pub(crate) struct UnknownFeature {
 }
 
 #[derive(Diagnostic)]
+#[diag(passes_unknown_feature_alias, code = E0635)]
+pub(crate) struct RenamedFeature {
+    #[primary_span]
+    pub span: Span,
+    pub feature: Symbol,
+    pub alias: Symbol,
+}
+
+#[derive(Diagnostic)]
 #[diag(passes_implied_feature_not_exist)]
 pub(crate) struct ImpliedFeatureNotExist {
     #[primary_span]
@@ -1604,6 +1487,9 @@ pub(crate) enum MultipleDeadCodes<'tcx> {
         participle: &'tcx str,
         name_list: DiagSymbolList,
         #[subdiagnostic]
+        // only on DeadCodes since it's never a problem for tuple struct fields
+        enum_variants_with_same_name: Vec<EnumVariantSameName<'tcx>>,
+        #[subdiagnostic]
         parent_info: Option<ParentInfo<'tcx>>,
         #[subdiagnostic]
         ignored_derived_impls: Option<IgnoredDerivedImpls>,
@@ -1625,6 +1511,15 @@ pub(crate) enum MultipleDeadCodes<'tcx> {
 }
 
 #[derive(Subdiagnostic)]
+#[note(passes_enum_variant_same_name)]
+pub(crate) struct EnumVariantSameName<'tcx> {
+    #[primary_span]
+    pub variant_span: Span,
+    pub dead_name: Symbol,
+    pub descr: &'tcx str,
+}
+
+#[derive(Subdiagnostic)]
 #[label(passes_parent_info)]
 pub(crate) struct ParentInfo<'tcx> {
     pub num: usize,
diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs
index 6852153a2e7..46e6c0bf7da 100644
--- a/compiler/rustc_passes/src/input_stats.rs
+++ b/compiler/rustc_passes/src/input_stats.rs
@@ -5,7 +5,7 @@
 use rustc_ast::visit::BoundKind;
 use rustc_ast::{self as ast, NodeId, visit as ast_visit};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::thousands::format_with_underscores;
+use rustc_data_structures::thousands::usize_with_underscores;
 use rustc_hir::{self as hir, AmbigArg, HirId, intravisit as hir_visit};
 use rustc_middle::ty::TyCtxt;
 use rustc_span::Span;
@@ -140,10 +140,10 @@ impl<'k> StatCollector<'k> {
                 "{} {:<18}{:>10} ({:4.1}%){:>14}{:>14}",
                 prefix,
                 label,
-                format_with_underscores(size),
+                usize_with_underscores(size),
                 percent(size, total_size),
-                format_with_underscores(node.stats.count),
-                format_with_underscores(node.stats.size)
+                usize_with_underscores(node.stats.count),
+                usize_with_underscores(node.stats.size)
             );
             if !node.subnodes.is_empty() {
                 // We will soon sort, so the initial order does not matter.
@@ -159,9 +159,9 @@ impl<'k> StatCollector<'k> {
                         "{} - {:<18}{:>10} ({:4.1}%){:>14}",
                         prefix,
                         label,
-                        format_with_underscores(size),
+                        usize_with_underscores(size),
                         percent(size, total_size),
-                        format_with_underscores(subnode.count),
+                        usize_with_underscores(subnode.count),
                     );
                 }
             }
@@ -171,8 +171,8 @@ impl<'k> StatCollector<'k> {
             "{} {:<18}{:>10}        {:>14}",
             prefix,
             "Total",
-            format_with_underscores(total_size),
-            format_with_underscores(total_count),
+            usize_with_underscores(total_size),
+            usize_with_underscores(total_count),
         );
         eprintln!("{prefix}");
     }
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index 1831f45a9ec..af7ecf0830c 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -29,7 +29,6 @@ mod lang_items;
 pub mod layout_test;
 mod lib_features;
 mod liveness;
-pub mod loops;
 mod reachable;
 pub mod stability;
 mod upvars;
@@ -45,7 +44,6 @@ pub fn provide(providers: &mut Providers) {
     entry::provide(providers);
     lang_items::provide(providers);
     lib_features::provide(providers);
-    loops::provide(providers);
     liveness::provide(providers);
     reachable::provide(providers);
     stability::provide(providers);
diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs
index b3e6ee9512c..127e0df1332 100644
--- a/compiler/rustc_passes/src/lib_features.rs
+++ b/compiler/rustc_passes/src/lib_features.rs
@@ -40,7 +40,7 @@ impl<'tcx> LibFeatureCollector<'tcx> {
         };
 
         let feature_stability = match level {
-            StabilityLevel::Unstable { .. } => FeatureStability::Unstable,
+            StabilityLevel::Unstable { old_name, .. } => FeatureStability::Unstable { old_name },
             StabilityLevel::Stable { since, .. } => FeatureStability::AcceptedSince(match since {
                 StableSince::Version(v) => Symbol::intern(&v.to_string()),
                 StableSince::Current => sym::env_CFG_RELEASE,
@@ -71,7 +71,7 @@ impl<'tcx> LibFeatureCollector<'tcx> {
                     });
                 }
             }
-            (FeatureStability::AcceptedSince(_), Some((FeatureStability::Unstable, _))) => {
+            (FeatureStability::AcceptedSince(_), Some((FeatureStability::Unstable { .. }, _))) => {
                 self.tcx.dcx().emit_err(FeaturePreviouslyDeclared {
                     span,
                     feature,
@@ -79,7 +79,7 @@ impl<'tcx> LibFeatureCollector<'tcx> {
                     prev_declared: "unstable",
                 });
             }
-            (FeatureStability::Unstable, Some((FeatureStability::AcceptedSince(_), _))) => {
+            (FeatureStability::Unstable { .. }, Some((FeatureStability::AcceptedSince(_), _))) => {
                 self.tcx.dcx().emit_err(FeaturePreviouslyDeclared {
                     span,
                     feature,
@@ -88,7 +88,7 @@ impl<'tcx> LibFeatureCollector<'tcx> {
                 });
             }
             // duplicate `unstable` feature is ok.
-            (FeatureStability::Unstable, Some((FeatureStability::Unstable, _))) => {}
+            (FeatureStability::Unstable { .. }, Some((FeatureStability::Unstable { .. }, _))) => {}
         }
     }
 }
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 45e26c8999a..56d9f5bf785 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -718,6 +718,7 @@ fn stability_index(tcx: TyCtxt<'_>, (): ()) -> Index {
                     issue: NonZero::new(27812),
                     is_soft: false,
                     implied_by: None,
+                    old_name: None,
                 },
                 feature: sym::rustc_private,
             };
@@ -1161,8 +1162,8 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
         defined_features: &LibFeatures,
         all_implications: &UnordMap<Symbol, Symbol>,
     ) {
-        for (feature, since) in defined_features.to_sorted_vec() {
-            if let FeatureStability::AcceptedSince(since) = since
+        for (feature, stability) in defined_features.to_sorted_vec() {
+            if let FeatureStability::AcceptedSince(since) = stability
                 && let Some(span) = remaining_lib_features.get(&feature)
             {
                 // Warn if the user has enabled an already-stable lib feature.
@@ -1181,6 +1182,12 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
             // implications from this crate.
             remaining_implications.remove(&feature);
 
+            if let FeatureStability::Unstable { old_name: Some(alias) } = stability {
+                if let Some(span) = remaining_lib_features.swap_remove(&alias) {
+                    tcx.dcx().emit_err(errors::RenamedFeature { span, feature, alias });
+                }
+            }
+
             if remaining_lib_features.is_empty() && remaining_implications.is_empty() {
                 break;
             }
diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index 38cdfa72a14..58942474e32 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -119,7 +119,7 @@ resolve_const_param_in_enum_discriminant =
     const parameters may not be used in enum discriminant values
 
 resolve_const_param_in_non_trivial_anon_const =
-    const parameters may only be used as standalone arguments, i.e. `{$name}`
+    const parameters may only be used as standalone arguments here, i.e. `{$name}`
 
 resolve_constructor_private_if_any_field_private =
     a constructor is private if any of the fields is private
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index c30ed781f35..650a827ba56 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -1098,22 +1098,20 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
             self.r.potentially_unused_imports.push(import);
             module.for_each_child(self, |this, ident, ns, binding| {
                 if ns == MacroNS {
-                    let imported_binding =
-                        if this.r.is_accessible_from(binding.vis, this.parent_scope.module) {
-                            this.r.import(binding, import)
-                        } else if !this.r.is_builtin_macro(binding.res())
-                            && !this.r.macro_use_prelude.contains_key(&ident.name)
-                        {
-                            // - `!r.is_builtin_macro(res)` excluding the built-in macros such as `Debug` or `Hash`.
-                            // - `!r.macro_use_prelude.contains_key(name)` excluding macros defined in other extern
-                            //    crates such as `std`.
-                            // FIXME: This branch should eventually be removed.
-                            let import = macro_use_import(this, span, true);
-                            this.r.import(binding, import)
-                        } else {
+                    let import = if this.r.is_accessible_from(binding.vis, this.parent_scope.module)
+                    {
+                        import
+                    } else {
+                        // FIXME: This branch is used for reporting the `private_macro_use` lint
+                        // and should eventually be removed.
+                        if this.r.macro_use_prelude.contains_key(&ident.name) {
+                            // Do not override already existing entries with compatibility entries.
                             return;
-                        };
-                    this.add_macro_use_binding(ident.name, imported_binding, span, allow_shadowing);
+                        }
+                        macro_use_import(this, span, true)
+                    };
+                    let import_binding = this.r.import(binding, import);
+                    this.add_macro_use_binding(ident.name, import_binding, span, allow_shadowing);
                 }
             });
         } else {
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index dc16fe212b1..f8e0a6936a0 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -128,7 +128,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
                 // FIXME(jdonszelmann) make one of these in the resolver?
                 // FIXME(jdonszelmann) don't care about tools here maybe? Just parse what we can.
                 // Does that prevents errors from happening? maybe
-                let parser = AttributeParser::new(
+                let mut parser = AttributeParser::new_early(
                     &self.resolver.tcx.sess,
                     self.resolver.tcx.features(),
                     Vec::new(),
@@ -136,8 +136,14 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
                 let attrs = parser.parse_attribute_list(
                     &i.attrs,
                     i.span,
+                    i.id,
                     OmitDoc::Skip,
                     std::convert::identity,
+                    |_l| {
+                        // FIXME(jdonszelmann): emit lints here properly
+                        // NOTE that before new attribute parsing, they didn't happen either
+                        // but it would be nice if we could change that.
+                    },
                 );
 
                 let macro_data =
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 201b1c0a493..9149974a617 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -7,7 +7,7 @@ use rustc_ast::{
 use rustc_ast_pretty::pprust;
 use rustc_attr_data_structures::{self as attr, Stability};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::unord::UnordSet;
+use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_errors::codes::*;
 use rustc_errors::{
     Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, MultiSpan, SuggestionStyle,
@@ -1054,6 +1054,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                                 false,
                                 false,
                                 None,
+                                None,
                             ) else {
                                 continue;
                             };
@@ -1482,7 +1483,35 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         parent_scope: &ParentScope<'ra>,
         ident: Ident,
         krate: &Crate,
+        sugg_span: Option<Span>,
     ) {
+        // Bring imported but unused `derive` macros into `macro_map` so we ensure they can be used
+        // for suggestions.
+        self.visit_scopes(
+            ScopeSet::Macro(MacroKind::Derive),
+            &parent_scope,
+            ident.span.ctxt(),
+            |this, scope, _use_prelude, _ctxt| {
+                let Scope::Module(m, _) = scope else {
+                    return None;
+                };
+                for (_, resolution) in this.resolutions(m).borrow().iter() {
+                    let Some(binding) = resolution.borrow().binding else {
+                        continue;
+                    };
+                    let Res::Def(DefKind::Macro(MacroKind::Derive | MacroKind::Attr), def_id) =
+                        binding.res()
+                    else {
+                        continue;
+                    };
+                    // By doing this all *imported* macros get added to the `macro_map` even if they
+                    // are *unused*, which makes the later suggestions find them and work.
+                    let _ = this.get_macro_by_def_id(def_id);
+                }
+                None::<()>
+            },
+        );
+
         let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind);
         let suggestion = self.early_lookup_typo_candidate(
             ScopeSet::Macro(macro_kind),
@@ -1490,7 +1519,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             ident,
             is_expected,
         );
-        self.add_typo_suggestion(err, suggestion, ident.span);
+        if !self.add_typo_suggestion(err, suggestion, ident.span) {
+            self.detect_derive_attribute(err, ident, parent_scope, sugg_span);
+        }
 
         let import_suggestions =
             self.lookup_import_candidates(ident, Namespace::MacroNS, parent_scope, is_expected);
@@ -1623,6 +1654,105 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         }
     }
 
+    /// Given an attribute macro that failed to be resolved, look for `derive` macros that could
+    /// provide it, either as-is or with small typos.
+    fn detect_derive_attribute(
+        &self,
+        err: &mut Diag<'_>,
+        ident: Ident,
+        parent_scope: &ParentScope<'ra>,
+        sugg_span: Option<Span>,
+    ) {
+        // Find all of the `derive`s in scope and collect their corresponding declared
+        // attributes.
+        // FIXME: this only works if the crate that owns the macro that has the helper_attr
+        // has already been imported.
+        let mut derives = vec![];
+        let mut all_attrs: UnordMap<Symbol, Vec<_>> = UnordMap::default();
+        // We're collecting these in a hashmap, and handle ordering the output further down.
+        #[allow(rustc::potential_query_instability)]
+        for (def_id, data) in &self.macro_map {
+            for helper_attr in &data.ext.helper_attrs {
+                let item_name = self.tcx.item_name(*def_id);
+                all_attrs.entry(*helper_attr).or_default().push(item_name);
+                if helper_attr == &ident.name {
+                    derives.push(item_name);
+                }
+            }
+        }
+        let kind = MacroKind::Derive.descr();
+        if !derives.is_empty() {
+            // We found an exact match for the missing attribute in a `derive` macro. Suggest it.
+            let mut derives: Vec<String> = derives.into_iter().map(|d| d.to_string()).collect();
+            derives.sort();
+            derives.dedup();
+            let msg = match &derives[..] {
+                [derive] => format!(" `{derive}`"),
+                [start @ .., last] => format!(
+                    "s {} and `{last}`",
+                    start.iter().map(|d| format!("`{d}`")).collect::<Vec<_>>().join(", ")
+                ),
+                [] => unreachable!("we checked for this to be non-empty 10 lines above!?"),
+            };
+            let msg = format!(
+                "`{}` is an attribute that can be used by the {kind}{msg}, you might be \
+                     missing a `derive` attribute",
+                ident.name,
+            );
+            let sugg_span = if let ModuleKind::Def(DefKind::Enum, id, _) = parent_scope.module.kind
+            {
+                let span = self.def_span(id);
+                if span.from_expansion() {
+                    None
+                } else {
+                    // For enum variants sugg_span is empty but we can get the enum's Span.
+                    Some(span.shrink_to_lo())
+                }
+            } else {
+                // For items this `Span` will be populated, everything else it'll be None.
+                sugg_span
+            };
+            match sugg_span {
+                Some(span) => {
+                    err.span_suggestion_verbose(
+                        span,
+                        msg,
+                        format!("#[derive({})]\n", derives.join(", ")),
+                        Applicability::MaybeIncorrect,
+                    );
+                }
+                None => {
+                    err.note(msg);
+                }
+            }
+        } else {
+            // We didn't find an exact match. Look for close matches. If any, suggest fixing typo.
+            let all_attr_names = all_attrs.keys().map(|s| *s).into_sorted_stable_ord();
+            if let Some(best_match) = find_best_match_for_name(&all_attr_names, ident.name, None)
+                && let Some(macros) = all_attrs.get(&best_match)
+            {
+                let mut macros: Vec<String> = macros.into_iter().map(|d| d.to_string()).collect();
+                macros.sort();
+                macros.dedup();
+                let msg = match &macros[..] {
+                    [] => return,
+                    [name] => format!(" `{name}` accepts"),
+                    [start @ .., end] => format!(
+                        "s {} and `{end}` accept",
+                        start.iter().map(|m| format!("`{m}`")).collect::<Vec<_>>().join(", "),
+                    ),
+                };
+                let msg = format!("the {kind}{msg} the similarly named `{best_match}` attribute");
+                err.span_suggestion_verbose(
+                    ident.span,
+                    msg,
+                    best_match,
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        }
+    }
+
     pub(crate) fn add_typo_suggestion(
         &self,
         err: &mut Diag<'_>,
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 180d6af219d..68fbe48ebcb 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -460,6 +460,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                                 true,
                                 force,
                                 ignore_import,
+                                None,
                             ) {
                                 Ok((Some(ext), _)) => {
                                     if ext.helper_attrs.contains(&ident.name) {
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 816efd0d5fa..e989209e177 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -133,7 +133,9 @@ impl<'ra> std::fmt::Debug for ImportKind<'ra> {
                 .field("target", target)
                 .field("id", id)
                 .finish(),
-            MacroUse { .. } => f.debug_struct("MacroUse").finish(),
+            MacroUse { warn_private } => {
+                f.debug_struct("MacroUse").field("warn_private", warn_private).finish()
+            }
             MacroExport => f.debug_struct("MacroExport").finish(),
         }
     }
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 3dc285fdab6..fa4b024c422 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -4509,7 +4509,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
             let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident);
             let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None };
             if let Ok((_, res)) =
-                self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None)
+                self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None, None)
             {
                 return Ok(Some(PartialRes::new(res)));
             }
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index 9ba70abd4d9..f0540725416 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1139,7 +1139,7 @@ pub struct Resolver<'ra, 'tcx> {
     proc_macro_stubs: FxHashSet<LocalDefId>,
     /// Traces collected during macro resolution and validated when it's complete.
     single_segment_macro_resolutions:
-        Vec<(Ident, MacroKind, ParentScope<'ra>, Option<NameBinding<'ra>>)>,
+        Vec<(Ident, MacroKind, ParentScope<'ra>, Option<NameBinding<'ra>>, Option<Span>)>,
     multi_segment_macro_resolutions:
         Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'ra>, Option<Res>, Namespace)>,
     builtin_attrs: Vec<(Ident, ParentScope<'ra>)>,
@@ -1934,12 +1934,26 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         }
         if let NameBindingKind::Import { import, binding } = used_binding.kind {
             if let ImportKind::MacroUse { warn_private: true } = import.kind {
-                self.lint_buffer().buffer_lint(
-                    PRIVATE_MACRO_USE,
-                    import.root_id,
-                    ident.span,
-                    BuiltinLintDiag::MacroIsPrivate(ident),
-                );
+                // Do not report the lint if the macro name resolves in stdlib prelude
+                // even without the problematic `macro_use` import.
+                let found_in_stdlib_prelude = self.prelude.is_some_and(|prelude| {
+                    self.maybe_resolve_ident_in_module(
+                        ModuleOrUniformRoot::Module(prelude),
+                        ident,
+                        MacroNS,
+                        &ParentScope::module(self.empty_module, self),
+                        None,
+                    )
+                    .is_ok()
+                });
+                if !found_in_stdlib_prelude {
+                    self.lint_buffer().buffer_lint(
+                        PRIVATE_MACRO_USE,
+                        import.root_id,
+                        ident.span,
+                        BuiltinLintDiag::MacroIsPrivate(ident),
+                    );
+                }
             }
             // Avoid marking `extern crate` items that refer to a name from extern prelude,
             // but not introduce it, as used if they are accessed from lexical scope.
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index ee905065b96..1b82e9c9799 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -12,7 +12,8 @@ use rustc_attr_data_structures::StabilityLevel;
 use rustc_data_structures::intern::Interned;
 use rustc_errors::{Applicability, DiagCtxtHandle, StashKey};
 use rustc_expand::base::{
-    DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, SyntaxExtensionKind,
+    Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension,
+    SyntaxExtensionKind,
 };
 use rustc_expand::compile_declarative_macro;
 use rustc_expand::expand::{
@@ -294,6 +295,14 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
                     && self.tcx.def_kind(mod_def_id) == DefKind::Mod
             })
             .map(|&InvocationParent { parent_def: mod_def_id, .. }| mod_def_id);
+        let sugg_span = match &invoc.kind {
+            InvocationKind::Attr { item: Annotatable::Item(item), .. }
+                if !item.span.from_expansion() =>
+            {
+                Some(item.span.shrink_to_lo())
+            }
+            _ => None,
+        };
         let (ext, res) = self.smart_resolve_macro_path(
             path,
             kind,
@@ -304,6 +313,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
             force,
             deleg_impl,
             looks_like_invoc_in_mod_inert_attr,
+            sugg_span,
         )?;
 
         let span = invoc.span();
@@ -386,6 +396,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
                         true,
                         force,
                         None,
+                        None,
                     ) {
                         Ok((Some(ext), _)) => {
                             if !ext.helper_attrs.is_empty() {
@@ -528,6 +539,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         force: bool,
         deleg_impl: Option<LocalDefId>,
         invoc_in_mod_inert_attr: Option<LocalDefId>,
+        suggestion_span: Option<Span>,
     ) -> Result<(Arc<SyntaxExtension>, Res), Indeterminate> {
         let (ext, res) = match self.resolve_macro_or_delegation_path(
             path,
@@ -538,6 +550,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             deleg_impl,
             invoc_in_mod_inert_attr.map(|def_id| (def_id, node_id)),
             None,
+            suggestion_span,
         ) {
             Ok((Some(ext), res)) => (ext, res),
             Ok((None, res)) => (self.dummy_ext(kind), res),
@@ -681,6 +694,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         trace: bool,
         force: bool,
         ignore_import: Option<Import<'ra>>,
+        suggestion_span: Option<Span>,
     ) -> Result<(Option<Arc<SyntaxExtension>>, Res), Determinacy> {
         self.resolve_macro_or_delegation_path(
             path,
@@ -691,6 +705,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             None,
             None,
             ignore_import,
+            suggestion_span,
         )
     }
 
@@ -704,6 +719,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         deleg_impl: Option<LocalDefId>,
         invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>,
         ignore_import: Option<Import<'ra>>,
+        suggestion_span: Option<Span>,
     ) -> Result<(Option<Arc<SyntaxExtension>>, Res), Determinacy> {
         let path_span = ast_path.span;
         let mut path = Segment::from_path(ast_path);
@@ -768,6 +784,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     kind,
                     *parent_scope,
                     binding.ok(),
+                    suggestion_span,
                 ));
             }
 
@@ -905,7 +922,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         }
 
         let macro_resolutions = mem::take(&mut self.single_segment_macro_resolutions);
-        for (ident, kind, parent_scope, initial_binding) in macro_resolutions {
+        for (ident, kind, parent_scope, initial_binding, sugg_span) in macro_resolutions {
             match self.early_resolve_ident_in_lexical_scope(
                 ident,
                 ScopeSet::Macro(kind),
@@ -946,7 +963,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         expected,
                         ident,
                     });
-                    self.unresolved_macro_suggestions(&mut err, kind, &parent_scope, ident, krate);
+                    self.unresolved_macro_suggestions(
+                        &mut err,
+                        kind,
+                        &parent_scope,
+                        ident,
+                        krate,
+                        sugg_span,
+                    );
                     err.emit();
                 }
             }
@@ -974,7 +998,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
     ) {
         let span = path.span;
         if let Some(stability) = &ext.stability {
-            if let StabilityLevel::Unstable { reason, issue, is_soft, implied_by } = stability.level
+            if let StabilityLevel::Unstable { reason, issue, is_soft, implied_by, .. } =
+                stability.level
             {
                 let feature = stability.feature;
 
diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl
index 528c52eace7..61953614c77 100644
--- a/compiler/rustc_session/messages.ftl
+++ b/compiler/rustc_session/messages.ftl
@@ -40,6 +40,11 @@ session_file_is_not_writeable = output file {$file} is not writeable -- check it
 
 session_file_write_fail = failed to write `{$path}` due to error `{$err}`
 
+session_forbidden_ctarget_feature =
+    target feature `{$feature}` cannot be {$enabled} with `-Ctarget-feature`: {$reason}
+    .note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+session_forbidden_ctarget_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
+
 session_function_return_requires_x86_or_x86_64 = `-Zfunction-return` (except `keep`) is only supported on x86 and x86_64
 
 session_function_return_thunk_extern_requires_non_large_code_model = `-Zfunction-return=thunk-extern` is only supported on non-large code models
@@ -132,6 +137,9 @@ session_target_stack_protector_not_supported = `-Z stack-protector={$stack_prote
 session_unleashed_feature_help_named = skipping check for `{$gate}` feature
 session_unleashed_feature_help_unnamed = skipping check that does not even have a feature gate
 
+session_unstable_ctarget_feature =
+    unstable feature specified for `-Ctarget-feature`: `{$feature}`
+    .note = this feature is not stably supported; its behavior can change in the future
 session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto`
 
 session_unsupported_crate_type_for_target =
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 60e1b465ba9..8984634e5ec 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -2649,6 +2649,15 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M
 
     let prints = collect_print_requests(early_dcx, &mut cg, &unstable_opts, matches);
 
+    // -Zretpoline-external-thunk also requires -Zretpoline
+    if unstable_opts.retpoline_external_thunk {
+        unstable_opts.retpoline = true;
+        target_modifiers.insert(
+            OptionsTargetModifiers::UnstableOptions(UnstableOptionsTargetModifiers::retpoline),
+            "true".to_string(),
+        );
+    }
+
     let cg = cg;
 
     let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index bf95014843d..9c591dcf619 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -501,3 +501,20 @@ pub(crate) struct SoftFloatIgnored;
 #[note]
 #[note(session_soft_float_deprecated_issue)]
 pub(crate) struct SoftFloatDeprecated;
+
+#[derive(Diagnostic)]
+#[diag(session_forbidden_ctarget_feature)]
+#[note]
+#[note(session_forbidden_ctarget_feature_issue)]
+pub(crate) struct ForbiddenCTargetFeature<'a> {
+    pub feature: &'a str,
+    pub enabled: &'a str,
+    pub reason: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(session_unstable_ctarget_feature)]
+#[note]
+pub(crate) struct UnstableCTargetFeature<'a> {
+    pub feature: &'a str,
+}
diff --git a/compiler/rustc_session/src/features.rs b/compiler/rustc_session/src/features.rs
new file mode 100644
index 00000000000..70a088a236f
--- /dev/null
+++ b/compiler/rustc_session/src/features.rs
@@ -0,0 +1,59 @@
+use rustc_target::target_features::Stability;
+
+use crate::Session;
+use crate::errors::{ForbiddenCTargetFeature, UnstableCTargetFeature};
+
+pub trait StabilityExt {
+    /// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`.
+    /// Otherwise, some features also may only be enabled by flag (target modifier).
+    /// (It might still be nightly-only even if this returns `true`, so make sure to also check
+    /// `requires_nightly`.)
+    fn is_toggle_permitted(&self, sess: &Session) -> Result<(), &'static str>;
+
+    /// Check that feature is correctly enabled/disabled by command line flag (emits warnings)
+    fn verify_feature_enabled_by_flag(&self, sess: &Session, enable: bool, feature: &str);
+}
+
+impl StabilityExt for Stability {
+    fn is_toggle_permitted(&self, sess: &Session) -> Result<(), &'static str> {
+        match self {
+            Stability::Forbidden { reason } => Err(reason),
+            Stability::TargetModifierOnly { reason, flag } => {
+                if !sess.opts.target_feature_flag_enabled(*flag) { Err(reason) } else { Ok(()) }
+            }
+            _ => Ok(()),
+        }
+    }
+    fn verify_feature_enabled_by_flag(&self, sess: &Session, enable: bool, feature: &str) {
+        if let Err(reason) = self.is_toggle_permitted(sess) {
+            sess.dcx().emit_warn(ForbiddenCTargetFeature {
+                feature,
+                enabled: if enable { "enabled" } else { "disabled" },
+                reason,
+            });
+        } else if self.requires_nightly().is_some() {
+            // An unstable feature. Warn about using it. It makes little sense
+            // to hard-error here since we just warn about fully unknown
+            // features above.
+            sess.dcx().emit_warn(UnstableCTargetFeature { feature });
+        }
+    }
+}
+
+pub fn retpoline_features_by_flags(sess: &Session, features: &mut Vec<&str>) {
+    // -Zretpoline without -Zretpoline-external-thunk enables
+    // retpoline-indirect-branches and retpoline-indirect-calls target features
+    let unstable_opts = &sess.opts.unstable_opts;
+    if unstable_opts.retpoline && !unstable_opts.retpoline_external_thunk {
+        features.push("+retpoline-indirect-branches");
+        features.push("+retpoline-indirect-calls");
+    }
+    // -Zretpoline-external-thunk (maybe, with -Zretpoline too) enables
+    // retpoline-external-thunk, retpoline-indirect-branches and
+    // retpoline-indirect-calls target features
+    if unstable_opts.retpoline_external_thunk {
+        features.push("+retpoline-external-thunk");
+        features.push("+retpoline-indirect-branches");
+        features.push("+retpoline-indirect-calls");
+    }
+}
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index 5e5872ee068..4added19e56 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -29,6 +29,7 @@ pub use session::*;
 pub mod output;
 
 pub use getopts;
+pub mod features;
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 12fa05118ca..6218521d4f0 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -290,6 +290,14 @@ macro_rules! top_level_options {
                 mods.sort_by(|a, b| a.opt.cmp(&b.opt));
                 mods
             }
+
+            pub fn target_feature_flag_enabled(&self, flag: &str) -> bool {
+                match flag {
+                    "retpoline" => self.unstable_opts.retpoline,
+                    "retpoline-external-thunk" => self.unstable_opts.retpoline_external_thunk,
+                    _ => false,
+                }
+            }
         }
     );
 }
@@ -2305,6 +2313,8 @@ options! {
         (space separated)"),
     macro_backtrace: bool = (false, parse_bool, [UNTRACKED],
         "show macro backtraces (default: no)"),
+    macro_stats: bool = (false, parse_bool, [UNTRACKED],
+        "print some statistics about macro expansions (default: no)"),
     maximal_hir_to_mir_coverage: bool = (false, parse_bool, [TRACKED],
         "save as much information as possible about the correspondence between MIR and HIR \
         as source scopes (default: no)"),
@@ -2446,6 +2456,11 @@ options! {
     remark_dir: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
         "directory into which to write optimization remarks (if not specified, they will be \
 written to standard error output)"),
+    retpoline: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
+        "enables retpoline-indirect-branches and retpoline-indirect-calls target features (default: no)"),
+    retpoline_external_thunk: bool = (false, parse_bool, [TRACKED TARGET_MODIFIER],
+        "enables retpoline-external-thunk, retpoline-indirect-branches and retpoline-indirect-calls \
+        target features (default: no)"),
     sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
         "use a sanitizer"),
     sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED],
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 1fe521bd32d..87c848cf857 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -17,7 +17,7 @@ use rustc_feature::{GateIssue, UnstableFeatures, find_feature_issue};
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::ExpnId;
 use rustc_span::source_map::{FilePathMapping, SourceMap};
-use rustc_span::{Span, Symbol};
+use rustc_span::{Span, Symbol, sym};
 
 use crate::Session;
 use crate::config::{Cfg, CheckCfg};
@@ -192,8 +192,11 @@ pub fn add_feature_diagnostics_for_issue<G: EmissionGuarantee>(
         } else {
             err.subdiagnostic(FeatureDiagnosticHelp { feature });
         }
-
-        if sess.opts.unstable_opts.ui_testing {
+        if feature == sym::rustc_attrs {
+            // We're unlikely to stabilize something out of `rustc_attrs`
+            // without at least renaming it, so pointing out how old
+            // the compiler is will do little good.
+        } else if sess.opts.unstable_opts.ui_testing {
             err.subdiagnostic(SuggestUpgradeCompiler::ui_testing());
         } else if let Some(suggestion) = SuggestUpgradeCompiler::new() {
             err.subdiagnostic(suggestion);
diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs
index 6e13b87c41d..a4c6f186222 100644
--- a/compiler/rustc_smir/src/rustc_internal/internal.rs
+++ b/compiler/rustc_smir/src/rustc_internal/internal.rs
@@ -496,6 +496,7 @@ impl RustcInternal for Abi {
             Abi::RustCold => rustc_abi::ExternAbi::RustCold,
             Abi::RiscvInterruptM => rustc_abi::ExternAbi::RiscvInterruptM,
             Abi::RiscvInterruptS => rustc_abi::ExternAbi::RiscvInterruptS,
+            Abi::Custom => rustc_abi::ExternAbi::Custom,
         }
     }
 }
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
index bac5c9066f1..ef8c88355f6 100644
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -16,7 +16,7 @@ use rustc_middle::ty::{
 };
 use rustc_middle::{mir, ty};
 use rustc_span::def_id::LOCAL_CRATE;
-use stable_mir::abi::{FnAbi, Layout, LayoutShape};
+use stable_mir::abi::{FnAbi, Layout, LayoutShape, ReprOptions};
 use stable_mir::mir::alloc::GlobalAlloc;
 use stable_mir::mir::mono::{InstanceDef, StaticDef};
 use stable_mir::mir::{BinOp, Body, Place, UnOp};
@@ -397,6 +397,13 @@ impl<'tcx> SmirCtxt<'tcx> {
         tables.tcx.is_lang_item(def_id, LangItem::CStr)
     }
 
+    /// Returns the representation options for this ADT
+    pub fn adt_repr(&self, def: AdtDef) -> ReprOptions {
+        let mut tables = self.0.borrow_mut();
+        let tcx = tables.tcx;
+        def.internal(&mut *tables, tcx).repr().stable(&mut *tables)
+    }
+
     /// Retrieve the function signature for the given generic arguments.
     pub fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig {
         let mut tables = self.0.borrow_mut();
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
index 64901ee0502..35d5b7fb89a 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
@@ -6,9 +6,9 @@ use rustc_abi::{ArmCall, CanonAbi, InterruptKind, X86Call};
 use rustc_middle::ty;
 use rustc_target::callconv;
 use stable_mir::abi::{
-    AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength, Layout,
-    LayoutShape, PassMode, Primitive, Scalar, TagEncoding, TyAndLayout, ValueAbi, VariantsShape,
-    WrappingRange,
+    AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength,
+    IntegerType, Layout, LayoutShape, PassMode, Primitive, ReprFlags, ReprOptions, Scalar,
+    TagEncoding, TyAndLayout, ValueAbi, VariantsShape, WrappingRange,
 };
 use stable_mir::opaque;
 use stable_mir::target::MachineSize as Size;
@@ -101,6 +101,7 @@ impl<'tcx> Stable<'tcx> for CanonAbi {
             CanonAbi::C => CallConvention::C,
             CanonAbi::Rust => CallConvention::Rust,
             CanonAbi::RustCold => CallConvention::Cold,
+            CanonAbi::Custom => CallConvention::Custom,
             CanonAbi::Arm(arm_call) => match arm_call {
                 ArmCall::Aapcs => CallConvention::ArmAapcs,
                 ArmCall::CCmseNonSecureCall => CallConvention::CCmseNonSecureCall,
@@ -310,3 +311,42 @@ impl<'tcx> Stable<'tcx> for rustc_abi::WrappingRange {
         WrappingRange { start: self.start, end: self.end }
     }
 }
+
+impl<'tcx> Stable<'tcx> for rustc_abi::ReprFlags {
+    type T = ReprFlags;
+
+    fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
+        ReprFlags {
+            is_simd: self.intersects(Self::IS_SIMD),
+            is_c: self.intersects(Self::IS_C),
+            is_transparent: self.intersects(Self::IS_TRANSPARENT),
+            is_linear: self.intersects(Self::IS_LINEAR),
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_abi::IntegerType {
+    type T = IntegerType;
+
+    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+        match self {
+            rustc_abi::IntegerType::Pointer(signed) => IntegerType::Pointer { is_signed: *signed },
+            rustc_abi::IntegerType::Fixed(integer, signed) => {
+                IntegerType::Fixed { length: integer.stable(tables), is_signed: *signed }
+            }
+        }
+    }
+}
+
+impl<'tcx> Stable<'tcx> for rustc_abi::ReprOptions {
+    type T = ReprOptions;
+
+    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+        ReprOptions {
+            int: self.int.map(|int| int.stable(tables)),
+            align: self.align.map(|align| align.stable(tables)),
+            pack: self.pack.map(|pack| pack.stable(tables)),
+            flags: self.flags.stable(tables),
+        }
+    }
+}
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index b0c9dba78a6..6a26f5f7997 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -879,6 +879,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::ExternAbi {
             ExternAbi::RustCold => Abi::RustCold,
             ExternAbi::RiscvInterruptM => Abi::RiscvInterruptM,
             ExternAbi::RiscvInterruptS => Abi::RiscvInterruptS,
+            ExternAbi::Custom => Abi::Custom,
         }
     }
 }
diff --git a/compiler/rustc_smir/src/stable_mir/abi.rs b/compiler/rustc_smir/src/stable_mir/abi.rs
index 3842cb7e653..d8a2b97662c 100644
--- a/compiler/rustc_smir/src/stable_mir/abi.rs
+++ b/compiler/rustc_smir/src/stable_mir/abi.rs
@@ -430,6 +430,8 @@ pub enum CallConvention {
     PreserveMost,
     PreserveAll,
 
+    Custom,
+
     // Target-specific calling conventions.
     ArmAapcs,
     CCmseNonSecureCall,
@@ -455,3 +457,38 @@ pub enum CallConvention {
 
     RiscvInterrupt,
 }
+
+#[non_exhaustive]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
+pub struct ReprFlags {
+    pub is_simd: bool,
+    pub is_c: bool,
+    pub is_transparent: bool,
+    pub is_linear: bool,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
+pub enum IntegerType {
+    /// Pointer-sized integer type, i.e. `isize` and `usize`.
+    Pointer {
+        /// Signedness. e.g. `true` for `isize`
+        is_signed: bool,
+    },
+    /// Fixed-sized integer type, e.g. `i8`, `u32`, `i128`.
+    Fixed {
+        /// Length of this integer type. e.g. `IntegerLength::I8` for `u8`.
+        length: IntegerLength,
+        /// Signedness. e.g. `false` for `u8`
+        is_signed: bool,
+    },
+}
+
+/// Representation options provided by the user
+#[non_exhaustive]
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
+pub struct ReprOptions {
+    pub int: Option<IntegerType>,
+    pub align: Option<Align>,
+    pub pack: Option<Align>,
+    pub flags: ReprFlags,
+}
diff --git a/compiler/rustc_smir/src/stable_mir/compiler_interface.rs b/compiler/rustc_smir/src/stable_mir/compiler_interface.rs
index bb35e23a728..3967ad13eeb 100644
--- a/compiler/rustc_smir/src/stable_mir/compiler_interface.rs
+++ b/compiler/rustc_smir/src/stable_mir/compiler_interface.rs
@@ -6,7 +6,7 @@
 use std::cell::Cell;
 
 use rustc_smir::context::SmirCtxt;
-use stable_mir::abi::{FnAbi, Layout, LayoutShape};
+use stable_mir::abi::{FnAbi, Layout, LayoutShape, ReprOptions};
 use stable_mir::crate_def::Attribute;
 use stable_mir::mir::alloc::{AllocId, GlobalAlloc};
 use stable_mir::mir::mono::{Instance, InstanceDef, StaticDef};
@@ -200,6 +200,11 @@ impl<'tcx> SmirInterface<'tcx> {
         self.cx.adt_is_cstr(def)
     }
 
+    /// Returns the representation options for this ADT
+    pub(crate) fn adt_repr(&self, def: AdtDef) -> ReprOptions {
+        self.cx.adt_repr(def)
+    }
+
     /// Retrieve the function signature for the given generic arguments.
     pub(crate) fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig {
         self.cx.fn_sig(def, args)
diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs
index e331e593471..2934af31cd5 100644
--- a/compiler/rustc_smir/src/stable_mir/ty.rs
+++ b/compiler/rustc_smir/src/stable_mir/ty.rs
@@ -9,6 +9,7 @@ use stable_mir::mir::mono::StaticDef;
 use stable_mir::target::MachineInfo;
 use stable_mir::{Filename, Opaque};
 
+use super::abi::ReprOptions;
 use super::mir::{Body, Mutability, Safety};
 use super::{DefId, Error, Symbol, with};
 use crate::stable_mir;
@@ -742,6 +743,14 @@ crate_def! {
     pub ClosureDef;
 }
 
+impl ClosureDef {
+    /// Retrieves the body of the closure definition. Returns None if the body
+    /// isn't available.
+    pub fn body(&self) -> Option<Body> {
+        with(|ctx| ctx.has_body(self.0).then(|| ctx.mir_body(self.0)))
+    }
+}
+
 crate_def! {
     #[derive(Serialize)]
     pub CoroutineDef;
@@ -818,6 +827,10 @@ impl AdtDef {
     pub fn variant(&self, idx: VariantIdx) -> Option<VariantDef> {
         (idx.to_index() < self.num_variants()).then_some(VariantDef { idx, adt_def: *self })
     }
+
+    pub fn repr(&self) -> ReprOptions {
+        with(|cx| cx.adt_repr(*self))
+    }
 }
 
 /// Definition of a variant, which can be either a struct / union field or an enum variant.
@@ -1098,6 +1111,7 @@ pub enum Abi {
     RustCold,
     RiscvInterruptM,
     RiscvInterruptS,
+    Custom,
 }
 
 /// A binder represents a possibly generic type and its bound vars.
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index b621920d62b..315dedec107 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -1135,7 +1135,7 @@ impl ExpnKind {
 }
 
 /// The kind of macro invocation or definition.
-#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable, Hash, Debug)]
 #[derive(HashStable_Generic)]
 pub enum MacroKind {
     /// A bang macro `foo!()`.
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index d66f98871b9..cb9ccf4cc3f 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -407,6 +407,7 @@ symbols! {
         abi_amdgpu_kernel,
         abi_avr_interrupt,
         abi_c_cmse_nonsecure_call,
+        abi_custom,
         abi_efiapi,
         abi_gpu_kernel,
         abi_msp430_interrupt,
@@ -429,6 +430,8 @@ symbols! {
         aggregate_raw_ptr,
         alias,
         align,
+        align_of,
+        align_of_val,
         alignment,
         all,
         alloc,
@@ -1353,8 +1356,6 @@ symbols! {
         message,
         meta,
         metadata_type,
-        min_align_of,
-        min_align_of_val,
         min_const_fn,
         min_const_generics,
         min_const_unsafe_fn,
@@ -1512,6 +1513,7 @@ symbols! {
         offset_of_nested,
         offset_of_slice,
         ok_or_else,
+        old_name,
         omit_gdb_pretty_printer_section,
         on,
         on_unimplemented,
@@ -2288,6 +2290,7 @@ symbols! {
         usize_legacy_fn_max_value,
         usize_legacy_fn_min_value,
         usize_legacy_mod,
+        v1,
         v8plus,
         va_arg,
         va_copy,
@@ -2675,7 +2678,7 @@ impl Interner {
         assert_eq!(
             strings.len(),
             init.len() + extra.len(),
-            "`init` or `extra` contain duplicate symbols",
+            "there are duplicate symbols in the rustc symbol list and the extra symbols added by the driver",
         );
         Interner(Lock::new(InternerInner { arena: Default::default(), strings }))
     }
diff --git a/compiler/rustc_target/src/asm/loongarch.rs b/compiler/rustc_target/src/asm/loongarch.rs
index b4ea6fc592a..8783d3953b1 100644
--- a/compiler/rustc_target/src/asm/loongarch.rs
+++ b/compiler/rustc_target/src/asm/loongarch.rs
@@ -34,11 +34,13 @@ impl LoongArchInlineAsmRegClass {
 
     pub fn supported_types(
         self,
-        _arch: InlineAsmArch,
+        arch: InlineAsmArch,
     ) -> &'static [(InlineAsmType, Option<Symbol>)] {
-        match self {
-            Self::reg => types! { _: I8, I16, I32, I64, F32, F64; },
-            Self::freg => types! { f: F32; d: F64; },
+        match (self, arch) {
+            (Self::reg, InlineAsmArch::LoongArch64) => types! { _: I8, I16, I32, I64, F32, F64; },
+            (Self::reg, InlineAsmArch::LoongArch32) => types! { _: I8, I16, I32, F32; },
+            (Self::freg, _) => types! { f: F32; d: F64; },
+            _ => unreachable!("unsupported register class"),
         }
     }
 }
diff --git a/compiler/rustc_target/src/spec/abi_map.rs b/compiler/rustc_target/src/spec/abi_map.rs
index c4978a8e52a..4659bbdb890 100644
--- a/compiler/rustc_target/src/spec/abi_map.rs
+++ b/compiler/rustc_target/src/spec/abi_map.rs
@@ -71,6 +71,8 @@ impl AbiMap {
             (ExternAbi::RustCold, _) if self.os == OsKind::Windows => CanonAbi::Rust,
             (ExternAbi::RustCold, _) => CanonAbi::RustCold,
 
+            (ExternAbi::Custom, _) => CanonAbi::Custom,
+
             (ExternAbi::System { .. }, Arch::X86) if os == OsKind::Windows && !has_c_varargs => {
                 CanonAbi::X86(X86Call::Stdcall)
             }
diff --git a/compiler/rustc_target/src/spec/base/xtensa.rs b/compiler/rustc_target/src/spec/base/xtensa.rs
index 47a532dfdd4..a7cc748973c 100644
--- a/compiler/rustc_target/src/spec/base/xtensa.rs
+++ b/compiler/rustc_target/src/spec/base/xtensa.rs
@@ -6,7 +6,7 @@ pub(crate) fn opts() -> TargetOptions {
     TargetOptions {
         os: "none".into(),
         endian: Endian::Little,
-        c_int_width: "32".into(),
+        c_int_width: 32,
         linker_flavor: LinkerFlavor::Gnu(Cc::Yes, Lld::No),
         executables: true,
         panic_strategy: PanicStrategy::Abort,
diff --git a/compiler/rustc_target/src/spec/json.rs b/compiler/rustc_target/src/spec/json.rs
index 039056a5a25..6c716f87125 100644
--- a/compiler/rustc_target/src/spec/json.rs
+++ b/compiler/rustc_target/src/spec/json.rs
@@ -80,6 +80,12 @@ impl Target {
                     base.$key_name = s;
                 }
             } );
+            ($key_name:ident = $json_name:expr, u64 as $int_ty:ty) => ( {
+                let name = $json_name;
+                if let Some(s) = obj.remove(name).and_then(|b| b.as_u64()) {
+                    base.$key_name = s as $int_ty;
+                }
+            } );
             ($key_name:ident, bool) => ( {
                 let name = (stringify!($key_name)).replace("_", "-");
                 if let Some(s) = obj.remove(&name).and_then(|b| b.as_bool()) {
@@ -554,7 +560,7 @@ impl Target {
             }
         }
 
-        key!(c_int_width = "target-c-int-width");
+        key!(c_int_width = "target-c-int-width", u64 as u16);
         key!(c_enum_min_bits, Option<u64>); // if None, matches c_int_width
         key!(os);
         key!(env);
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 6ceb5e80f21..c360fe63a00 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -2213,18 +2213,10 @@ impl Target {
             });
         }
 
-        dl.c_enum_min_size = self
-            .c_enum_min_bits
-            .map_or_else(
-                || {
-                    self.c_int_width
-                        .parse()
-                        .map_err(|_| String::from("failed to parse c_int_width"))
-                },
-                Ok,
-            )
-            .and_then(|i| Integer::from_size(Size::from_bits(i)))
-            .map_err(|err| TargetDataLayoutErrors::InvalidBitsSize { err })?;
+        dl.c_enum_min_size = Integer::from_size(Size::from_bits(
+            self.c_enum_min_bits.unwrap_or(self.c_int_width as _),
+        ))
+        .map_err(|err| TargetDataLayoutErrors::InvalidBitsSize { err })?;
 
         Ok(dl)
     }
@@ -2286,7 +2278,7 @@ pub struct TargetOptions {
     /// Used as the `target_endian` `cfg` variable. Defaults to little endian.
     pub endian: Endian,
     /// Width of c_int type. Defaults to "32".
-    pub c_int_width: StaticCow<str>,
+    pub c_int_width: u16,
     /// OS name to use for conditional compilation (`target_os`). Defaults to "none".
     /// "none" implies a bare metal target without `std` library.
     /// A couple of targets having `std` also use "unknown" as an `os` value,
@@ -2783,7 +2775,7 @@ impl Default for TargetOptions {
     fn default() -> TargetOptions {
         TargetOptions {
             endian: Endian::Little,
-            c_int_width: "32".into(),
+            c_int_width: 32,
             os: "none".into(),
             env: "".into(),
             abi: "".into(),
diff --git a/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs
index 6a83835059e..4902dc37d13 100644
--- a/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7_sony_vita_newlibeabihf.rs
@@ -31,7 +31,7 @@ pub(crate) fn target() -> Target {
         options: TargetOptions {
             os: "vita".into(),
             endian: Endian::Little,
-            c_int_width: "32".into(),
+            c_int_width: 32,
             env: "newlib".into(),
             vendor: "sony".into(),
             abi: "eabihf".into(),
diff --git a/compiler/rustc_target/src/spec/targets/avr_none.rs b/compiler/rustc_target/src/spec/targets/avr_none.rs
index 91d3197d099..07ed2a37803 100644
--- a/compiler/rustc_target/src/spec/targets/avr_none.rs
+++ b/compiler/rustc_target/src/spec/targets/avr_none.rs
@@ -13,7 +13,7 @@ pub(crate) fn target() -> Target {
         llvm_target: "avr-unknown-unknown".into(),
         pointer_width: 16,
         options: TargetOptions {
-            c_int_width: "16".into(),
+            c_int_width: 16,
             exe_suffix: ".elf".into(),
             linker: Some("avr-gcc".into()),
             eh_frame_header: false,
diff --git a/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs b/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs
index b067ac1e54a..caf77bb8669 100644
--- a/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs
+++ b/compiler/rustc_target/src/spec/targets/msp430_none_elf.rs
@@ -16,7 +16,7 @@ pub(crate) fn target() -> Target {
         arch: "msp430".into(),
 
         options: TargetOptions {
-            c_int_width: "16".into(),
+            c_int_width: 16,
 
             // The LLVM backend currently can't generate object files. To
             // workaround this LLVM generates assembly files which then we feed
diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs
index c5b4d472fad..8a6773811e8 100644
--- a/compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs
+++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32_espidf.rs
@@ -13,7 +13,7 @@ pub(crate) fn target() -> Target {
 
         options: TargetOptions {
             endian: Endian::Little,
-            c_int_width: "32".into(),
+            c_int_width: 32,
             families: cvs!["unix"],
             os: "espidf".into(),
             env: "newlib".into(),
diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs
index cffdaa90727..f38d771f257 100644
--- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs
+++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s2_espidf.rs
@@ -13,7 +13,7 @@ pub(crate) fn target() -> Target {
 
         options: TargetOptions {
             endian: Endian::Little,
-            c_int_width: "32".into(),
+            c_int_width: 32,
             families: cvs!["unix"],
             os: "espidf".into(),
             env: "newlib".into(),
diff --git a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs
index 2e4afc00541..4ec6e319fd4 100644
--- a/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs
+++ b/compiler/rustc_target/src/spec/targets/xtensa_esp32s3_espidf.rs
@@ -13,7 +13,7 @@ pub(crate) fn target() -> Target {
 
         options: TargetOptions {
             endian: Endian::Little,
-            c_int_width: "32".into(),
+            c_int_width: 32,
             families: cvs!["unix"],
             os: "espidf".into(),
             env: "newlib".into(),
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index d48a599f544..a1eac1fba25 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -34,6 +34,9 @@ pub enum Stability {
     /// particular for features are actually ABI configuration flags (not all targets are as nice as
     /// RISC-V and have an explicit way to set the ABI separate from target features).
     Forbidden { reason: &'static str },
+    /// This feature can not be set via `-Ctarget-feature` or `#[target_feature]`, it can only be set
+    /// by target modifier flag. Target modifier flags are tracked to be consistent in linked modules.
+    TargetModifierOnly { reason: &'static str, flag: &'static str },
 }
 use Stability::*;
 
@@ -49,6 +52,7 @@ impl<CTX> HashStable<CTX> for Stability {
             Stability::Forbidden { reason } => {
                 reason.hash_stable(hcx, hasher);
             }
+            Stability::TargetModifierOnly { .. } => {}
         }
     }
 }
@@ -74,16 +78,7 @@ impl Stability {
             Stability::Unstable(nightly_feature) => Some(nightly_feature),
             Stability::Stable { .. } => None,
             Stability::Forbidden { .. } => panic!("forbidden features should not reach this far"),
-        }
-    }
-
-    /// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`.
-    /// (It might still be nightly-only even if this returns `true`, so make sure to also check
-    /// `requires_nightly`.)
-    pub fn toggle_allowed(&self) -> Result<(), &'static str> {
-        match self {
-            Stability::Forbidden { reason } => Err(reason),
-            _ => Ok(()),
+            Stability::TargetModifierOnly { .. } => None,
         }
     }
 }
@@ -443,7 +438,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, &[]),
@@ -453,6 +448,30 @@ static X86_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     ("prfchw", Unstable(sym::prfchw_target_feature), &[]),
     ("rdrand", Stable, &[]),
     ("rdseed", Stable, &[]),
+    (
+        "retpoline-external-thunk",
+        Stability::TargetModifierOnly {
+            reason: "use `retpoline-external-thunk` target modifier flag instead",
+            flag: "retpoline-external-thunk",
+        },
+        &[],
+    ),
+    (
+        "retpoline-indirect-branches",
+        Stability::TargetModifierOnly {
+            reason: "use `retpoline` target modifier flag instead",
+            flag: "retpoline",
+        },
+        &[],
+    ),
+    (
+        "retpoline-indirect-calls",
+        Stability::TargetModifierOnly {
+            reason: "use `retpoline` target modifier flag instead",
+            flag: "retpoline",
+        },
+        &[],
+    ),
     ("rtm", Unstable(sym::rtm_target_feature), &[]),
     ("sha", Stable, &["sse2"]),
     ("sha512", Stable, &["avx2"]),
@@ -471,7 +490,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/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index fc5be111144..0c88bd3dcbc 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -2558,32 +2558,31 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         rustc_transmute::Reason::SrcIsNotYetSupported => {
                             format!("analyzing the transmutability of `{src}` is not yet supported")
                         }
-
                         rustc_transmute::Reason::DstIsNotYetSupported => {
                             format!("analyzing the transmutability of `{dst}` is not yet supported")
                         }
-
                         rustc_transmute::Reason::DstIsBitIncompatible => {
                             format!(
                                 "at least one value of `{src}` isn't a bit-valid value of `{dst}`"
                             )
                         }
-
                         rustc_transmute::Reason::DstUninhabited => {
                             format!("`{dst}` is uninhabited")
                         }
-
                         rustc_transmute::Reason::DstMayHaveSafetyInvariants => {
                             format!("`{dst}` may carry safety invariants")
                         }
                         rustc_transmute::Reason::DstIsTooBig => {
                             format!("the size of `{src}` is smaller than the size of `{dst}`")
                         }
-                        rustc_transmute::Reason::DstRefIsTooBig { src, dst } => {
-                            let src_size = src.size;
-                            let dst_size = dst.size;
+                        rustc_transmute::Reason::DstRefIsTooBig {
+                            src,
+                            src_size,
+                            dst,
+                            dst_size,
+                        } => {
                             format!(
-                                "the referent size of `{src}` ({src_size} bytes) \
+                                "the size of `{src}` ({src_size} bytes) \
                         is smaller than that of `{dst}` ({dst_size} bytes)"
                             )
                         }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
index 37968386e9a..89dab90dc68 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
@@ -810,7 +810,8 @@ impl<'tcx> OnUnimplementedFormatString {
 
         let mut result = Ok(());
 
-        match FormatString::parse(self.symbol, self.span, &ctx) {
+        let snippet = tcx.sess.source_map().span_to_snippet(self.span).ok();
+        match FormatString::parse(self.symbol, snippet, self.span, &ctx) {
             // Warnings about format specifiers, deprecated parameters, wrong parameters etc.
             // In other words we'd like to let the author know, but we can still try to format the string later
             Ok(FormatString { warnings, .. }) => {
@@ -848,34 +849,27 @@ impl<'tcx> OnUnimplementedFormatString {
                     }
                 }
             }
-            // Errors from the underlying `rustc_parse_format::Parser`
-            Err(errors) => {
+            // Error from the underlying `rustc_parse_format::Parser`
+            Err(e) => {
                 // we cannot return errors from processing the format string as hard error here
                 // as the diagnostic namespace guarantees that malformed input cannot cause an error
                 //
                 // if we encounter any error while processing we nevertheless want to show it as warning
                 // so that users are aware that something is not correct
-                for e in errors {
-                    if self.is_diagnostic_namespace_variant {
-                        if let Some(trait_def_id) = trait_def_id.as_local() {
-                            tcx.emit_node_span_lint(
-                                UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
-                                tcx.local_def_id_to_hir_id(trait_def_id),
-                                self.span,
-                                WrappedParserError { description: e.description, label: e.label },
-                            );
-                        }
-                    } else {
-                        let reported = struct_span_code_err!(
-                            tcx.dcx(),
+                if self.is_diagnostic_namespace_variant {
+                    if let Some(trait_def_id) = trait_def_id.as_local() {
+                        tcx.emit_node_span_lint(
+                            UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                            tcx.local_def_id_to_hir_id(trait_def_id),
                             self.span,
-                            E0231,
-                            "{}",
-                            e.description,
-                        )
-                        .emit();
-                        result = Err(reported);
+                            WrappedParserError { description: e.description, label: e.label },
+                        );
                     }
+                } else {
+                    let reported =
+                        struct_span_code_err!(tcx.dcx(), self.span, E0231, "{}", e.description,)
+                            .emit();
+                    result = Err(reported);
                 }
             }
         }
@@ -896,7 +890,8 @@ impl<'tcx> OnUnimplementedFormatString {
             Ctx::RustcOnUnimplemented { tcx, trait_def_id }
         };
 
-        if let Ok(s) = FormatString::parse(self.symbol, self.span, &ctx) {
+        // No point passing a snippet here, we already did that in `verify`
+        if let Ok(s) = FormatString::parse(self.symbol, None, self.span, &ctx) {
             s.format(args)
         } else {
             // we cannot return errors from processing the format string as hard error here
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs
index e8ea9f2d23e..171d05230d4 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs
@@ -198,7 +198,7 @@ enum LitOrArg {
 
 impl FilterFormatString {
     fn parse(input: Symbol) -> Self {
-        let pieces = Parser::new(input.as_str(), None, None, false, ParseMode::Format)
+        let pieces = Parser::new(input.as_str(), None, None, false, ParseMode::Diagnostic)
             .map(|p| match p {
                 Piece::Lit(s) => LitOrArg::Lit(s.to_owned()),
                 // We just ignore formatspecs here
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs
index 7c1dfc1728f..3e8b906fa93 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs
@@ -5,12 +5,11 @@ use errors::*;
 use rustc_middle::ty::print::TraitRefPrintSugared;
 use rustc_middle::ty::{GenericParamDefKind, TyCtxt};
 use rustc_parse_format::{
-    Alignment, Argument, Count, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece,
-    Position,
+    Argument, FormatSpec, ParseError, ParseMode, Parser, Piece as RpfPiece, Position,
 };
 use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
 use rustc_span::def_id::DefId;
-use rustc_span::{BytePos, Pos, Span, Symbol, kw, sym};
+use rustc_span::{InnerSpan, Span, Symbol, kw, sym};
 
 /// Like [std::fmt::Arguments] this is a string that has been parsed into "pieces",
 /// either as string pieces or dynamic arguments.
@@ -160,32 +159,32 @@ impl FormatString {
 
     pub fn parse<'tcx>(
         input: Symbol,
+        snippet: Option<String>,
         span: Span,
         ctx: &Ctx<'tcx>,
-    ) -> Result<Self, Vec<ParseError>> {
+    ) -> Result<Self, ParseError> {
         let s = input.as_str();
-        let mut parser = Parser::new(s, None, None, false, ParseMode::Format);
-        let mut pieces = Vec::new();
+        let mut parser = Parser::new(s, None, snippet, false, ParseMode::Diagnostic);
+        let pieces: Vec<_> = parser.by_ref().collect();
+
+        if let Some(err) = parser.errors.into_iter().next() {
+            return Err(err);
+        }
         let mut warnings = Vec::new();
 
-        for piece in &mut parser {
-            match piece {
-                RpfPiece::Lit(lit) => {
-                    pieces.push(Piece::Lit(lit.into()));
-                }
+        let pieces = pieces
+            .into_iter()
+            .map(|piece| match piece {
+                RpfPiece::Lit(lit) => Piece::Lit(lit.into()),
                 RpfPiece::NextArgument(arg) => {
-                    warn_on_format_spec(arg.format.clone(), &mut warnings, span);
-                    let arg = parse_arg(&arg, ctx, &mut warnings, span);
-                    pieces.push(Piece::Arg(arg));
+                    warn_on_format_spec(&arg.format, &mut warnings, span, parser.is_source_literal);
+                    let arg = parse_arg(&arg, ctx, &mut warnings, span, parser.is_source_literal);
+                    Piece::Arg(arg)
                 }
-            }
-        }
+            })
+            .collect();
 
-        if parser.errors.is_empty() {
-            Ok(FormatString { input, pieces, span, warnings })
-        } else {
-            Err(parser.errors)
-        }
+        Ok(FormatString { input, pieces, span, warnings })
     }
 
     pub fn format(&self, args: &FormatArgs<'_>) -> String {
@@ -229,11 +228,12 @@ fn parse_arg<'tcx>(
     ctx: &Ctx<'tcx>,
     warnings: &mut Vec<FormatWarning>,
     input_span: Span,
+    is_source_literal: bool,
 ) -> FormatArg {
     let (Ctx::RustcOnUnimplemented { tcx, trait_def_id }
     | Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id }) = ctx;
 
-    let span = slice_span(input_span, arg.position_span.clone());
+    let span = slice_span(input_span, arg.position_span.clone(), is_source_literal);
 
     match arg.position {
         // Something like "hello {name}"
@@ -283,39 +283,24 @@ fn parse_arg<'tcx>(
 
 /// `#[rustc_on_unimplemented]` and `#[diagnostic::...]` don't actually do anything
 /// with specifiers, so emit a warning if they are used.
-fn warn_on_format_spec(spec: FormatSpec<'_>, warnings: &mut Vec<FormatWarning>, input_span: Span) {
-    if !matches!(
-        spec,
-        FormatSpec {
-            fill: None,
-            fill_span: None,
-            align: Alignment::AlignUnknown,
-            sign: None,
-            alternate: false,
-            zero_pad: false,
-            debug_hex: None,
-            precision: Count::CountImplied,
-            precision_span: None,
-            width: Count::CountImplied,
-            width_span: None,
-            ty: _,
-            ty_span: _,
-        },
-    ) {
-        let span = spec.ty_span.map(|inner| slice_span(input_span, inner)).unwrap_or(input_span);
+fn warn_on_format_spec(
+    spec: &FormatSpec<'_>,
+    warnings: &mut Vec<FormatWarning>,
+    input_span: Span,
+    is_source_literal: bool,
+) {
+    if spec.ty != "" {
+        let span = spec
+            .ty_span
+            .as_ref()
+            .map(|inner| slice_span(input_span, inner.clone(), is_source_literal))
+            .unwrap_or(input_span);
         warnings.push(FormatWarning::InvalidSpecifier { span, name: spec.ty.into() })
     }
 }
 
-fn slice_span(input: Span, range: Range<usize>) -> Span {
-    let span = input.data();
-
-    Span::new(
-        span.lo + BytePos::from_usize(range.start),
-        span.lo + BytePos::from_usize(range.end),
-        span.ctxt,
-        span.parent,
-    )
+fn slice_span(input: Span, Range { start, end }: Range<usize>, is_source_literal: bool) -> Span {
+    if is_source_literal { input.from_inner(InnerSpan { start, end }) } else { input }
 }
 
 pub mod errors {
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 06f81ac554e..7bf49056e29 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -759,7 +759,8 @@ pub enum ExplicitLifetimeRequired<'a> {
         #[suggestion(
             trait_selection_explicit_lifetime_required_sugg_with_ident,
             code = "{new_ty}",
-            applicability = "unspecified"
+            applicability = "unspecified",
+            style = "verbose"
         )]
         new_ty_span: Span,
         #[skip_arg]
@@ -774,7 +775,8 @@ pub enum ExplicitLifetimeRequired<'a> {
         #[suggestion(
             trait_selection_explicit_lifetime_required_sugg_with_param_type,
             code = "{new_ty}",
-            applicability = "unspecified"
+            applicability = "unspecified",
+            style = "verbose"
         )]
         new_ty_span: Span,
         #[skip_arg]
@@ -1462,7 +1464,8 @@ pub enum SuggestAccessingField<'a> {
     #[suggestion(
         trait_selection_suggest_accessing_field,
         code = "{snippet}.{name}",
-        applicability = "maybe-incorrect"
+        applicability = "maybe-incorrect",
+        style = "verbose"
     )]
     Safe {
         #[primary_span]
@@ -1474,7 +1477,8 @@ pub enum SuggestAccessingField<'a> {
     #[suggestion(
         trait_selection_suggest_accessing_field,
         code = "unsafe {{ {snippet}.{name} }}",
-        applicability = "maybe-incorrect"
+        applicability = "maybe-incorrect",
+        style = "verbose"
     )]
     Unsafe {
         #[primary_span]
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index d5d318ee490..b0c8fa1f217 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -11,7 +11,8 @@
 
 use std::assert_matches::assert_matches;
 
-use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
+use rustc_infer::infer::InferCtxt;
+use rustc_infer::traits::Obligation;
 use rustc_macros::extension;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult};
@@ -20,7 +21,7 @@ use rustc_middle::{bug, ty};
 use rustc_next_trait_solver::resolve::eager_resolve_vars;
 use rustc_next_trait_solver::solve::inspect::{self, instantiate_canonical_state};
 use rustc_next_trait_solver::solve::{GenerateProofTree, MaybeCause, SolverDelegateEvalExt as _};
-use rustc_span::{DUMMY_SP, Span};
+use rustc_span::Span;
 use tracing::instrument;
 
 use crate::solve::delegate::SolverDelegate;
@@ -60,28 +61,29 @@ impl<'tcx> NormalizesToTermHack<'tcx> {
     /// Relate the `term` with the new `unconstrained_term` created
     /// when computing the proof tree for this `NormalizesTo` goals.
     /// This handles nested obligations.
-    fn constrain(
-        self,
+    fn constrain_and(
+        &self,
         infcx: &InferCtxt<'tcx>,
         span: Span,
         param_env: ty::ParamEnv<'tcx>,
+        f: impl FnOnce(&ObligationCtxt<'_, 'tcx>),
     ) -> Result<Certainty, NoSolution> {
-        infcx
-            .at(&ObligationCause::dummy_with_span(span), param_env)
-            .eq(DefineOpaqueTypes::Yes, self.term, self.unconstrained_term)
-            .map_err(|_| NoSolution)
-            .and_then(|InferOk { value: (), obligations }| {
-                let ocx = ObligationCtxt::new(infcx);
-                ocx.register_obligations(obligations);
-                let errors = ocx.select_all_or_error();
-                if errors.is_empty() {
-                    Ok(Certainty::Yes)
-                } else if errors.iter().all(|e| !e.is_true_error()) {
-                    Ok(Certainty::AMBIGUOUS)
-                } else {
-                    Err(NoSolution)
-                }
-            })
+        let ocx = ObligationCtxt::new(infcx);
+        ocx.eq(
+            &ObligationCause::dummy_with_span(span),
+            param_env,
+            self.term,
+            self.unconstrained_term,
+        )?;
+        f(&ocx);
+        let errors = ocx.select_all_or_error();
+        if errors.is_empty() {
+            Ok(Certainty::Yes)
+        } else if errors.iter().all(|e| !e.is_true_error()) {
+            Ok(Certainty::AMBIGUOUS)
+        } else {
+            Err(NoSolution)
+        }
     }
 }
 
@@ -160,11 +162,11 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
         let () =
             instantiate_canonical_state(infcx, span, param_env, &mut orig_values, self.final_state);
 
-        if let Some(term_hack) = self.goal.normalizes_to_term_hack {
+        if let Some(term_hack) = &self.goal.normalizes_to_term_hack {
             // FIXME: We ignore the expected term of `NormalizesTo` goals
             // when computing the result of its candidates. This is
             // scuffed.
-            let _ = term_hack.constrain(infcx, span, param_env);
+            let _ = term_hack.constrain_and(infcx, span, param_env, |_| {});
         }
 
         instantiated_goals
@@ -240,13 +242,39 @@ impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
                 // building their proof tree, the expected term was unconstrained, but when
                 // instantiating the candidate it is already constrained to the result of another
                 // candidate.
-                let proof_tree = infcx
-                    .probe(|_| infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes, None).1);
+                let normalizes_to_term_hack = NormalizesToTermHack { term, unconstrained_term };
+                let (proof_tree, nested_goals_result) = infcx.probe(|_| {
+                    // Here, if we have any nested goals, then we make sure to apply them
+                    // considering the constrained RHS, and pass the resulting certainty to
+                    // `InspectGoal::new` so that the goal has the right result (and maintains
+                    // the impression that we don't do this normalizes-to infer hack at all).
+                    let (nested, proof_tree) =
+                        infcx.evaluate_root_goal_raw(goal, GenerateProofTree::Yes, None);
+                    let proof_tree = proof_tree.unwrap();
+                    let nested_goals_result = nested.and_then(|(nested, _)| {
+                        normalizes_to_term_hack.constrain_and(
+                            infcx,
+                            span,
+                            proof_tree.uncanonicalized_goal.param_env,
+                            |ocx| {
+                                ocx.register_obligations(nested.0.into_iter().map(|(_, goal)| {
+                                    Obligation::new(
+                                        infcx.tcx,
+                                        ObligationCause::dummy_with_span(span),
+                                        goal.param_env,
+                                        goal.predicate,
+                                    )
+                                }));
+                            },
+                        )
+                    });
+                    (proof_tree, nested_goals_result)
+                });
                 InspectGoal::new(
                     infcx,
                     self.goal.depth + 1,
-                    proof_tree.unwrap(),
-                    Some(NormalizesToTermHack { term, unconstrained_term }),
+                    proof_tree,
+                    Some((normalizes_to_term_hack, nested_goals_result)),
                     source,
                 )
             }
@@ -393,20 +421,21 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
         infcx: &'a InferCtxt<'tcx>,
         depth: usize,
         root: inspect::GoalEvaluation<TyCtxt<'tcx>>,
-        normalizes_to_term_hack: Option<NormalizesToTermHack<'tcx>>,
+        term_hack_and_nested_certainty: Option<(
+            NormalizesToTermHack<'tcx>,
+            Result<Certainty, NoSolution>,
+        )>,
         source: GoalSource,
     ) -> Self {
         let infcx = <&SolverDelegate<'tcx>>::from(infcx);
 
         let inspect::GoalEvaluation { uncanonicalized_goal, orig_values, evaluation } = root;
+        // If there's a normalizes-to goal, AND the evaluation result with the result of
+        // constraining the normalizes-to RHS and computing the nested goals.
         let result = evaluation.result.and_then(|ok| {
-            if let Some(term_hack) = normalizes_to_term_hack {
-                infcx
-                    .probe(|_| term_hack.constrain(infcx, DUMMY_SP, uncanonicalized_goal.param_env))
-                    .map(|certainty| ok.value.certainty.and(certainty))
-            } else {
-                Ok(ok.value.certainty)
-            }
+            let nested_goals_certainty =
+                term_hack_and_nested_certainty.map_or(Ok(Certainty::Yes), |(_, c)| c)?;
+            Ok(ok.value.certainty.and(nested_goals_certainty))
         });
 
         InspectGoal {
@@ -416,7 +445,7 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
             goal: eager_resolve_vars(infcx, uncanonicalized_goal),
             result,
             evaluation_kind: evaluation.kind,
-            normalizes_to_term_hack,
+            normalizes_to_term_hack: term_hack_and_nested_certainty.map(|(n, _)| n),
             source,
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs
index eb6d5c8a60a..35a43b294ee 100644
--- a/compiler/rustc_trait_selection/src/traits/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/normalize.rs
@@ -47,7 +47,7 @@ impl<'tcx> At<'_, 'tcx> {
     /// same goals in both a temporary and the shared context which negatively impacts
     /// performance as these don't share caching.
     ///
-    /// FIXME(-Znext-solver): For performance reasons, we currently reuse an existing
+    /// FIXME(-Znext-solver=no): For performance reasons, we currently reuse an existing
     /// fulfillment context in the old solver. Once we have removed the old solver, we
     /// can remove the `fulfill_cx` parameter on this function.
     fn deeply_normalize<T, E>(
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 7acf0f990d1..786afd7cf48 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -9,13 +9,12 @@
 
 use std::ops::ControlFlow;
 
-use rustc_ast::Mutability;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::{DefineOpaqueTypes, HigherRankedType, InferOk};
 use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
-use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, Upcast, elaborate};
+use rustc_middle::ty::{self, GenericArgsRef, Region, Ty, TyCtxt, Upcast, elaborate};
 use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::DefId;
 use thin_vec::thin_vec;
@@ -286,99 +285,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ) -> Result<PredicateObligations<'tcx>, SelectionError<'tcx>> {
         use rustc_transmute::{Answer, Assume, Condition};
 
-        /// Generate sub-obligations for reference-to-reference transmutations.
-        fn reference_obligations<'tcx>(
-            tcx: TyCtxt<'tcx>,
-            obligation: &PolyTraitObligation<'tcx>,
-            (src_lifetime, src_ty, src_mut): (ty::Region<'tcx>, Ty<'tcx>, Mutability),
-            (dst_lifetime, dst_ty, dst_mut): (ty::Region<'tcx>, Ty<'tcx>, Mutability),
-            assume: Assume,
-        ) -> PredicateObligations<'tcx> {
-            let make_transmute_obl = |src, dst| {
-                let transmute_trait = obligation.predicate.def_id();
-                let assume = obligation.predicate.skip_binder().trait_ref.args.const_at(2);
-                let trait_ref = ty::TraitRef::new(
-                    tcx,
-                    transmute_trait,
-                    [
-                        ty::GenericArg::from(dst),
-                        ty::GenericArg::from(src),
-                        ty::GenericArg::from(assume),
-                    ],
-                );
-                Obligation::with_depth(
-                    tcx,
-                    obligation.cause.clone(),
-                    obligation.recursion_depth + 1,
-                    obligation.param_env,
-                    trait_ref,
-                )
-            };
-
-            let make_freeze_obl = |ty| {
-                let trait_ref = ty::TraitRef::new(
-                    tcx,
-                    tcx.require_lang_item(LangItem::Freeze, obligation.cause.span),
-                    [ty::GenericArg::from(ty)],
-                );
-                Obligation::with_depth(
-                    tcx,
-                    obligation.cause.clone(),
-                    obligation.recursion_depth + 1,
-                    obligation.param_env,
-                    trait_ref,
-                )
-            };
-
-            let make_outlives_obl = |target, region| {
-                let outlives = ty::OutlivesPredicate(target, region);
-                Obligation::with_depth(
-                    tcx,
-                    obligation.cause.clone(),
-                    obligation.recursion_depth + 1,
-                    obligation.param_env,
-                    outlives,
-                )
-            };
-
-            // Given a transmutation from `&'a (mut) Src` and `&'dst (mut) Dst`,
-            // it is always the case that `Src` must be transmutable into `Dst`,
-            // and that that `'src` must outlive `'dst`.
-            let mut obls = PredicateObligations::with_capacity(1);
-            obls.push(make_transmute_obl(src_ty, dst_ty));
-            if !assume.lifetimes {
-                obls.push(make_outlives_obl(src_lifetime, dst_lifetime));
-            }
-
-            // Given a transmutation from `&Src`, both `Src` and `Dst` must be
-            // `Freeze`, otherwise, using the transmuted value could lead to
-            // data races.
-            if src_mut == Mutability::Not {
-                obls.extend([make_freeze_obl(src_ty), make_freeze_obl(dst_ty)])
-            }
-
-            // Given a transmutation into `&'dst mut Dst`, it also must be the
-            // case that `Dst` is transmutable into `Src`. For example,
-            // transmuting bool -> u8 is OK as long as you can't update that u8
-            // to be > 1, because you could later transmute the u8 back to a
-            // bool and get undefined behavior. It also must be the case that
-            // `'dst` lives exactly as long as `'src`.
-            if dst_mut == Mutability::Mut {
-                obls.push(make_transmute_obl(dst_ty, src_ty));
-                if !assume.lifetimes {
-                    obls.push(make_outlives_obl(dst_lifetime, src_lifetime));
-                }
-            }
-
-            obls
-        }
-
         /// Flatten the `Condition` tree into a conjunction of obligations.
         #[instrument(level = "debug", skip(tcx, obligation))]
         fn flatten_answer_tree<'tcx>(
             tcx: TyCtxt<'tcx>,
             obligation: &PolyTraitObligation<'tcx>,
-            cond: Condition<rustc_transmute::layout::rustc::Ref<'tcx>>,
+            cond: Condition<Region<'tcx>, Ty<'tcx>>,
             assume: Assume,
         ) -> PredicateObligations<'tcx> {
             match cond {
@@ -388,13 +300,50 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     .into_iter()
                     .flat_map(|cond| flatten_answer_tree(tcx, obligation, cond, assume))
                     .collect(),
-                Condition::IfTransmutable { src, dst } => reference_obligations(
-                    tcx,
-                    obligation,
-                    (src.lifetime, src.ty, src.mutability),
-                    (dst.lifetime, dst.ty, dst.mutability),
-                    assume,
-                ),
+                Condition::Immutable { ty } => {
+                    let trait_ref = ty::TraitRef::new(
+                        tcx,
+                        tcx.require_lang_item(LangItem::Freeze, obligation.cause.span),
+                        [ty::GenericArg::from(ty)],
+                    );
+                    thin_vec![Obligation::with_depth(
+                        tcx,
+                        obligation.cause.clone(),
+                        obligation.recursion_depth + 1,
+                        obligation.param_env,
+                        trait_ref,
+                    )]
+                }
+                Condition::Outlives { long, short } => {
+                    let outlives = ty::OutlivesPredicate(long, short);
+                    thin_vec![Obligation::with_depth(
+                        tcx,
+                        obligation.cause.clone(),
+                        obligation.recursion_depth + 1,
+                        obligation.param_env,
+                        outlives,
+                    )]
+                }
+                Condition::Transmutable { src, dst } => {
+                    let transmute_trait = obligation.predicate.def_id();
+                    let assume = obligation.predicate.skip_binder().trait_ref.args.const_at(2);
+                    let trait_ref = ty::TraitRef::new(
+                        tcx,
+                        transmute_trait,
+                        [
+                            ty::GenericArg::from(dst),
+                            ty::GenericArg::from(src),
+                            ty::GenericArg::from(assume),
+                        ],
+                    );
+                    thin_vec![Obligation::with_depth(
+                        tcx,
+                        obligation.cause.clone(),
+                        obligation.recursion_depth + 1,
+                        obligation.param_env,
+                        trait_ref,
+                    )]
+                }
             }
         }
 
diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs
index 88f02d16c7d..a0a1d454556 100644
--- a/compiler/rustc_traits/src/codegen.rs
+++ b/compiler/rustc_traits/src/codegen.rs
@@ -58,7 +58,6 @@ pub(crate) fn codegen_select_candidate<'tcx>(
     // Currently, we use a fulfillment context to completely resolve
     // all nested obligations. This is because they can inform the
     // inference of the impl's type parameters.
-    // FIXME(-Znext-solver): Doesn't need diagnostics if new solver.
     let ocx = ObligationCtxt::new(&infcx);
     let impl_source = selection.map(|obligation| {
         ocx.register_obligation(obligation);
diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs
index 6d072c336af..6fc40ce42d8 100644
--- a/compiler/rustc_transmute/src/layout/dfa.rs
+++ b/compiler/rustc_transmute/src/layout/dfa.rs
@@ -2,32 +2,35 @@ use std::fmt;
 use std::iter::Peekable;
 use std::sync::atomic::{AtomicU32, Ordering};
 
-use super::{Byte, Ref, Tree, Uninhabited};
+use super::{Byte, Reference, Region, Tree, Type, Uninhabited};
 use crate::{Map, Set};
 
 #[derive(PartialEq)]
 #[cfg_attr(test, derive(Clone))]
-pub(crate) struct Dfa<R>
+pub(crate) struct Dfa<R, T>
 where
-    R: Ref,
+    R: Region,
+    T: Type,
 {
-    pub(crate) transitions: Map<State, Transitions<R>>,
+    pub(crate) transitions: Map<State, Transitions<R, T>>,
     pub(crate) start: State,
     pub(crate) accept: State,
 }
 
 #[derive(PartialEq, Clone, Debug)]
-pub(crate) struct Transitions<R>
+pub(crate) struct Transitions<R, T>
 where
-    R: Ref,
+    R: Region,
+    T: Type,
 {
     byte_transitions: EdgeSet<State>,
-    ref_transitions: Map<R, State>,
+    ref_transitions: Map<Reference<R, T>, State>,
 }
 
-impl<R> Default for Transitions<R>
+impl<R, T> Default for Transitions<R, T>
 where
-    R: Ref,
+    R: Region,
+    T: Type,
 {
     fn default() -> Self {
         Self { byte_transitions: EdgeSet::empty(), ref_transitions: Map::default() }
@@ -51,9 +54,10 @@ impl fmt::Debug for State {
     }
 }
 
-impl<R> Dfa<R>
+impl<R, T> Dfa<R, T>
 where
-    R: Ref,
+    R: Region,
+    T: Type,
 {
     #[cfg(test)]
     pub(crate) fn bool() -> Self {
@@ -64,7 +68,7 @@ where
     }
 
     pub(crate) fn unit() -> Self {
-        let transitions: Map<State, Transitions<R>> = Map::default();
+        let transitions: Map<State, Transitions<R, T>> = Map::default();
         let start = State::new();
         let accept = start;
 
@@ -78,21 +82,21 @@ where
         })
     }
 
-    pub(crate) fn from_ref(r: R) -> Self {
+    pub(crate) fn from_ref(r: Reference<R, T>) -> Self {
         Self::from_transitions(|accept| Transitions {
             byte_transitions: EdgeSet::empty(),
             ref_transitions: [(r, accept)].into_iter().collect(),
         })
     }
 
-    fn from_transitions(f: impl FnOnce(State) -> Transitions<R>) -> Self {
+    fn from_transitions(f: impl FnOnce(State) -> Transitions<R, T>) -> Self {
         let start = State::new();
         let accept = State::new();
 
         Self { transitions: [(start, f(accept))].into_iter().collect(), start, accept }
     }
 
-    pub(crate) fn from_tree(tree: Tree<!, R>) -> Result<Self, Uninhabited> {
+    pub(crate) fn from_tree(tree: Tree<!, R, T>) -> Result<Self, Uninhabited> {
         Ok(match tree {
             Tree::Byte(b) => Self::from_byte(b),
             Tree::Ref(r) => Self::from_ref(r),
@@ -125,7 +129,7 @@ where
         let start = self.start;
         let accept = other.accept;
 
-        let mut transitions: Map<State, Transitions<R>> = self.transitions;
+        let mut transitions: Map<State, Transitions<R, T>> = self.transitions;
 
         for (source, transition) in other.transitions {
             let fix_state = |state| if state == other.start { self.accept } else { state };
@@ -169,7 +173,7 @@ where
         };
 
         let start = mapped((Some(a.start), Some(b.start)));
-        let mut transitions: Map<State, Transitions<R>> = Map::default();
+        let mut transitions: Map<State, Transitions<R, T>> = Map::default();
         let empty_transitions = Transitions::default();
 
         struct WorkQueue {
@@ -257,7 +261,7 @@ where
             .flat_map(|transitions| transitions.byte_transitions.iter())
     }
 
-    pub(crate) fn refs_from(&self, start: State) -> impl Iterator<Item = (R, State)> {
+    pub(crate) fn refs_from(&self, start: State) -> impl Iterator<Item = (Reference<R, T>, State)> {
         self.transitions
             .get(&start)
             .into_iter()
@@ -297,9 +301,10 @@ where
 }
 
 /// Serialize the DFA using the Graphviz DOT format.
-impl<R> fmt::Debug for Dfa<R>
+impl<R, T> fmt::Debug for Dfa<R, T>
 where
-    R: Ref,
+    R: Region,
+    T: Type,
 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         writeln!(f, "digraph {{")?;
diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs
index c08bf440734..acbce258f39 100644
--- a/compiler/rustc_transmute/src/layout/mod.rs
+++ b/compiler/rustc_transmute/src/layout/mod.rs
@@ -78,16 +78,41 @@ impl From<u8> for Byte {
     }
 }
 
+/// A reference, i.e., `&'region T` or `&'region mut T`.
+#[derive(Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
+pub(crate) struct Reference<R, T>
+where
+    R: Region,
+    T: Type,
+{
+    pub(crate) region: R,
+    pub(crate) is_mut: bool,
+    pub(crate) referent: T,
+    pub(crate) referent_size: usize,
+    pub(crate) referent_align: usize,
+}
+
+impl<R, T> fmt::Display for Reference<R, T>
+where
+    R: Region,
+    T: Type,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_str("&")?;
+        if self.is_mut {
+            f.write_str("mut ")?;
+        }
+        self.referent.fmt(f)
+    }
+}
+
 pub(crate) trait Def: Debug + Hash + Eq + PartialEq + Copy + Clone {
     fn has_safety_invariants(&self) -> bool;
 }
-pub trait Ref: Debug + Hash + Eq + PartialEq + Copy + Clone {
-    fn min_align(&self) -> usize;
 
-    fn size(&self) -> usize;
+pub(crate) trait Region: Debug + Hash + Eq + PartialEq + Copy + Clone {}
 
-    fn is_mutable(&self) -> bool;
-}
+pub(crate) trait Type: Debug + Hash + Eq + PartialEq + Copy + Clone {}
 
 impl Def for ! {
     fn has_safety_invariants(&self) -> bool {
@@ -95,79 +120,21 @@ impl Def for ! {
     }
 }
 
-impl Ref for ! {
-    fn min_align(&self) -> usize {
-        unreachable!()
-    }
-    fn size(&self) -> usize {
-        unreachable!()
-    }
-    fn is_mutable(&self) -> bool {
-        unreachable!()
-    }
-}
+impl Region for ! {}
 
-#[cfg(test)]
-impl<const N: usize> Ref for [(); N] {
-    fn min_align(&self) -> usize {
-        N
-    }
+impl Type for ! {}
 
-    fn size(&self) -> usize {
-        N
-    }
+#[cfg(test)]
+impl Region for usize {}
 
-    fn is_mutable(&self) -> bool {
-        false
-    }
-}
+#[cfg(test)]
+impl Type for () {}
 
 #[cfg(feature = "rustc")]
 pub mod rustc {
-    use std::fmt::{self, Write};
-
     use rustc_abi::Layout;
-    use rustc_middle::mir::Mutability;
     use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError};
-    use rustc_middle::ty::{self, Ty};
-
-    /// A reference in the layout.
-    #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
-    pub struct Ref<'tcx> {
-        pub lifetime: ty::Region<'tcx>,
-        pub ty: Ty<'tcx>,
-        pub mutability: Mutability,
-        pub align: usize,
-        pub size: usize,
-    }
-
-    impl<'tcx> super::Ref for Ref<'tcx> {
-        fn min_align(&self) -> usize {
-            self.align
-        }
-
-        fn size(&self) -> usize {
-            self.size
-        }
-
-        fn is_mutable(&self) -> bool {
-            match self.mutability {
-                Mutability::Mut => true,
-                Mutability::Not => false,
-            }
-        }
-    }
-    impl<'tcx> Ref<'tcx> {}
-
-    impl<'tcx> fmt::Display for Ref<'tcx> {
-        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-            f.write_char('&')?;
-            if self.mutability == Mutability::Mut {
-                f.write_str("mut ")?;
-            }
-            self.ty.fmt(f)
-        }
-    }
+    use rustc_middle::ty::{self, Region, Ty};
 
     /// A visibility node in the layout.
     #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
@@ -187,6 +154,10 @@ pub mod rustc {
         }
     }
 
+    impl<'tcx> super::Region for Region<'tcx> {}
+
+    impl<'tcx> super::Type for Ty<'tcx> {}
+
     pub(crate) fn layout_of<'tcx>(
         cx: LayoutCx<'tcx>,
         ty: Ty<'tcx>,
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index ff665695b5a..372b4f5353a 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -1,6 +1,6 @@
 use std::ops::{ControlFlow, RangeInclusive};
 
-use super::{Byte, Def, Ref};
+use super::{Byte, Def, Reference, Region, Type};
 
 #[cfg(test)]
 mod tests;
@@ -15,10 +15,11 @@ mod tests;
 /// 2. A `Seq` is never directly nested beneath another `Seq`.
 /// 3. `Seq`s and `Alt`s with a single member do not exist.
 #[derive(Clone, Debug, Hash, PartialEq, Eq)]
-pub(crate) enum Tree<D, R>
+pub(crate) enum Tree<D, R, T>
 where
     D: Def,
-    R: Ref,
+    R: Region,
+    T: Type,
 {
     /// A sequence of successive layouts.
     Seq(Vec<Self>),
@@ -27,7 +28,7 @@ where
     /// A definition node.
     Def(D),
     /// A reference node.
-    Ref(R),
+    Ref(Reference<R, T>),
     /// A byte node.
     Byte(Byte),
 }
@@ -48,10 +49,11 @@ impl From<rustc_abi::Endian> for Endian {
     }
 }
 
-impl<D, R> Tree<D, R>
+impl<D, R, T> Tree<D, R, T>
 where
     D: Def,
-    R: Ref,
+    R: Region,
+    T: Type,
 {
     /// A `Tree` consisting only of a definition node.
     pub(crate) fn def(def: D) -> Self {
@@ -138,7 +140,7 @@ where
 
     /// Remove all `Def` nodes, and all branches of the layout for which `f`
     /// produces `true`.
-    pub(crate) fn prune<F>(self, f: &F) -> Tree<!, R>
+    pub(crate) fn prune<F>(self, f: &F) -> Tree<!, R, T>
     where
         F: Fn(D) -> bool,
     {
@@ -198,13 +200,13 @@ where
 
     /// Produces a `Tree` where each of the trees in `trees` are sequenced one
     /// after another.
-    pub(crate) fn seq<const N: usize>(trees: [Tree<D, R>; N]) -> Self {
+    pub(crate) fn seq<const N: usize>(trees: [Tree<D, R, T>; N]) -> Self {
         trees.into_iter().fold(Tree::unit(), Self::then)
     }
 
     /// Produces a `Tree` where each of the trees in `trees` are accepted as
     /// alternative layouts.
-    pub(crate) fn alt<const N: usize>(trees: [Tree<D, R>; N]) -> Self {
+    pub(crate) fn alt<const N: usize>(trees: [Tree<D, R, T>; N]) -> Self {
         trees.into_iter().fold(Tree::uninhabited(), Self::or)
     }
 
@@ -251,11 +253,14 @@ pub(crate) mod rustc {
         FieldIdx, FieldsShape, Layout, Size, TagEncoding, TyAndLayout, VariantIdx, Variants,
     };
     use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError};
-    use rustc_middle::ty::{self, AdtDef, AdtKind, List, ScalarInt, Ty, TyCtxt, TypeVisitableExt};
+    use rustc_middle::ty::{
+        self, AdtDef, AdtKind, List, Region, ScalarInt, Ty, TyCtxt, TypeVisitableExt,
+    };
     use rustc_span::ErrorGuaranteed;
 
     use super::Tree;
-    use crate::layout::rustc::{Def, Ref, layout_of};
+    use crate::layout::Reference;
+    use crate::layout::rustc::{Def, layout_of};
 
     #[derive(Debug, Copy, Clone)]
     pub(crate) enum Err {
@@ -281,7 +286,7 @@ pub(crate) mod rustc {
         }
     }
 
-    impl<'tcx> Tree<Def<'tcx>, Ref<'tcx>> {
+    impl<'tcx> Tree<Def<'tcx>, Region<'tcx>, Ty<'tcx>> {
         pub(crate) fn from_ty(ty: Ty<'tcx>, cx: LayoutCx<'tcx>) -> Result<Self, Err> {
             use rustc_abi::HasDataLayout;
             let layout = layout_of(cx, ty)?;
@@ -353,16 +358,17 @@ pub(crate) mod rustc {
                     }
                 }
 
-                ty::Ref(lifetime, ty, mutability) => {
+                ty::Ref(region, ty, mutability) => {
                     let layout = layout_of(cx, *ty)?;
-                    let align = layout.align.abi.bytes_usize();
-                    let size = layout.size.bytes_usize();
-                    Ok(Tree::Ref(Ref {
-                        lifetime: *lifetime,
-                        ty: *ty,
-                        mutability: *mutability,
-                        align,
-                        size,
+                    let referent_align = layout.align.abi.bytes_usize();
+                    let referent_size = layout.size.bytes_usize();
+
+                    Ok(Tree::Ref(Reference {
+                        region: *region,
+                        is_mut: mutability.is_mut(),
+                        referent: *ty,
+                        referent_align,
+                        referent_size,
                     }))
                 }
 
diff --git a/compiler/rustc_transmute/src/layout/tree/tests.rs b/compiler/rustc_transmute/src/layout/tree/tests.rs
index 8c3dbbe37ab..bc47b19c681 100644
--- a/compiler/rustc_transmute/src/layout/tree/tests.rs
+++ b/compiler/rustc_transmute/src/layout/tree/tests.rs
@@ -20,13 +20,13 @@ mod prune {
 
         #[test]
         fn seq_1() {
-            let layout: Tree<Def, !> = Tree::def(Def::NoSafetyInvariants).then(Tree::byte(0x00));
+            let layout: Tree<Def, !, !> = Tree::def(Def::NoSafetyInvariants).then(Tree::byte(0x00));
             assert_eq!(layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)), Tree::byte(0x00));
         }
 
         #[test]
         fn seq_2() {
-            let layout: Tree<Def, !> =
+            let layout: Tree<Def, !, !> =
                 Tree::byte(0x00).then(Tree::def(Def::NoSafetyInvariants)).then(Tree::byte(0x01));
 
             assert_eq!(
@@ -41,7 +41,7 @@ mod prune {
 
         #[test]
         fn invisible_def() {
-            let layout: Tree<Def, !> = Tree::def(Def::HasSafetyInvariants);
+            let layout: Tree<Def, !, !> = Tree::def(Def::HasSafetyInvariants);
             assert_eq!(
                 layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)),
                 Tree::uninhabited()
@@ -50,7 +50,7 @@ mod prune {
 
         #[test]
         fn invisible_def_in_seq_len_2() {
-            let layout: Tree<Def, !> =
+            let layout: Tree<Def, !, !> =
                 Tree::def(Def::NoSafetyInvariants).then(Tree::def(Def::HasSafetyInvariants));
             assert_eq!(
                 layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)),
@@ -60,7 +60,7 @@ mod prune {
 
         #[test]
         fn invisible_def_in_seq_len_3() {
-            let layout: Tree<Def, !> = Tree::def(Def::NoSafetyInvariants)
+            let layout: Tree<Def, !, !> = Tree::def(Def::NoSafetyInvariants)
                 .then(Tree::byte(0x00))
                 .then(Tree::def(Def::HasSafetyInvariants));
             assert_eq!(
@@ -75,20 +75,20 @@ mod prune {
 
         #[test]
         fn visible_def() {
-            let layout: Tree<Def, !> = Tree::def(Def::NoSafetyInvariants);
+            let layout: Tree<Def, !, !> = Tree::def(Def::NoSafetyInvariants);
             assert_eq!(layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)), Tree::unit());
         }
 
         #[test]
         fn visible_def_in_seq_len_2() {
-            let layout: Tree<Def, !> =
+            let layout: Tree<Def, !, !> =
                 Tree::def(Def::NoSafetyInvariants).then(Tree::def(Def::NoSafetyInvariants));
             assert_eq!(layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)), Tree::unit());
         }
 
         #[test]
         fn visible_def_in_seq_len_3() {
-            let layout: Tree<Def, !> = Tree::def(Def::NoSafetyInvariants)
+            let layout: Tree<Def, !, !> = Tree::def(Def::NoSafetyInvariants)
                 .then(Tree::byte(0x00))
                 .then(Tree::def(Def::NoSafetyInvariants));
             assert_eq!(layout.prune(&|d| matches!(d, Def::HasSafetyInvariants)), Tree::byte(0x00));
diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs
index ce18dad5517..36281ff16bc 100644
--- a/compiler/rustc_transmute/src/lib.rs
+++ b/compiler/rustc_transmute/src/lib.rs
@@ -19,23 +19,29 @@ pub struct Assume {
 /// Either transmutation is allowed, we have an error, or we have an optional
 /// Condition that must hold.
 #[derive(Debug, Hash, Eq, PartialEq, Clone)]
-pub enum Answer<R> {
+pub enum Answer<R, T> {
     Yes,
-    No(Reason<R>),
-    If(Condition<R>),
+    No(Reason<T>),
+    If(Condition<R, T>),
 }
 
 /// A condition which must hold for safe transmutation to be possible.
 #[derive(Debug, Hash, Eq, PartialEq, Clone)]
-pub enum Condition<R> {
+pub enum Condition<R, T> {
     /// `Src` is transmutable into `Dst`, if `src` is transmutable into `dst`.
-    IfTransmutable { src: R, dst: R },
+    Transmutable { src: T, dst: T },
+
+    /// The region `long` must outlive `short`.
+    Outlives { long: R, short: R },
+
+    /// The `ty` is immutable.
+    Immutable { ty: T },
 
     /// `Src` is transmutable into `Dst`, if all of the enclosed requirements are met.
-    IfAll(Vec<Condition<R>>),
+    IfAll(Vec<Condition<R, T>>),
 
     /// `Src` is transmutable into `Dst` if any of the enclosed requirements are met.
-    IfAny(Vec<Condition<R>>),
+    IfAny(Vec<Condition<R, T>>),
 }
 
 /// Answers "why wasn't the source type transmutable into the destination type?"
@@ -53,12 +59,16 @@ pub enum Reason<T> {
     DstMayHaveSafetyInvariants,
     /// `Dst` is larger than `Src`, and the excess bytes were not exclusively uninitialized.
     DstIsTooBig,
-    /// A referent of `Dst` is larger than a referent in `Src`.
+    /// `Dst` is larger `Src`.
     DstRefIsTooBig {
         /// The referent of the source type.
         src: T,
+        /// The size of the source type's referent.
+        src_size: usize,
         /// The too-large referent of the destination type.
         dst: T,
+        /// The size of the destination type's referent.
+        dst_size: usize,
     },
     /// Src should have a stricter alignment than Dst, but it does not.
     DstHasStricterAlignment { src_min_align: usize, dst_min_align: usize },
@@ -79,7 +89,7 @@ pub enum Reason<T> {
 #[cfg(feature = "rustc")]
 mod rustc {
     use rustc_hir::lang_items::LangItem;
-    use rustc_middle::ty::{Const, Ty, TyCtxt};
+    use rustc_middle::ty::{Const, Region, Ty, TyCtxt};
 
     use super::*;
 
@@ -105,7 +115,7 @@ mod rustc {
             &mut self,
             types: Types<'tcx>,
             assume: crate::Assume,
-        ) -> crate::Answer<crate::layout::rustc::Ref<'tcx>> {
+        ) -> crate::Answer<Region<'tcx>, Ty<'tcx>> {
             crate::maybe_transmutable::MaybeTransmutableQuery::new(
                 types.src, types.dst, assume, self.tcx,
             )
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
index f76abe50ed3..062de4b5d08 100644
--- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
+++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
@@ -5,7 +5,7 @@ pub(crate) mod query_context;
 #[cfg(test)]
 mod tests;
 
-use crate::layout::{self, Def, Dfa, Ref, Tree, dfa, union};
+use crate::layout::{self, Def, Dfa, Reference, Tree, dfa, union};
 use crate::maybe_transmutable::query_context::QueryContext;
 use crate::{Answer, Condition, Map, Reason};
 
@@ -41,7 +41,10 @@ mod rustc {
         /// This method begins by converting `src` and `dst` from `Ty`s to `Tree`s,
         /// then computes an answer using those trees.
         #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
-        pub(crate) fn answer(self) -> Answer<<TyCtxt<'tcx> as QueryContext>::Ref> {
+        pub(crate) fn answer(
+            self,
+        ) -> Answer<<TyCtxt<'tcx> as QueryContext>::Region, <TyCtxt<'tcx> as QueryContext>::Type>
+        {
             let Self { src, dst, assume, context } = self;
 
             let layout_cx = LayoutCx::new(context, TypingEnv::fully_monomorphized());
@@ -67,7 +70,11 @@ mod rustc {
     }
 }
 
-impl<C> MaybeTransmutableQuery<Tree<<C as QueryContext>::Def, <C as QueryContext>::Ref>, C>
+impl<C>
+    MaybeTransmutableQuery<
+        Tree<<C as QueryContext>::Def, <C as QueryContext>::Region, <C as QueryContext>::Type>,
+        C,
+    >
 where
     C: QueryContext,
 {
@@ -77,7 +84,7 @@ where
     /// then converts `src` and `dst` to `Dfa`s, and computes an answer using those DFAs.
     #[inline(always)]
     #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
-    pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
+    pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Region, <C as QueryContext>::Type> {
         let Self { src, dst, assume, context } = self;
 
         // Unconditionally remove all `Def` nodes from `src`, without pruning away the
@@ -130,12 +137,12 @@ where
     }
 }
 
-impl<C> MaybeTransmutableQuery<Dfa<<C as QueryContext>::Ref>, C>
+impl<C> MaybeTransmutableQuery<Dfa<<C as QueryContext>::Region, <C as QueryContext>::Type>, C>
 where
     C: QueryContext,
 {
     /// Answers whether a `Dfa` is transmutable into another `Dfa`.
-    pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
+    pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Region, <C as QueryContext>::Type> {
         self.answer_memo(&mut Map::default(), self.src.start, self.dst.start)
     }
 
@@ -143,10 +150,13 @@ where
     #[instrument(level = "debug", skip(self))]
     fn answer_memo(
         &self,
-        cache: &mut Map<(dfa::State, dfa::State), Answer<<C as QueryContext>::Ref>>,
+        cache: &mut Map<
+            (dfa::State, dfa::State),
+            Answer<<C as QueryContext>::Region, <C as QueryContext>::Type>,
+        >,
         src_state: dfa::State,
         dst_state: dfa::State,
-    ) -> Answer<<C as QueryContext>::Ref> {
+    ) -> Answer<<C as QueryContext>::Region, <C as QueryContext>::Type> {
         if let Some(answer) = cache.get(&(src_state, dst_state)) {
             answer.clone()
         } else {
@@ -160,10 +170,13 @@ where
 
     fn answer_impl(
         &self,
-        cache: &mut Map<(dfa::State, dfa::State), Answer<<C as QueryContext>::Ref>>,
+        cache: &mut Map<
+            (dfa::State, dfa::State),
+            Answer<<C as QueryContext>::Region, <C as QueryContext>::Type>,
+        >,
         src_state: dfa::State,
         dst_state: dfa::State,
-    ) -> Answer<<C as QueryContext>::Ref> {
+    ) -> Answer<<C as QueryContext>::Region, <C as QueryContext>::Type> {
         debug!(?src_state, ?dst_state);
         debug!(src = ?self.src);
         debug!(dst = ?self.dst);
@@ -247,27 +260,51 @@ where
                     // ...there exists a reference transition out of `dst_state`...
                     Quantifier::ThereExists.apply(self.dst.refs_from(dst_state).map(
                         |(dst_ref, dst_state_prime)| {
-                            if !src_ref.is_mutable() && dst_ref.is_mutable() {
+                            if !src_ref.is_mut && dst_ref.is_mut {
                                 Answer::No(Reason::DstIsMoreUnique)
                             } else if !self.assume.alignment
-                                && src_ref.min_align() < dst_ref.min_align()
+                                && src_ref.referent_align < dst_ref.referent_align
                             {
                                 Answer::No(Reason::DstHasStricterAlignment {
-                                    src_min_align: src_ref.min_align(),
-                                    dst_min_align: dst_ref.min_align(),
+                                    src_min_align: src_ref.referent_align,
+                                    dst_min_align: dst_ref.referent_align,
+                                })
+                            } else if dst_ref.referent_size > src_ref.referent_size {
+                                Answer::No(Reason::DstRefIsTooBig {
+                                    src: src_ref.referent,
+                                    src_size: src_ref.referent_size,
+                                    dst: dst_ref.referent,
+                                    dst_size: dst_ref.referent_size,
                                 })
-                            } else if dst_ref.size() > src_ref.size() {
-                                Answer::No(Reason::DstRefIsTooBig { src: src_ref, dst: dst_ref })
                             } else {
-                                // ...such that `src` is transmutable into `dst`, if
-                                // `src_ref` is transmutability into `dst_ref`.
-                                and(
-                                    Answer::If(Condition::IfTransmutable {
-                                        src: src_ref,
-                                        dst: dst_ref,
-                                    }),
-                                    self.answer_memo(cache, src_state_prime, dst_state_prime),
-                                )
+                                let mut conditions = Vec::with_capacity(4);
+                                let mut is_transmutable =
+                                    |src: Reference<_, _>, dst: Reference<_, _>| {
+                                        conditions.push(Condition::Transmutable {
+                                            src: src.referent,
+                                            dst: dst.referent,
+                                        });
+                                        if !self.assume.lifetimes {
+                                            conditions.push(Condition::Outlives {
+                                                long: src.region,
+                                                short: dst.region,
+                                            });
+                                        }
+                                    };
+
+                                is_transmutable(src_ref, dst_ref);
+
+                                if dst_ref.is_mut {
+                                    is_transmutable(dst_ref, src_ref);
+                                } else {
+                                    conditions.push(Condition::Immutable { ty: dst_ref.referent });
+                                }
+
+                                Answer::If(Condition::IfAll(conditions)).and(self.answer_memo(
+                                    cache,
+                                    src_state_prime,
+                                    dst_state_prime,
+                                ))
                             }
                         },
                     ))
@@ -275,67 +312,65 @@ where
             );
 
             if self.assume.validity {
-                or(bytes_answer, refs_answer)
+                bytes_answer.or(refs_answer)
             } else {
-                and(bytes_answer, refs_answer)
+                bytes_answer.and(refs_answer)
             }
         }
     }
 }
 
-fn and<R>(lhs: Answer<R>, rhs: Answer<R>) -> Answer<R>
-where
-    R: PartialEq,
-{
-    match (lhs, rhs) {
-        // If both are errors, then we should return the more specific one
-        (Answer::No(Reason::DstIsBitIncompatible), Answer::No(reason))
-        | (Answer::No(reason), Answer::No(_))
-        // If either is an error, return it
-        | (Answer::No(reason), _) | (_, Answer::No(reason)) => Answer::No(reason),
-        // If only one side has a condition, pass it along
-        | (Answer::Yes, other) | (other, Answer::Yes) => other,
-        // If both sides have IfAll conditions, merge them
-        (Answer::If(Condition::IfAll(mut lhs)), Answer::If(Condition::IfAll(ref mut rhs))) => {
-            lhs.append(rhs);
-            Answer::If(Condition::IfAll(lhs))
-        }
-        // If only one side is an IfAll, add the other Condition to it
-        (Answer::If(cond), Answer::If(Condition::IfAll(mut conds)))
-        | (Answer::If(Condition::IfAll(mut conds)), Answer::If(cond)) => {
-            conds.push(cond);
-            Answer::If(Condition::IfAll(conds))
+impl<R, T> Answer<R, T> {
+    fn and(self, rhs: Answer<R, T>) -> Answer<R, T> {
+        let lhs = self;
+        match (lhs, rhs) {
+            // If both are errors, then we should return the more specific one
+            (Answer::No(Reason::DstIsBitIncompatible), Answer::No(reason))
+            | (Answer::No(reason), Answer::No(_))
+            // If either is an error, return it
+            | (Answer::No(reason), _) | (_, Answer::No(reason)) => Answer::No(reason),
+            // If only one side has a condition, pass it along
+            | (Answer::Yes, other) | (other, Answer::Yes) => other,
+            // If both sides have IfAll conditions, merge them
+            (Answer::If(Condition::IfAll(mut lhs)), Answer::If(Condition::IfAll(ref mut rhs))) => {
+                lhs.append(rhs);
+                Answer::If(Condition::IfAll(lhs))
+            }
+            // If only one side is an IfAll, add the other Condition to it
+            (Answer::If(cond), Answer::If(Condition::IfAll(mut conds)))
+            | (Answer::If(Condition::IfAll(mut conds)), Answer::If(cond)) => {
+                conds.push(cond);
+                Answer::If(Condition::IfAll(conds))
+            }
+            // Otherwise, both lhs and rhs conditions can be combined in a parent IfAll
+            (Answer::If(lhs), Answer::If(rhs)) => Answer::If(Condition::IfAll(vec![lhs, rhs])),
         }
-        // Otherwise, both lhs and rhs conditions can be combined in a parent IfAll
-        (Answer::If(lhs), Answer::If(rhs)) => Answer::If(Condition::IfAll(vec![lhs, rhs])),
     }
-}
 
-fn or<R>(lhs: Answer<R>, rhs: Answer<R>) -> Answer<R>
-where
-    R: PartialEq,
-{
-    match (lhs, rhs) {
-        // If both are errors, then we should return the more specific one
-        (Answer::No(Reason::DstIsBitIncompatible), Answer::No(reason))
-        | (Answer::No(reason), Answer::No(_)) => Answer::No(reason),
-        // Otherwise, errors can be ignored for the rest of the pattern matching
-        (Answer::No(_), other) | (other, Answer::No(_)) => or(other, Answer::Yes),
-        // If only one side has a condition, pass it along
-        (Answer::Yes, other) | (other, Answer::Yes) => other,
-        // If both sides have IfAny conditions, merge them
-        (Answer::If(Condition::IfAny(mut lhs)), Answer::If(Condition::IfAny(ref mut rhs))) => {
-            lhs.append(rhs);
-            Answer::If(Condition::IfAny(lhs))
-        }
-        // If only one side is an IfAny, add the other Condition to it
-        (Answer::If(cond), Answer::If(Condition::IfAny(mut conds)))
-        | (Answer::If(Condition::IfAny(mut conds)), Answer::If(cond)) => {
-            conds.push(cond);
-            Answer::If(Condition::IfAny(conds))
+    fn or(self, rhs: Answer<R, T>) -> Answer<R, T> {
+        let lhs = self;
+        match (lhs, rhs) {
+            // If both are errors, then we should return the more specific one
+            (Answer::No(Reason::DstIsBitIncompatible), Answer::No(reason))
+            | (Answer::No(reason), Answer::No(_)) => Answer::No(reason),
+            // Otherwise, errors can be ignored for the rest of the pattern matching
+            (Answer::No(_), other) | (other, Answer::No(_)) => other.or(Answer::Yes),
+            // If only one side has a condition, pass it along
+            (Answer::Yes, other) | (other, Answer::Yes) => other,
+            // If both sides have IfAny conditions, merge them
+            (Answer::If(Condition::IfAny(mut lhs)), Answer::If(Condition::IfAny(ref mut rhs))) => {
+                lhs.append(rhs);
+                Answer::If(Condition::IfAny(lhs))
+            }
+            // If only one side is an IfAny, add the other Condition to it
+            (Answer::If(cond), Answer::If(Condition::IfAny(mut conds)))
+            | (Answer::If(Condition::IfAny(mut conds)), Answer::If(cond)) => {
+                conds.push(cond);
+                Answer::If(Condition::IfAny(conds))
+            }
+            // Otherwise, both lhs and rhs conditions can be combined in a parent IfAny
+            (Answer::If(lhs), Answer::If(rhs)) => Answer::If(Condition::IfAny(vec![lhs, rhs])),
         }
-        // Otherwise, both lhs and rhs conditions can be combined in a parent IfAny
-        (Answer::If(lhs), Answer::If(rhs)) => Answer::If(Condition::IfAny(vec![lhs, rhs])),
     }
 }
 
@@ -345,24 +380,25 @@ enum Quantifier {
 }
 
 impl Quantifier {
-    fn apply<R, I>(&self, iter: I) -> Answer<R>
+    fn apply<R, T, I>(&self, iter: I) -> Answer<R, T>
     where
-        R: layout::Ref,
-        I: IntoIterator<Item = Answer<R>>,
+        R: layout::Region,
+        T: layout::Type,
+        I: IntoIterator<Item = Answer<R, T>>,
     {
         use std::ops::ControlFlow::{Break, Continue};
 
         let (init, try_fold_f): (_, fn(_, _) -> _) = match self {
             Self::ThereExists => {
-                (Answer::No(Reason::DstIsBitIncompatible), |accum: Answer<R>, next| {
-                    match or(accum, next) {
-                        Answer::Yes => Break(Answer::Yes),
-                        maybe => Continue(maybe),
-                    }
+                (Answer::No(Reason::DstIsBitIncompatible), |accum: Answer<R, T>, next| match accum
+                    .or(next)
+                {
+                    Answer::Yes => Break(Answer::Yes),
+                    maybe => Continue(maybe),
                 })
             }
-            Self::ForAll => (Answer::Yes, |accum: Answer<R>, next| {
-                let answer = and(accum, next);
+            Self::ForAll => (Answer::Yes, |accum: Answer<R, T>, next| {
+                let answer = accum.and(next);
                 match answer {
                     Answer::No(_) => Break(answer),
                     maybe => Continue(maybe),
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs
index 214da101be3..6be0cb11904 100644
--- a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs
+++ b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs
@@ -3,7 +3,8 @@ use crate::layout;
 /// Context necessary to answer the question "Are these types transmutable?".
 pub(crate) trait QueryContext {
     type Def: layout::Def;
-    type Ref: layout::Ref;
+    type Region: layout::Region;
+    type Type: layout::Type;
 }
 
 #[cfg(test)]
@@ -12,9 +13,9 @@ pub(crate) mod test {
 
     use super::QueryContext;
 
-    pub(crate) struct UltraMinimal<R = !>(PhantomData<R>);
+    pub(crate) struct UltraMinimal<R = !, T = !>(PhantomData<(R, T)>);
 
-    impl<R> Default for UltraMinimal<R> {
+    impl<R, T> Default for UltraMinimal<R, T> {
         fn default() -> Self {
             Self(PhantomData)
         }
@@ -32,20 +33,26 @@ pub(crate) mod test {
         }
     }
 
-    impl<R: crate::layout::Ref> QueryContext for UltraMinimal<R> {
+    impl<R, T> QueryContext for UltraMinimal<R, T>
+    where
+        R: crate::layout::Region,
+        T: crate::layout::Type,
+    {
         type Def = Def;
-        type Ref = R;
+        type Region = R;
+        type Type = T;
     }
 }
 
 #[cfg(feature = "rustc")]
 mod rustc {
-    use rustc_middle::ty::TyCtxt;
+    use rustc_middle::ty::{Region, Ty, TyCtxt};
 
     use super::*;
 
     impl<'tcx> super::QueryContext for TyCtxt<'tcx> {
         type Def = layout::rustc::Def<'tcx>;
-        type Ref = layout::rustc::Ref<'tcx>;
+        type Region = Region<'tcx>;
+        type Type = Ty<'tcx>;
     }
 }
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs
index 0227ad71ae6..8440ace2608 100644
--- a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs
+++ b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs
@@ -3,17 +3,17 @@ extern crate test;
 use itertools::Itertools;
 
 use super::query_context::test::{Def, UltraMinimal};
-use crate::{Answer, Assume, Reason, layout};
+use crate::{Answer, Assume, Condition, Reason, layout};
 
-type Tree = layout::Tree<Def, !>;
-type Dfa = layout::Dfa<!>;
+type Tree = layout::Tree<Def, !, !>;
+type Dfa = layout::Dfa<!, !>;
 
 trait Representation {
-    fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer<!>;
+    fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer<!, !>;
 }
 
 impl Representation for Tree {
-    fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer<!> {
+    fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer<!, !> {
         crate::maybe_transmutable::MaybeTransmutableQuery::new(
             src,
             dst,
@@ -25,7 +25,7 @@ impl Representation for Tree {
 }
 
 impl Representation for Dfa {
-    fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer<!> {
+    fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer<!, !> {
         crate::maybe_transmutable::MaybeTransmutableQuery::new(
             src,
             dst,
@@ -40,7 +40,7 @@ fn is_transmutable<R: Representation + Clone>(
     src: &R,
     dst: &R,
     assume: Assume,
-) -> crate::Answer<!> {
+) -> crate::Answer<!, !> {
     let src = src.clone();
     let dst = dst.clone();
     // The only dimension of the transmutability analysis we want to test
@@ -53,7 +53,7 @@ mod safety {
     use super::*;
     use crate::Answer;
 
-    const DST_HAS_SAFETY_INVARIANTS: Answer<!> =
+    const DST_HAS_SAFETY_INVARIANTS: Answer<!, !> =
         Answer::No(crate::Reason::DstMayHaveSafetyInvariants);
 
     #[test]
@@ -177,14 +177,15 @@ mod bool {
 
     #[test]
     fn should_permit_validity_expansion_and_reject_contraction() {
-        let b0 = layout::Tree::<Def, !>::byte(0);
-        let b1 = layout::Tree::<Def, !>::byte(1);
-        let b2 = layout::Tree::<Def, !>::byte(2);
+        let b0 = layout::Tree::<Def, !, !>::byte(0);
+        let b1 = layout::Tree::<Def, !, !>::byte(1);
+        let b2 = layout::Tree::<Def, !, !>::byte(2);
 
         let alts = [b0, b1, b2];
 
         let into_layout = |alts: Vec<_>| {
-            alts.into_iter().fold(layout::Tree::<Def, !>::uninhabited(), layout::Tree::<Def, !>::or)
+            alts.into_iter()
+                .fold(layout::Tree::<Def, !, !>::uninhabited(), layout::Tree::<Def, !, !>::or)
         };
 
         let into_set = |alts: Vec<_>| {
@@ -277,7 +278,7 @@ mod alt {
 
     #[test]
     fn should_permit_identity_transmutation() {
-        type Tree = layout::Tree<Def, !>;
+        type Tree = layout::Tree<Def, !, !>;
 
         let x = Tree::Seq(vec![Tree::byte(0), Tree::byte(0)]);
         let y = Tree::Seq(vec![Tree::bool(), Tree::byte(1)]);
@@ -331,7 +332,7 @@ mod char {
     fn should_permit_valid_transmutation() {
         for order in [Endian::Big, Endian::Little] {
             use Answer::*;
-            let char_layout = layout::Tree::<Def, !>::char(order);
+            let char_layout = layout::Tree::<Def, !, !>::char(order);
 
             // `char`s can be in the following ranges:
             // - [0, 0xD7FF]
@@ -353,7 +354,7 @@ mod char {
                 (0xFFFFFFFF, no),
             ] {
                 let src_layout =
-                    layout::tree::Tree::<Def, !>::from_big_endian(order, src.to_be_bytes());
+                    layout::tree::Tree::<Def, !, !>::from_big_endian(order, src.to_be_bytes());
 
                 let a = is_transmutable(&src_layout, &char_layout, Assume::default());
                 assert_eq!(a, answer, "endian:{order:?},\nsrc:{src:x}");
@@ -371,7 +372,7 @@ mod nonzero {
     #[test]
     fn should_permit_identity_transmutation() {
         for width in NONZERO_BYTE_WIDTHS {
-            let layout = layout::Tree::<Def, !>::nonzero(width);
+            let layout = layout::Tree::<Def, !, !>::nonzero(width);
             assert_eq!(is_transmutable(&layout, &layout, Assume::default()), Answer::Yes);
         }
     }
@@ -381,8 +382,8 @@ mod nonzero {
         for width in NONZERO_BYTE_WIDTHS {
             use Answer::*;
 
-            let num = layout::Tree::<Def, !>::number(width);
-            let nz = layout::Tree::<Def, !>::nonzero(width);
+            let num = layout::Tree::<Def, !, !>::number(width);
+            let nz = layout::Tree::<Def, !, !>::nonzero(width);
 
             let a = is_transmutable(&num, &nz, Assume::default());
             assert_eq!(a, No(Reason::DstIsBitIncompatible), "width:{width}");
@@ -395,13 +396,23 @@ mod nonzero {
 
 mod r#ref {
     use super::*;
+    use crate::layout::Reference;
 
     #[test]
     fn should_permit_identity_transmutation() {
-        type Tree = crate::layout::Tree<Def, [(); 1]>;
+        type Tree = crate::layout::Tree<Def, usize, ()>;
 
         for validity in [false, true] {
-            let layout = Tree::Seq(vec![Tree::byte(0x00), Tree::Ref([()])]);
+            let layout = Tree::Seq(vec![
+                Tree::byte(0x00),
+                Tree::Ref(Reference {
+                    region: 42,
+                    is_mut: false,
+                    referent: (),
+                    referent_size: 0,
+                    referent_align: 1,
+                }),
+            ]);
 
             let assume = Assume { validity, ..Assume::default() };
 
@@ -414,7 +425,11 @@ mod r#ref {
             .answer();
             assert_eq!(
                 answer,
-                Answer::If(crate::Condition::IfTransmutable { src: [()], dst: [()] })
+                Answer::If(Condition::IfAll(vec![
+                    Condition::Transmutable { src: (), dst: () },
+                    Condition::Outlives { long: 42, short: 42 },
+                    Condition::Immutable { ty: () },
+                ]))
             );
         }
     }
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 4dc27622d23..79ac622df32 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -255,10 +255,8 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
     }
 }
 
-fn param_env_normalized_for_post_analysis(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
-    // This is a bit ugly but the easiest way to avoid code duplication.
-    let typing_env = ty::TypingEnv::non_body_analysis(tcx, def_id);
-    typing_env.with_post_analysis_normalized(tcx).param_env
+fn typing_env_normalized_for_post_analysis(tcx: TyCtxt<'_>, def_id: DefId) -> ty::TypingEnv<'_> {
+    ty::TypingEnv::non_body_analysis(tcx, def_id).with_post_analysis_normalized(tcx)
 }
 
 /// Check if a function is async.
@@ -374,7 +372,7 @@ pub(crate) fn provide(providers: &mut Providers) {
         asyncness,
         adt_sized_constraint,
         param_env,
-        param_env_normalized_for_post_analysis,
+        typing_env_normalized_for_post_analysis,
         defaultness,
         unsizing_params_for_adt,
         impl_self_is_guaranteed_unsized,
diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs
index 2b1b0617cef..c66a83662d7 100644
--- a/compiler/rustc_type_ir/src/canonical.rs
+++ b/compiler/rustc_type_ir/src/canonical.rs
@@ -7,6 +7,7 @@ use derive_where::derive_where;
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
 use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 
+use crate::data_structures::HashMap;
 use crate::inherent::*;
 use crate::{self as ty, Interner, TypingMode, UniverseIndex};
 
@@ -333,3 +334,11 @@ impl<I: Interner> Index<ty::BoundVar> for CanonicalVarValues<I> {
         &self.var_values.as_slice()[value.as_usize()]
     }
 }
+
+#[derive_where(Clone, Debug; I: Interner)]
+pub struct CanonicalParamEnvCacheEntry<I: Interner> {
+    pub param_env: I::ParamEnv,
+    pub variables: Vec<I::GenericArg>,
+    pub variable_lookup_table: HashMap<I::GenericArg, usize>,
+    pub var_kinds: Vec<CanonicalVarKind<I>>,
+}
diff --git a/compiler/rustc_type_ir/src/fast_reject.rs b/compiler/rustc_type_ir/src/fast_reject.rs
index 34502f49550..615d07707b9 100644
--- a/compiler/rustc_type_ir/src/fast_reject.rs
+++ b/compiler/rustc_type_ir/src/fast_reject.rs
@@ -84,6 +84,9 @@ pub enum TreatParams {
     ///
     /// This also treats projections with inference variables as infer vars
     /// since they could be further normalized.
+    // FIXME(@lcnr): This treats aliases as rigid. This is only correct if the
+    // type has been structurally normalized. We should reflect this requirement
+    // in the variant name. It is currently incorrectly used in diagnostics.
     AsRigid,
 }
 
@@ -151,9 +154,11 @@ pub fn simplify_type<I: Interner>(
         ty::Alias(..) => match treat_params {
             // When treating `ty::Param` as a placeholder, projections also
             // don't unify with anything else as long as they are fully normalized.
-            // FIXME(-Znext-solver): Can remove this `if` and always simplify to `Placeholder`
-            // when the new solver is enabled by default.
-            TreatParams::AsRigid if !ty.has_non_region_infer() => Some(SimplifiedType::Placeholder),
+            TreatParams::AsRigid
+                if !ty.has_non_region_infer() || cx.next_trait_solver_globally() =>
+            {
+                Some(SimplifiedType::Placeholder)
+            }
             TreatParams::AsRigid | TreatParams::InstantiateWithInfer => None,
         },
         ty::Foreign(def_id) => Some(SimplifiedType::Foreign(def_id)),
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 05ca6f10323..cc0925b2c32 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -12,7 +12,7 @@ use crate::lang_items::TraitSolverLangItem;
 use crate::relate::Relate;
 use crate::solve::{CanonicalInput, ExternalConstraintsData, PredefinedOpaquesData, QueryResult};
 use crate::visit::{Flags, TypeVisitable};
-use crate::{self as ty, search_graph};
+use crate::{self as ty, CanonicalParamEnvCacheEntry, search_graph};
 
 #[cfg_attr(feature = "nightly", rustc_diagnostic_item = "type_ir_interner")]
 pub trait Interner:
@@ -32,6 +32,10 @@ pub trait Interner:
     + IrPrint<ty::FnSig<Self>>
     + IrPrint<ty::PatternKind<Self>>
 {
+    fn next_trait_solver_globally(self) -> bool {
+        true
+    }
+
     type DefId: DefId<Self>;
     type LocalDefId: Copy + Debug + Hash + Eq + Into<Self::DefId> + TypeFoldable<Self>;
     type Span: Span<Self>;
@@ -149,6 +153,13 @@ pub trait Interner:
 
     fn with_global_cache<R>(self, f: impl FnOnce(&mut search_graph::GlobalCache<Self>) -> R) -> R;
 
+    fn canonical_param_env_cache_get_or_insert<R>(
+        self,
+        param_env: Self::ParamEnv,
+        f: impl FnOnce() -> CanonicalParamEnvCacheEntry<Self>,
+        from_entry: impl FnOnce(&CanonicalParamEnvCacheEntry<Self>) -> R,
+    ) -> R;
+
     fn evaluation_is_concurrent(&self) -> bool;
 
     fn expand_abstract_consts<T: TypeFoldable<Self>>(self, t: T) -> T;
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index 0cd98b5aa53..9669772d1a6 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -771,23 +771,6 @@ pub enum InferTy {
     FreshFloatTy(u32),
 }
 
-/// Raw `TyVid` are used as the unification key for `sub_relations`;
-/// they carry no values.
-impl UnifyKey for TyVid {
-    type Value = ();
-    #[inline]
-    fn index(&self) -> u32 {
-        self.as_u32()
-    }
-    #[inline]
-    fn from_index(i: u32) -> TyVid {
-        TyVid::from_u32(i)
-    }
-    fn tag() -> &'static str {
-        "TyVid"
-    }
-}
-
 impl UnifyValue for IntVarValue {
     type Error = NoError;
 
diff --git a/library/Cargo.lock b/library/Cargo.lock
index 966ae72dc2a..1bd97e7b527 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -4,11 +4,10 @@ version = 4
 
 [[package]]
 name = "addr2line"
-version = "0.24.2"
+version = "0.25.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
+checksum = "9acbfca36652500c911ddb767ed433e3ed99b032b5d935be73c6923662db1d43"
 dependencies = [
- "compiler_builtins",
  "gimli",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
@@ -16,11 +15,10 @@ dependencies = [
 
 [[package]]
 name = "adler2"
-version = "2.0.0"
+version = "2.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
+checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
 dependencies = [
- "compiler_builtins",
  "rustc-std-workspace-core",
 ]
 
@@ -51,11 +49,10 @@ dependencies = [
 
 [[package]]
 name = "cfg-if"
-version = "1.0.0"
+version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
 dependencies = [
- "compiler_builtins",
  "rustc-std-workspace-core",
 ]
 
@@ -81,12 +78,11 @@ dependencies = [
 
 [[package]]
 name = "dlmalloc"
-version = "0.2.8"
+version = "0.2.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8cff88b751e7a276c4ab0e222c3f355190adc6dde9ce39c851db39da34990df7"
+checksum = "d01597dde41c0b9da50d5f8c219023d63d8f27f39a27095070fd191fddc83891"
 dependencies = [
  "cfg-if",
- "compiler_builtins",
  "libc",
  "rustc-std-workspace-core",
  "windows-sys",
@@ -104,9 +100,9 @@ dependencies = [
 
 [[package]]
 name = "getopts"
-version = "0.2.21"
+version = "0.2.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
+checksum = "cba6ae63eb948698e300f645f87c70f76630d505f23b8907cf1e193ee85048c1"
 dependencies = [
  "rustc-std-workspace-core",
  "rustc-std-workspace-std",
@@ -115,33 +111,30 @@ dependencies = [
 
 [[package]]
 name = "gimli"
-version = "0.31.1"
+version = "0.32.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
+checksum = "93563d740bc9ef04104f9ed6f86f1e3275c2cdafb95664e26584b9ca807a8ffe"
 dependencies = [
- "compiler_builtins",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
 ]
 
 [[package]]
 name = "hashbrown"
-version = "0.15.3"
+version = "0.15.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
+checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
 dependencies = [
- "compiler_builtins",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
 ]
 
 [[package]]
 name = "hermit-abi"
-version = "0.5.1"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f154ce46856750ed433c8649605bf7ed2de3bc35fd9d2a9f30cddd873c80cb08"
+checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
 dependencies = [
- "compiler_builtins",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
 ]
@@ -157,33 +150,30 @@ dependencies = [
 
 [[package]]
 name = "memchr"
-version = "2.7.4"
+version = "2.7.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
 dependencies = [
- "compiler_builtins",
  "rustc-std-workspace-core",
 ]
 
 [[package]]
 name = "miniz_oxide"
-version = "0.8.8"
+version = "0.8.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
+checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
 dependencies = [
  "adler2",
- "compiler_builtins",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
 ]
 
 [[package]]
 name = "object"
-version = "0.36.7"
+version = "0.37.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87"
+checksum = "03fd943161069e1768b4b3d050890ba48730e590f57e56d4aa04e7e090e61b4a"
 dependencies = [
- "compiler_builtins",
  "memchr",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
@@ -274,11 +264,10 @@ dependencies = [
 
 [[package]]
 name = "rustc-demangle"
-version = "0.1.24"
+version = "0.1.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
+checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
 dependencies = [
- "compiler_builtins",
  "rustc-std-workspace-core",
 ]
 
@@ -353,7 +342,6 @@ name = "std_detect"
 version = "0.1.5"
 dependencies = [
  "cfg-if",
- "compiler_builtins",
  "libc",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
@@ -381,11 +369,10 @@ dependencies = [
 
 [[package]]
 name = "unicode-width"
-version = "0.1.14"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
+checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c"
 dependencies = [
- "compiler_builtins",
  "rustc-std-workspace-core",
  "rustc-std-workspace-std",
 ]
@@ -403,9 +390,9 @@ dependencies = [
 
 [[package]]
 name = "unwinding"
-version = "0.2.6"
+version = "0.2.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8393f2782b6060a807337ff353780c1ca15206f9ba2424df18cb6e733bd7b345"
+checksum = "7d80f6c2bfede213d9a90b4a14f3eb99b84e33c52df6c1a15de0a100f5a88751"
 dependencies = [
  "compiler_builtins",
  "gimli",
@@ -414,11 +401,10 @@ dependencies = [
 
 [[package]]
 name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
+version = "0.11.1+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
 dependencies = [
- "compiler_builtins",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
 ]
diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs
index 8b448a18402..48849bf7536 100644
--- a/library/alloc/src/ffi/c_str.rs
+++ b/library/alloc/src/ffi/c_str.rs
@@ -714,6 +714,8 @@ impl ops::Deref for CString {
     }
 }
 
+/// Delegates to the [`CStr`] implementation of [`fmt::Debug`],
+/// showing invalid UTF-8 as hex escapes.
 #[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Debug for CString {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
diff --git a/library/alloctests/tests/slice.rs b/library/alloctests/tests/slice.rs
index 2516563187f..1e15d54d979 100644
--- a/library/alloctests/tests/slice.rs
+++ b/library/alloctests/tests/slice.rs
@@ -1636,6 +1636,19 @@ fn test_chunk_by() {
     assert_eq!(iter.next_back(), Some(&[1][..]));
     assert_eq!(iter.next(), Some(&[2, 2, 2][..]));
     assert_eq!(iter.next_back(), None);
+
+    let mut iter = slice.chunk_by(|a, b| a == b);
+    assert_eq!(iter.next(), Some(&[1, 1, 1][..]));
+    assert_eq!(iter.next(), Some(&[3, 3][..]));
+    let mut iter_clone = iter.clone();
+    assert_eq!(iter.next(), Some(&[2, 2, 2][..]));
+    assert_eq!(iter.next(), Some(&[1][..]));
+    assert_eq!(iter.next(), Some(&[0][..]));
+    assert_eq!(iter.next(), None);
+    assert_eq!(iter_clone.next(), Some(&[2, 2, 2][..]));
+    assert_eq!(iter_clone.next(), Some(&[1][..]));
+    assert_eq!(iter_clone.next(), Some(&[0][..]));
+    assert_eq!(iter_clone.next(), None);
 }
 
 #[test]
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/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 595cc1fe025..f7a21072f53 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -162,10 +162,12 @@ impl fmt::Display for FromBytesUntilNulError {
     }
 }
 
+/// Shows the underlying bytes as a normal string, with invalid UTF-8
+/// presented as hex escape sequences.
 #[stable(feature = "cstr_debug", since = "1.3.0")]
 impl fmt::Debug for CStr {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "\"{}\"", self.to_bytes().escape_ascii())
+        fmt::Debug::fmt(crate::bstr::ByteStr::from_bytes(self.to_bytes()), f)
     }
 }
 
diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs
index dd9c379b666..ce878f2da4b 100644
--- a/library/core/src/fmt/num.rs
+++ b/library/core/src/fmt/num.rs
@@ -279,7 +279,7 @@ macro_rules! impl_Display {
                 // Format per two digits from the lookup table.
                 if remain > 9 {
                     // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
-                    // and the while condition ensures at least 2 more decimals.
+                    // and the if condition ensures at least 2 more decimals.
                     unsafe { core::hint::assert_unchecked(offset >= 2) }
                     // SAFETY: The offset counts down from its initial buf.len()
                     // without underflow due to the previous precondition.
@@ -565,93 +565,6 @@ mod imp {
 }
 impl_Exp!(i128, u128 as u128 via to_u128 named exp_u128);
 
-/// Helper function for writing a u64 into `buf` going from last to first, with `curr`.
-fn parse_u64_into<const N: usize>(mut n: u64, buf: &mut [MaybeUninit<u8>; N], curr: &mut usize) {
-    let buf_ptr = MaybeUninit::slice_as_mut_ptr(buf);
-    let lut_ptr = DEC_DIGITS_LUT.as_ptr();
-    assert!(*curr > 19);
-
-    // SAFETY:
-    // Writes at most 19 characters into the buffer. Guaranteed that any ptr into LUT is at most
-    // 198, so will never OOB. There is a check above that there are at least 19 characters
-    // remaining.
-    unsafe {
-        if n >= 1e16 as u64 {
-            let to_parse = n % 1e16 as u64;
-            n /= 1e16 as u64;
-
-            // Some of these are nops but it looks more elegant this way.
-            let d1 = ((to_parse / 1e14 as u64) % 100) << 1;
-            let d2 = ((to_parse / 1e12 as u64) % 100) << 1;
-            let d3 = ((to_parse / 1e10 as u64) % 100) << 1;
-            let d4 = ((to_parse / 1e8 as u64) % 100) << 1;
-            let d5 = ((to_parse / 1e6 as u64) % 100) << 1;
-            let d6 = ((to_parse / 1e4 as u64) % 100) << 1;
-            let d7 = ((to_parse / 1e2 as u64) % 100) << 1;
-            let d8 = ((to_parse / 1e0 as u64) % 100) << 1;
-
-            *curr -= 16;
-
-            ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(*curr + 0), 2);
-            ptr::copy_nonoverlapping(lut_ptr.add(d2 as usize), buf_ptr.add(*curr + 2), 2);
-            ptr::copy_nonoverlapping(lut_ptr.add(d3 as usize), buf_ptr.add(*curr + 4), 2);
-            ptr::copy_nonoverlapping(lut_ptr.add(d4 as usize), buf_ptr.add(*curr + 6), 2);
-            ptr::copy_nonoverlapping(lut_ptr.add(d5 as usize), buf_ptr.add(*curr + 8), 2);
-            ptr::copy_nonoverlapping(lut_ptr.add(d6 as usize), buf_ptr.add(*curr + 10), 2);
-            ptr::copy_nonoverlapping(lut_ptr.add(d7 as usize), buf_ptr.add(*curr + 12), 2);
-            ptr::copy_nonoverlapping(lut_ptr.add(d8 as usize), buf_ptr.add(*curr + 14), 2);
-        }
-        if n >= 1e8 as u64 {
-            let to_parse = n % 1e8 as u64;
-            n /= 1e8 as u64;
-
-            // Some of these are nops but it looks more elegant this way.
-            let d1 = ((to_parse / 1e6 as u64) % 100) << 1;
-            let d2 = ((to_parse / 1e4 as u64) % 100) << 1;
-            let d3 = ((to_parse / 1e2 as u64) % 100) << 1;
-            let d4 = ((to_parse / 1e0 as u64) % 100) << 1;
-            *curr -= 8;
-
-            ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(*curr + 0), 2);
-            ptr::copy_nonoverlapping(lut_ptr.add(d2 as usize), buf_ptr.add(*curr + 2), 2);
-            ptr::copy_nonoverlapping(lut_ptr.add(d3 as usize), buf_ptr.add(*curr + 4), 2);
-            ptr::copy_nonoverlapping(lut_ptr.add(d4 as usize), buf_ptr.add(*curr + 6), 2);
-        }
-        // `n` < 1e8 < (1 << 32)
-        let mut n = n as u32;
-        if n >= 1e4 as u32 {
-            let to_parse = n % 1e4 as u32;
-            n /= 1e4 as u32;
-
-            let d1 = (to_parse / 100) << 1;
-            let d2 = (to_parse % 100) << 1;
-            *curr -= 4;
-
-            ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(*curr + 0), 2);
-            ptr::copy_nonoverlapping(lut_ptr.add(d2 as usize), buf_ptr.add(*curr + 2), 2);
-        }
-
-        // `n` < 1e4 < (1 << 16)
-        let mut n = n as u16;
-        if n >= 100 {
-            let d1 = (n % 100) << 1;
-            n /= 100;
-            *curr -= 2;
-            ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(*curr), 2);
-        }
-
-        // decode last 1 or 2 chars
-        if n < 10 {
-            *curr -= 1;
-            *buf_ptr.add(*curr) = (n as u8) + b'0';
-        } else {
-            let d1 = n << 1;
-            *curr -= 2;
-            ptr::copy_nonoverlapping(lut_ptr.add(d1 as usize), buf_ptr.add(*curr), 2);
-        }
-    }
-}
-
 #[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Display for u128 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -662,90 +575,153 @@ impl fmt::Display for u128 {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Display for i128 {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let is_nonnegative = *self >= 0;
-        let n = if is_nonnegative {
-            self.to_u128()
-        } else {
-            // convert the negative num to positive by summing 1 to its 2s complement
-            (!self.to_u128()).wrapping_add(1)
-        };
-        fmt_u128(n, is_nonnegative, f)
+        fmt_u128(self.unsigned_abs(), *self >= 0, f)
     }
 }
 
-/// Specialized optimization for u128. Instead of taking two items at a time, it splits
-/// into at most 2 u64s, and then chunks by 10e16, 10e8, 10e4, 10e2, and then 10e1.
-/// It also has to handle 1 last item, as 10^40 > 2^128 > 10^39, whereas
-/// 10^20 > 2^64 > 10^19.
+/// Format optimized for u128. Computation of 128 bits is limited by proccessing
+/// in batches of 16 decimals at a time.
 fn fmt_u128(n: u128, is_nonnegative: bool, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+    // Optimize common-case zero, which would also need special treatment due to
+    // its "leading" zero.
+    if n == 0 {
+        return f.pad_integral(true, "", "0");
+    }
+
+    // U128::MAX has 39 significant-decimals.
     const MAX_DEC_N: usize = u128::MAX.ilog(10) as usize + 1;
+    // Buffer decimals with right alignment.
     let mut buf = [MaybeUninit::<u8>::uninit(); MAX_DEC_N];
-    let mut curr = buf.len();
-
-    let (n, rem) = udiv_1e19(n);
-    parse_u64_into(rem, &mut buf, &mut curr);
-
-    if n != 0 {
-        // 0 pad up to point
-        let target = buf.len() - 19;
-        // SAFETY: Guaranteed that we wrote at most 19 bytes, and there must be space
-        // remaining since it has length 39
-        unsafe {
-            ptr::write_bytes(
-                MaybeUninit::slice_as_mut_ptr(&mut buf).add(target),
-                b'0',
-                curr - target,
-            );
-        }
-        curr = target;
-
-        let (n, rem) = udiv_1e19(n);
-        parse_u64_into(rem, &mut buf, &mut curr);
-        // Should this following branch be annotated with unlikely?
-        if n != 0 {
-            let target = buf.len() - 38;
-            // The raw `buf_ptr` pointer is only valid until `buf` is used the next time,
-            // buf `buf` is not used in this scope so we are good.
-            let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf);
-            // SAFETY: At this point we wrote at most 38 bytes, pad up to that point,
-            // There can only be at most 1 digit remaining.
-            unsafe {
-                ptr::write_bytes(buf_ptr.add(target), b'0', curr - target);
-                curr = target - 1;
-                *buf_ptr.add(curr) = (n as u8) + b'0';
-            }
+
+    // Take the 16 least-significant decimals.
+    let (quot_1e16, mod_1e16) = div_rem_1e16(n);
+    let (mut remain, mut offset) = if quot_1e16 == 0 {
+        (mod_1e16, MAX_DEC_N)
+    } else {
+        // Write digits at buf[23..39].
+        enc_16lsd::<{ MAX_DEC_N - 16 }>(&mut buf, mod_1e16);
+
+        // Take another 16 decimals.
+        let (quot2, mod2) = div_rem_1e16(quot_1e16);
+        if quot2 == 0 {
+            (mod2, MAX_DEC_N - 16)
+        } else {
+            // Write digits at buf[7..23].
+            enc_16lsd::<{ MAX_DEC_N - 32 }>(&mut buf, mod2);
+            // Quot2 has at most 7 decimals remaining after two 1e16 divisions.
+            (quot2 as u64, MAX_DEC_N - 32)
         }
+    };
+
+    // Format per four digits from the lookup table.
+    while remain > 999 {
+        // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
+        // and the while condition ensures at least 4 more decimals.
+        unsafe { core::hint::assert_unchecked(offset >= 4) }
+        // SAFETY: The offset counts down from its initial buf.len()
+        // without underflow due to the previous precondition.
+        unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
+        offset -= 4;
+
+        // pull two pairs
+        let quad = remain % 1_00_00;
+        remain /= 1_00_00;
+        let pair1 = (quad / 100) as usize;
+        let pair2 = (quad % 100) as usize;
+        buf[offset + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]);
+        buf[offset + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]);
+        buf[offset + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]);
+        buf[offset + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]);
+    }
+
+    // Format per two digits from the lookup table.
+    if remain > 9 {
+        // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
+        // and the if condition ensures at least 2 more decimals.
+        unsafe { core::hint::assert_unchecked(offset >= 2) }
+        // SAFETY: The offset counts down from its initial buf.len()
+        // without underflow due to the previous precondition.
+        unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
+        offset -= 2;
+
+        let pair = (remain % 100) as usize;
+        remain /= 100;
+        buf[offset + 0].write(DEC_DIGITS_LUT[pair * 2 + 0]);
+        buf[offset + 1].write(DEC_DIGITS_LUT[pair * 2 + 1]);
+    }
+
+    // Format the last remaining digit, if any.
+    if remain != 0 {
+        // SAFETY: All of the decimals fit in buf due to MAX_DEC_N
+        // and the if condition ensures (at least) 1 more decimals.
+        unsafe { core::hint::assert_unchecked(offset >= 1) }
+        // SAFETY: The offset counts down from its initial buf.len()
+        // without underflow due to the previous precondition.
+        unsafe { core::hint::assert_unchecked(offset <= buf.len()) }
+        offset -= 1;
+
+        // Either the compiler sees that remain < 10, or it prevents
+        // a boundary check up next.
+        let last = (remain & 15) as usize;
+        buf[offset].write(DEC_DIGITS_LUT[last * 2 + 1]);
+        // not used: remain = 0;
     }
 
-    // SAFETY: `curr` > 0 (since we made `buf` large enough), and all the chars are valid
-    // UTF-8 since `DEC_DIGITS_LUT` is
-    let buf_slice = unsafe {
+    // SAFETY: All buf content since offset is set.
+    let written = unsafe { buf.get_unchecked(offset..) };
+    // SAFETY: Writes use ASCII from the lookup table exclusively.
+    let as_str = unsafe {
         str::from_utf8_unchecked(slice::from_raw_parts(
-            MaybeUninit::slice_as_mut_ptr(&mut buf).add(curr),
-            buf.len() - curr,
+            MaybeUninit::slice_as_ptr(written),
+            written.len(),
         ))
     };
-    f.pad_integral(is_nonnegative, "", buf_slice)
+    f.pad_integral(is_nonnegative, "", as_str)
 }
 
-/// Partition of `n` into n > 1e19 and rem <= 1e19
+/// Encodes the 16 least-significant decimals of n into `buf[OFFSET .. OFFSET +
+/// 16 ]`.
+fn enc_16lsd<const OFFSET: usize>(buf: &mut [MaybeUninit<u8>; 39], n: u64) {
+    // Consume the least-significant decimals from a working copy.
+    let mut remain = n;
+
+    // Format per four digits from the lookup table.
+    for quad_index in (0..4).rev() {
+        // pull two pairs
+        let quad = remain % 1_00_00;
+        remain /= 1_00_00;
+        let pair1 = (quad / 100) as usize;
+        let pair2 = (quad % 100) as usize;
+        buf[quad_index * 4 + OFFSET + 0].write(DEC_DIGITS_LUT[pair1 * 2 + 0]);
+        buf[quad_index * 4 + OFFSET + 1].write(DEC_DIGITS_LUT[pair1 * 2 + 1]);
+        buf[quad_index * 4 + OFFSET + 2].write(DEC_DIGITS_LUT[pair2 * 2 + 0]);
+        buf[quad_index * 4 + OFFSET + 3].write(DEC_DIGITS_LUT[pair2 * 2 + 1]);
+    }
+}
+
+/// Euclidean division plus remainder with constant 1E16 basically consumes 16
+/// decimals from n.
 ///
-/// Integer division algorithm is based on the following paper:
+/// The integer division algorithm is based on the following paper:
 ///
 ///   T. Granlund and P. Montgomery, “Division by Invariant Integers Using Multiplication”
 ///   in Proc. of the SIGPLAN94 Conference on Programming Language Design and
 ///   Implementation, 1994, pp. 61–72
 ///
-fn udiv_1e19(n: u128) -> (u128, u64) {
-    const DIV: u64 = 1e19 as u64;
-    const FACTOR: u128 = 156927543384667019095894735580191660403;
+#[inline]
+fn div_rem_1e16(n: u128) -> (u128, u64) {
+    const D: u128 = 1_0000_0000_0000_0000;
+    // The check inlines well with the caller flow.
+    if n < D {
+        return (0, n as u64);
+    }
 
-    let quot = if n < 1 << 83 {
-        ((n >> 19) as u64 / (DIV >> 19)) as u128
-    } else {
-        n.widening_mul(FACTOR).1 >> 62
-    };
+    // These constant values are computed with the CHOOSE_MULTIPLIER procedure
+    // from the Granlund & Montgomery paper, using N=128, prec=128 and d=1E16.
+    const M_HIGH: u128 = 76624777043294442917917351357515459181;
+    const SH_POST: u8 = 51;
 
-    let rem = (n - quot * DIV as u128) as u64;
-    (quot, rem)
+    let quot = n.widening_mul(M_HIGH).1 >> SH_POST;
+    let rem = n - quot * D;
+    (quot, rem as u64)
 }
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index 4434ceb49bc..7ba48cc7268 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -926,8 +926,7 @@ pub const unsafe fn slice_get_unchecked<
 pub fn ptr_mask<T>(ptr: *const T, mask: usize) -> *const T;
 
 /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with
-/// a size of `count` * `size_of::<T>()` and an alignment of
-/// `min_align_of::<T>()`
+/// a size of `count` * `size_of::<T>()` and an alignment of `align_of::<T>()`.
 ///
 /// This intrinsic does not have a stable counterpart.
 /// # Safety
@@ -941,8 +940,7 @@ pub fn ptr_mask<T>(ptr: *const T, mask: usize) -> *const T;
 #[rustc_nounwind]
 pub unsafe fn volatile_copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: usize);
 /// Equivalent to the appropriate `llvm.memmove.p0i8.0i8.*` intrinsic, with
-/// a size of `count * size_of::<T>()` and an alignment of
-/// `min_align_of::<T>()`
+/// a size of `count * size_of::<T>()` and an alignment of `align_of::<T>()`.
 ///
 /// The volatile parameter is set to `true`, so it will not be optimized out
 /// unless size is equal to zero.
@@ -952,8 +950,7 @@ pub unsafe fn volatile_copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T,
 #[rustc_nounwind]
 pub unsafe fn volatile_copy_memory<T>(dst: *mut T, src: *const T, count: usize);
 /// Equivalent to the appropriate `llvm.memset.p0i8.*` intrinsic, with a
-/// size of `count * size_of::<T>()` and an alignment of
-/// `min_align_of::<T>()`.
+/// size of `count * size_of::<T>()` and an alignment of `align_of::<T>()`.
 ///
 /// This intrinsic does not have a stable counterpart.
 /// # Safety
@@ -2649,7 +2646,7 @@ pub const fn size_of<T>() -> usize;
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
-pub const fn min_align_of<T>() -> usize;
+pub const fn align_of<T>() -> usize;
 
 /// Returns the number of variants of the type `T` cast to a `usize`;
 /// if `T` has no variants, returns `0`. Uninhabited variants will be counted.
@@ -2689,7 +2686,7 @@ pub const unsafe fn size_of_val<T: ?Sized>(ptr: *const T) -> usize;
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic]
 #[rustc_intrinsic_const_stable_indirect]
-pub const unsafe fn min_align_of_val<T: ?Sized>(ptr: *const T) -> usize;
+pub const unsafe fn align_of_val<T: ?Sized>(ptr: *const T) -> usize;
 
 /// Gets a static string slice containing the name of a type.
 ///
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/mem/mod.rs b/library/core/src/mem/mod.rs
index 0a5f3ee35b1..6819face4c2 100644
--- a/library/core/src/mem/mod.rs
+++ b/library/core/src/mem/mod.rs
@@ -412,7 +412,7 @@ pub const unsafe fn size_of_val_raw<T: ?Sized>(val: *const T) -> usize {
 #[stable(feature = "rust1", since = "1.0.0")]
 #[deprecated(note = "use `align_of` instead", since = "1.2.0", suggestion = "align_of")]
 pub fn min_align_of<T>() -> usize {
-    intrinsics::min_align_of::<T>()
+    intrinsics::align_of::<T>()
 }
 
 /// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to in
@@ -436,7 +436,7 @@ pub fn min_align_of<T>() -> usize {
 #[deprecated(note = "use `align_of_val` instead", since = "1.2.0", suggestion = "align_of_val")]
 pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
     // SAFETY: val is a reference, so it's a valid raw pointer
-    unsafe { intrinsics::min_align_of_val(val) }
+    unsafe { intrinsics::align_of_val(val) }
 }
 
 /// Returns the [ABI]-required minimum alignment of a type in bytes.
@@ -458,7 +458,7 @@ pub fn min_align_of_val<T: ?Sized>(val: &T) -> usize {
 #[rustc_promotable]
 #[rustc_const_stable(feature = "const_align_of", since = "1.24.0")]
 pub const fn align_of<T>() -> usize {
-    intrinsics::min_align_of::<T>()
+    intrinsics::align_of::<T>()
 }
 
 /// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to in
@@ -477,10 +477,9 @@ pub const fn align_of<T>() -> usize {
 #[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "const_align_of_val", since = "1.85.0")]
-#[allow(deprecated)]
 pub const fn align_of_val<T: ?Sized>(val: &T) -> usize {
     // SAFETY: val is a reference, so it's a valid raw pointer
-    unsafe { intrinsics::min_align_of_val(val) }
+    unsafe { intrinsics::align_of_val(val) }
 }
 
 /// Returns the [ABI]-required minimum alignment of the type of the value that `val` points to in
@@ -527,7 +526,7 @@ pub const fn align_of_val<T: ?Sized>(val: &T) -> usize {
 #[unstable(feature = "layout_for_ptr", issue = "69835")]
 pub const unsafe fn align_of_val_raw<T: ?Sized>(val: *const T) -> usize {
     // SAFETY: the caller must provide a valid raw pointer
-    unsafe { intrinsics::min_align_of_val(val) }
+    unsafe { intrinsics::align_of_val(val) }
 }
 
 /// Returns `true` if dropping values of type `T` matters.
@@ -637,8 +636,6 @@ pub const fn needs_drop<T: ?Sized>() -> bool {
 #[inline(always)]
 #[must_use]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated_in_future)]
-#[allow(deprecated)]
 #[rustc_diagnostic_item = "mem_zeroed"]
 #[track_caller]
 #[rustc_const_stable(feature = "const_mem_zeroed", since = "1.75.0")]
@@ -677,8 +674,6 @@ pub const unsafe fn zeroed<T>() -> T {
 #[must_use]
 #[deprecated(since = "1.39.0", note = "use `mem::MaybeUninit` instead")]
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated_in_future)]
-#[allow(deprecated)]
 #[rustc_diagnostic_item = "mem_uninitialized"]
 #[track_caller]
 pub unsafe fn uninitialized<T>() -> T {
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 65560f63c18..3a7bc902f93 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -239,7 +239,6 @@ macro_rules! int_impl {
         /// Basic usage:
         ///
         /// ```
-        ///
         #[doc = concat!("let n = -1", stringify!($SelfT), ";")]
         ///
         #[doc = concat!("assert_eq!(n.cast_unsigned(), ", stringify!($UnsignedT), "::MAX);")]
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 5c73bddbef2..ab2fcff61cd 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -1053,7 +1053,6 @@ impl u8 {
     /// # Examples
     ///
     /// ```
-    ///
     /// assert_eq!("0", b'0'.escape_ascii().to_string());
     /// assert_eq!("\\t", b'\t'.escape_ascii().to_string());
     /// assert_eq!("\\r", b'\r'.escape_ascii().to_string());
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 5f82e6af86b..4ee0e7326b3 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -213,6 +213,30 @@ macro_rules! uint_impl {
             (!self).trailing_zeros()
         }
 
+        /// Returns the minimum number of bits required to represent `self`.
+        ///
+        /// This method returns zero if `self` is zero.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(uint_bit_width)]
+        ///
+        #[doc = concat!("assert_eq!(0_", stringify!($SelfT), ".bit_width(), 0);")]
+        #[doc = concat!("assert_eq!(0b111_", stringify!($SelfT), ".bit_width(), 3);")]
+        #[doc = concat!("assert_eq!(0b1110_", stringify!($SelfT), ".bit_width(), 4);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.bit_width(), ", stringify!($BITS), ");")]
+        /// ```
+        #[unstable(feature = "uint_bit_width", issue = "142326")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline(always)]
+        pub const fn bit_width(self) -> u32 {
+            Self::BITS - self.leading_zeros()
+        }
+
         /// Returns `self` with only the most significant bit set, or `0` if
         /// the input is `0`.
         ///
diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs
index ef7e6f9c2f4..26661b20c12 100644
--- a/library/core/src/ops/control_flow.rs
+++ b/library/core/src/ops/control_flow.rs
@@ -98,7 +98,7 @@ pub enum ControlFlow<B, C = ()> {
     // is a no-op conversion in the `Try` implementation.
 }
 
-#[unstable(feature = "try_trait_v2", issue = "84277")]
+#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
 impl<B, C> ops::Try for ControlFlow<B, C> {
     type Output = C;
     type Residual = ControlFlow<B, convert::Infallible>;
@@ -117,7 +117,7 @@ impl<B, C> ops::Try for ControlFlow<B, C> {
     }
 }
 
-#[unstable(feature = "try_trait_v2", issue = "84277")]
+#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
 // Note: manually specifying the residual type instead of using the default to work around
 // https://github.com/rust-lang/rust/issues/99940
 impl<B, C> ops::FromResidual<ControlFlow<B, convert::Infallible>> for ControlFlow<B, C> {
diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs
index 1658f0e5a36..87dd873fdb5 100644
--- a/library/core/src/ops/mod.rs
+++ b/library/core/src/ops/mod.rs
@@ -194,7 +194,7 @@ pub use self::try_trait::Residual;
 #[unstable(feature = "try_trait_v2_yeet", issue = "96374")]
 pub use self::try_trait::Yeet;
 pub(crate) use self::try_trait::{ChangeOutputType, NeverShortCircuit};
-#[unstable(feature = "try_trait_v2", issue = "84277")]
+#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
 pub use self::try_trait::{FromResidual, Try};
 #[unstable(feature = "coerce_unsized", issue = "18598")]
 pub use self::unsize::CoerceUnsized;
diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs
index bac8ffb074b..aebbddb4f1c 100644
--- a/library/core/src/ops/try_trait.rs
+++ b/library/core/src/ops/try_trait.rs
@@ -112,7 +112,7 @@ use crate::ops::ControlFlow;
 ///     R::from_output(accum)
 /// }
 /// ```
-#[unstable(feature = "try_trait_v2", issue = "84277")]
+#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
 #[rustc_on_unimplemented(
     on(
         all(from_desugaring = "TryBlock"),
@@ -130,7 +130,7 @@ use crate::ops::ControlFlow;
 #[lang = "Try"]
 pub trait Try: FromResidual {
     /// The type of the value produced by `?` when *not* short-circuiting.
-    #[unstable(feature = "try_trait_v2", issue = "84277")]
+    #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
     type Output;
 
     /// The type of the value passed to [`FromResidual::from_residual`]
@@ -154,7 +154,7 @@ pub trait Try: FromResidual {
     /// then typically you can use `Foo<std::convert::Infallible>` as its `Residual`
     /// type: that type will have a "hole" in the correct place, and will maintain the
     /// "foo-ness" of the residual so other types need to opt-in to interconversion.
-    #[unstable(feature = "try_trait_v2", issue = "84277")]
+    #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
     type Residual;
 
     /// Constructs the type from its `Output` type.
@@ -186,7 +186,7 @@ pub trait Try: FromResidual {
     /// assert_eq!(r, Some(4));
     /// ```
     #[lang = "from_output"]
-    #[unstable(feature = "try_trait_v2", issue = "84277")]
+    #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
     fn from_output(output: Self::Output) -> Self;
 
     /// Used in `?` to decide whether the operator should produce a value
@@ -213,7 +213,7 @@ pub trait Try: FromResidual {
     /// );
     /// ```
     #[lang = "branch"]
-    #[unstable(feature = "try_trait_v2", issue = "84277")]
+    #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
     fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
 }
 
@@ -303,7 +303,7 @@ pub trait Try: FromResidual {
     ),
 )]
 #[rustc_diagnostic_item = "FromResidual"]
-#[unstable(feature = "try_trait_v2", issue = "84277")]
+#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
 pub trait FromResidual<R = <Self as Try>::Residual> {
     /// Constructs the type from a compatible `Residual` type.
     ///
@@ -326,7 +326,7 @@ pub trait FromResidual<R = <Self as Try>::Residual> {
     /// );
     /// ```
     #[lang = "from_residual"]
-    #[unstable(feature = "try_trait_v2", issue = "84277")]
+    #[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
     fn from_residual(residual: R) -> Self;
 }
 
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index c04754848b4..f2a1e901188 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -2532,7 +2532,7 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> {
     }
 }
 
-#[unstable(feature = "try_trait_v2", issue = "84277")]
+#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
 impl<T> ops::Try for Option<T> {
     type Output = T;
     type Residual = Option<convert::Infallible>;
@@ -2551,7 +2551,7 @@ impl<T> ops::Try for Option<T> {
     }
 }
 
-#[unstable(feature = "try_trait_v2", issue = "84277")]
+#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
 // Note: manually specifying the residual type instead of using the default to work around
 // https://github.com/rust-lang/rust/issues/99940
 impl<T> ops::FromResidual<Option<convert::Infallible>> for Option<T> {
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index cb1cf818bf0..0ac887f99dc 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -1847,6 +1847,8 @@ mod prim_ref {}
 /// - If `T` is guaranteed to be subject to the [null pointer
 ///   optimization](option/index.html#representation), and `E` is an enum satisfying the following
 ///   requirements, then `T` and `E` are ABI-compatible. Such an enum `E` is called "option-like".
+///   - The enum `E` uses the [`Rust` representation], and is not modified by the `align` or
+///     `packed` representation modifiers.
 ///   - The enum `E` has exactly two variants.
 ///   - One variant has exactly one field, of type `T`.
 ///   - All fields of the other variant are zero-sized with 1-byte alignment.
@@ -1920,6 +1922,7 @@ mod prim_ref {}
 /// [`Pointer`]: fmt::Pointer
 /// [`UnwindSafe`]: panic::UnwindSafe
 /// [`RefUnwindSafe`]: panic::RefUnwindSafe
+/// [`Rust` representation]: <https://doc.rust-lang.org/reference/type-layout.html#the-rust-representation>
 ///
 /// In addition, all *safe* function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`], because
 /// these traits are specially known to the compiler.
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/result.rs b/library/core/src/result.rs
index 23e32c2e0f0..3a84ea66ad4 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -2051,7 +2051,7 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> {
     }
 }
 
-#[unstable(feature = "try_trait_v2", issue = "84277")]
+#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
 impl<T, E> ops::Try for Result<T, E> {
     type Output = T;
     type Residual = Result<convert::Infallible, E>;
@@ -2070,7 +2070,7 @@ impl<T, E> ops::Try for Result<T, E> {
     }
 }
 
-#[unstable(feature = "try_trait_v2", issue = "84277")]
+#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
 impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Result<T, F> {
     #[inline]
     #[track_caller]
diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs
index d91f8bba548..b4d9a1b1ca4 100644
--- a/library/core/src/slice/ascii.rs
+++ b/library/core/src/slice/ascii.rs
@@ -128,7 +128,6 @@ impl [u8] {
     /// # Examples
     ///
     /// ```
-    ///
     /// let s = b"0\t\r\n'\"\\\x9d";
     /// let escaped = s.escape_ascii().to_string();
     /// assert_eq!(escaped, "0\\t\\r\\n\\'\\\"\\\\\\x9d");
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index 85a5e89a49e..6def6ae8530 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -3376,6 +3376,13 @@ where
 #[stable(feature = "slice_group_by", since = "1.77.0")]
 impl<'a, T: 'a, P> FusedIterator for ChunkBy<'a, T, P> where P: FnMut(&T, &T) -> bool {}
 
+#[stable(feature = "slice_group_by_clone", since = "CURRENT_RUSTC_VERSION")]
+impl<'a, T: 'a, P: Clone> Clone for ChunkBy<'a, T, P> {
+    fn clone(&self) -> Self {
+        Self { slice: self.slice, predicate: self.predicate.clone() }
+    }
+}
+
 #[stable(feature = "slice_group_by", since = "1.77.0")]
 impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for ChunkBy<'a, T, P> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
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/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index 4f9f2936564..04c8d1473b0 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -891,6 +891,19 @@ impl AtomicBool {
     ///            Err(false));
     /// assert_eq!(some_bool.load(Ordering::Relaxed), false);
     /// ```
+    ///
+    /// # Considerations
+    ///
+    /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
+    /// of CAS operations. In particular, a load of the value followed by a successful
+    /// `compare_exchange` with the previous load *does not ensure* that other threads have not
+    /// changed the value in the interim. This is usually important when the *equality* check in
+    /// the `compare_exchange` is being used to check the *identity* of a value, but equality
+    /// does not necessarily imply identity. In this case, `compare_exchange` can lead to the
+    /// [ABA problem].
+    ///
+    /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
+    /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
     #[inline]
     #[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
     #[doc(alias = "compare_and_swap")]
@@ -973,6 +986,19 @@ impl AtomicBool {
     ///     }
     /// }
     /// ```
+    ///
+    /// # Considerations
+    ///
+    /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
+    /// of CAS operations. In particular, a load of the value followed by a successful
+    /// `compare_exchange` with the previous load *does not ensure* that other threads have not
+    /// changed the value in the interim. This is usually important when the *equality* check in
+    /// the `compare_exchange` is being used to check the *identity* of a value, but equality
+    /// does not necessarily imply identity. In this case, `compare_exchange` can lead to the
+    /// [ABA problem].
+    ///
+    /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
+    /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
     #[inline]
     #[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
     #[doc(alias = "compare_and_swap")]
@@ -1271,11 +1297,14 @@ impl AtomicBool {
     ///
     /// # Considerations
     ///
-    /// This method is not magic; it is not provided by the hardware.
-    /// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks.
-    /// In particular, this method will not circumvent the [ABA Problem].
+    /// This method is not magic; it is not provided by the hardware, and does not act like a
+    /// critical section or mutex.
+    ///
+    /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
+    /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem].
     ///
     /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
+    /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
     ///
     /// # Examples
     ///
@@ -1338,11 +1367,14 @@ impl AtomicBool {
     ///
     /// # Considerations
     ///
-    /// This method is not magic; it is not provided by the hardware.
-    /// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks.
-    /// In particular, this method will not circumvent the [ABA Problem].
+    /// This method is not magic; it is not provided by the hardware, and does not act like a
+    /// critical section or mutex.
+    ///
+    /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
+    /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem].
     ///
     /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
+    /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
     ///
     /// # Examples
     ///
@@ -1393,11 +1425,14 @@ impl AtomicBool {
     ///
     /// # Considerations
     ///
-    /// This method is not magic; it is not provided by the hardware.
-    /// It is implemented in terms of [`AtomicBool::compare_exchange_weak`], and suffers from the same drawbacks.
-    /// In particular, this method will not circumvent the [ABA Problem].
+    /// This method is not magic; it is not provided by the hardware, and does not act like a
+    /// critical section or mutex.
+    ///
+    /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
+    /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem].
     ///
     /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
+    /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
     ///
     /// # Examples
     ///
@@ -1825,6 +1860,20 @@ impl<T> AtomicPtr<T> {
     /// let value = some_ptr.compare_exchange(ptr, other_ptr,
     ///                                       Ordering::SeqCst, Ordering::Relaxed);
     /// ```
+    ///
+    /// # Considerations
+    ///
+    /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
+    /// of CAS operations. In particular, a load of the value followed by a successful
+    /// `compare_exchange` with the previous load *does not ensure* that other threads have not
+    /// changed the value in the interim. This is usually important when the *equality* check in
+    /// the `compare_exchange` is being used to check the *identity* of a value, but equality
+    /// does not necessarily imply identity. This is a particularly common case for pointers, as
+    /// a pointer holding the same address does not imply that the same object exists at that
+    /// address! In this case, `compare_exchange` can lead to the [ABA problem].
+    ///
+    /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
+    /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
     #[inline]
     #[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
     #[cfg(target_has_atomic = "ptr")]
@@ -1874,6 +1923,20 @@ impl<T> AtomicPtr<T> {
     ///     }
     /// }
     /// ```
+    ///
+    /// # Considerations
+    ///
+    /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
+    /// of CAS operations. In particular, a load of the value followed by a successful
+    /// `compare_exchange` with the previous load *does not ensure* that other threads have not
+    /// changed the value in the interim. This is usually important when the *equality* check in
+    /// the `compare_exchange` is being used to check the *identity* of a value, but equality
+    /// does not necessarily imply identity. This is a particularly common case for pointers, as
+    /// a pointer holding the same address does not imply that the same object exists at that
+    /// address! In this case, `compare_exchange` can lead to the [ABA problem].
+    ///
+    /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
+    /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
     #[inline]
     #[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
     #[cfg(target_has_atomic = "ptr")]
@@ -1917,11 +1980,15 @@ impl<T> AtomicPtr<T> {
     ///
     /// # Considerations
     ///
-    /// This method is not magic; it is not provided by the hardware.
-    /// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks.
-    /// In particular, this method will not circumvent the [ABA Problem].
+    /// This method is not magic; it is not provided by the hardware, and does not act like a
+    /// critical section or mutex.
+    ///
+    /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
+    /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem],
+    /// which is a particularly common pitfall for pointers!
     ///
     /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
+    /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
     ///
     /// # Examples
     ///
@@ -1992,11 +2059,15 @@ impl<T> AtomicPtr<T> {
     ///
     /// # Considerations
     ///
-    /// This method is not magic; it is not provided by the hardware.
-    /// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks.
-    /// In particular, this method will not circumvent the [ABA Problem].
+    /// This method is not magic; it is not provided by the hardware, and does not act like a
+    /// critical section or mutex.
+    ///
+    /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
+    /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem],
+    /// which is a particularly common pitfall for pointers!
     ///
     /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
+    /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
     ///
     /// # Examples
     ///
@@ -2057,11 +2128,15 @@ impl<T> AtomicPtr<T> {
     ///
     /// # Considerations
     ///
-    /// This method is not magic; it is not provided by the hardware.
-    /// It is implemented in terms of [`AtomicPtr::compare_exchange_weak`], and suffers from the same drawbacks.
-    /// In particular, this method will not circumvent the [ABA Problem].
+    /// This method is not magic; it is not provided by the hardware, and does not act like a
+    /// critical section or mutex.
+    ///
+    /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
+    /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem],
+    /// which is a particularly common pitfall for pointers!
     ///
     /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
+    /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
     ///
     /// # Examples
     ///
@@ -2967,6 +3042,20 @@ macro_rules! atomic_int {
             ///            Err(10));
             /// assert_eq!(some_var.load(Ordering::Relaxed), 10);
             /// ```
+            ///
+            /// # Considerations
+            ///
+            /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
+            /// of CAS operations. In particular, a load of the value followed by a successful
+            /// `compare_exchange` with the previous load *does not ensure* that other threads have not
+            /// changed the value in the interim! This is usually important when the *equality* check in
+            /// the `compare_exchange` is being used to check the *identity* of a value, but equality
+            /// does not necessarily imply identity. This is a particularly common case for pointers, as
+            /// a pointer holding the same address does not imply that the same object exists at that
+            /// address! In this case, `compare_exchange` can lead to the [ABA problem].
+            ///
+            /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
+            /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
             #[inline]
             #[$stable_cxchg]
             #[$cfg_cas]
@@ -3016,6 +3105,20 @@ macro_rules! atomic_int {
             ///     }
             /// }
             /// ```
+            ///
+            /// # Considerations
+            ///
+            /// `compare_exchange` is a [compare-and-swap operation] and thus exhibits the usual downsides
+            /// of CAS operations. In particular, a load of the value followed by a successful
+            /// `compare_exchange` with the previous load *does not ensure* that other threads have not
+            /// changed the value in the interim. This is usually important when the *equality* check in
+            /// the `compare_exchange` is being used to check the *identity* of a value, but equality
+            /// does not necessarily imply identity. This is a particularly common case for pointers, as
+            /// a pointer holding the same address does not imply that the same object exists at that
+            /// address! In this case, `compare_exchange` can lead to the [ABA problem].
+            ///
+            /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
+            /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
             #[inline]
             #[$stable_cxchg]
             #[$cfg_cas]
@@ -3246,13 +3349,16 @@ macro_rules! atomic_int {
             ///
             /// # Considerations
             ///
-            /// This method is not magic; it is not provided by the hardware.
-            /// It is implemented in terms of
-            #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")]
-            /// and suffers from the same drawbacks.
-            /// In particular, this method will not circumvent the [ABA Problem].
+            /// This method is not magic; it is not provided by the hardware, and does not act like a
+            /// critical section or mutex.
+            ///
+            /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
+            /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]
+            /// if this atomic integer is an index or more generally if knowledge of only the *bitwise value*
+            /// of the atomic is not in and of itself sufficient to ensure any required preconditions.
             ///
             /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
+            /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
             ///
             /// # Examples
             ///
@@ -3309,13 +3415,16 @@ macro_rules! atomic_int {
             ///
             /// # Considerations
             ///
-            /// This method is not magic; it is not provided by the hardware.
-            /// It is implemented in terms of
-            #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")]
-            /// and suffers from the same drawbacks.
-            /// In particular, this method will not circumvent the [ABA Problem].
+            /// This method is not magic; it is not provided by the hardware, and does not act like a
+            /// critical section or mutex.
+            ///
+            /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
+            /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]
+            /// if this atomic integer is an index or more generally if knowledge of only the *bitwise value*
+            /// of the atomic is not in and of itself sufficient to ensure any required preconditions.
             ///
             /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
+            /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
             ///
             /// # Examples
             ///
@@ -3367,13 +3476,17 @@ macro_rules! atomic_int {
             ///
             /// # Considerations
             ///
-            /// This method is not magic; it is not provided by the hardware.
-            /// It is implemented in terms of
-            #[doc = concat!("[`", stringify!($atomic_type), "::compare_exchange_weak`],")]
-            /// and suffers from the same drawbacks.
-            /// In particular, this method will not circumvent the [ABA Problem].
+            /// [CAS operation]: https://en.wikipedia.org/wiki/Compare-and-swap
+            /// This method is not magic; it is not provided by the hardware, and does not act like a
+            /// critical section or mutex.
+            ///
+            /// It is implemented on top of an atomic [compare-and-swap operation], and thus is subject to
+            /// the usual drawbacks of CAS operations. In particular, be careful of the [ABA problem]
+            /// if this atomic integer is an index or more generally if knowledge of only the *bitwise value*
+            /// of the atomic is not in and of itself sufficient to ensure any required preconditions.
             ///
             /// [ABA Problem]: https://en.wikipedia.org/wiki/ABA_problem
+            /// [compare-and-swap operation]: https://en.wikipedia.org/wiki/Compare-and-swap
             ///
             /// # Examples
             ///
diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs
index 6aab22177ab..ca668361ef6 100644
--- a/library/core/src/task/poll.rs
+++ b/library/core/src/task/poll.rs
@@ -229,7 +229,7 @@ impl<T> From<T> for Poll<T> {
     }
 }
 
-#[unstable(feature = "try_trait_v2", issue = "84277")]
+#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
 impl<T, E> ops::Try for Poll<Result<T, E>> {
     type Output = Poll<T>;
     type Residual = Result<convert::Infallible, E>;
@@ -249,7 +249,7 @@ impl<T, E> ops::Try for Poll<Result<T, E>> {
     }
 }
 
-#[unstable(feature = "try_trait_v2", issue = "84277")]
+#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
 impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Poll<Result<T, F>> {
     #[inline]
     fn from_residual(x: Result<convert::Infallible, E>) -> Self {
@@ -259,7 +259,7 @@ impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Pol
     }
 }
 
-#[unstable(feature = "try_trait_v2", issue = "84277")]
+#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
 impl<T, E> ops::Try for Poll<Option<Result<T, E>>> {
     type Output = Poll<Option<T>>;
     type Residual = Result<convert::Infallible, E>;
@@ -280,7 +280,7 @@ impl<T, E> ops::Try for Poll<Option<Result<T, E>>> {
     }
 }
 
-#[unstable(feature = "try_trait_v2", issue = "84277")]
+#[unstable(feature = "try_trait_v2", issue = "84277", old_name = "try_trait")]
 impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>>
     for Poll<Option<Result<T, F>>>
 {
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index 9b8fefe42af..bb7efe582f7 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -104,6 +104,7 @@ impl RawWaker {
 /// synchronization. This is because [`LocalWaker`] is not thread safe itself, so it cannot
 /// be sent across threads.
 #[stable(feature = "futures_api", since = "1.36.0")]
+#[allow(unpredictable_function_pointer_comparisons)]
 #[derive(PartialEq, Copy, Clone, Debug)]
 pub struct RawWakerVTable {
     /// This function will be called when the [`RawWaker`] gets cloned, e.g. when
diff --git a/library/coretests/tests/ffi/cstr.rs b/library/coretests/tests/ffi/cstr.rs
index dc34240cd99..7d669cc1c3f 100644
--- a/library/coretests/tests/ffi/cstr.rs
+++ b/library/coretests/tests/ffi/cstr.rs
@@ -17,7 +17,7 @@ fn compares_as_u8s() {
 #[test]
 fn debug() {
     let s = c"abc\x01\x02\n\xE2\x80\xA6\xFF";
-    assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#);
+    assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n…\xff""#);
 }
 
 #[test]
diff --git a/library/coretests/tests/fmt/num.rs b/library/coretests/tests/fmt/num.rs
index bc387a46ea7..4c145b484dd 100644
--- a/library/coretests/tests/fmt/num.rs
+++ b/library/coretests/tests/fmt/num.rs
@@ -1,5 +1,29 @@
+use std::mem::size_of;
+
+#[test]
+fn test_format_int_zero() {
+    assert_eq!(format!("{}", 0), "0");
+    assert_eq!(format!("{:?}", 0), "0");
+    assert_eq!(format!("{:b}", 0), "0");
+    assert_eq!(format!("{:o}", 0), "0");
+    assert_eq!(format!("{:x}", 0), "0");
+    assert_eq!(format!("{:X}", 0), "0");
+    assert_eq!(format!("{:e}", 0), "0e0");
+    assert_eq!(format!("{:E}", 0), "0E0");
+
+    // again, with unsigned
+    assert_eq!(format!("{}", 0u32), "0");
+    assert_eq!(format!("{:?}", 0u32), "0");
+    assert_eq!(format!("{:b}", 0u32), "0");
+    assert_eq!(format!("{:o}", 0u32), "0");
+    assert_eq!(format!("{:x}", 0u32), "0");
+    assert_eq!(format!("{:X}", 0u32), "0");
+    assert_eq!(format!("{:e}", 0u32), "0e0");
+    assert_eq!(format!("{:E}", 0u32), "0E0");
+}
+
 #[test]
-fn test_format_int() {
+fn test_format_int_one() {
     // Formatting integers should select the right implementation based off
     // the type of the argument. Also, hex/octal/binary should be defined
     // for integers, but they shouldn't emit the negative sign.
@@ -8,87 +32,157 @@ fn test_format_int() {
     assert_eq!(format!("{}", 1i16), "1");
     assert_eq!(format!("{}", 1i32), "1");
     assert_eq!(format!("{}", 1i64), "1");
-    assert_eq!(format!("{}", -1isize), "-1");
-    assert_eq!(format!("{}", -1i8), "-1");
-    assert_eq!(format!("{}", -1i16), "-1");
-    assert_eq!(format!("{}", -1i32), "-1");
-    assert_eq!(format!("{}", -1i64), "-1");
+    assert_eq!(format!("{}", 1i128), "1");
     assert_eq!(format!("{:?}", 1isize), "1");
     assert_eq!(format!("{:?}", 1i8), "1");
     assert_eq!(format!("{:?}", 1i16), "1");
     assert_eq!(format!("{:?}", 1i32), "1");
     assert_eq!(format!("{:?}", 1i64), "1");
+    assert_eq!(format!("{:?}", 1i128), "1");
     assert_eq!(format!("{:b}", 1isize), "1");
     assert_eq!(format!("{:b}", 1i8), "1");
     assert_eq!(format!("{:b}", 1i16), "1");
     assert_eq!(format!("{:b}", 1i32), "1");
     assert_eq!(format!("{:b}", 1i64), "1");
+    assert_eq!(format!("{:b}", 1i128), "1");
     assert_eq!(format!("{:x}", 1isize), "1");
     assert_eq!(format!("{:x}", 1i8), "1");
     assert_eq!(format!("{:x}", 1i16), "1");
     assert_eq!(format!("{:x}", 1i32), "1");
     assert_eq!(format!("{:x}", 1i64), "1");
+    assert_eq!(format!("{:x}", 1i128), "1");
     assert_eq!(format!("{:X}", 1isize), "1");
     assert_eq!(format!("{:X}", 1i8), "1");
     assert_eq!(format!("{:X}", 1i16), "1");
     assert_eq!(format!("{:X}", 1i32), "1");
     assert_eq!(format!("{:X}", 1i64), "1");
+    assert_eq!(format!("{:X}", 1i128), "1");
     assert_eq!(format!("{:o}", 1isize), "1");
     assert_eq!(format!("{:o}", 1i8), "1");
     assert_eq!(format!("{:o}", 1i16), "1");
     assert_eq!(format!("{:o}", 1i32), "1");
     assert_eq!(format!("{:o}", 1i64), "1");
+    assert_eq!(format!("{:o}", 1i128), "1");
     assert_eq!(format!("{:e}", 1isize), "1e0");
     assert_eq!(format!("{:e}", 1i8), "1e0");
     assert_eq!(format!("{:e}", 1i16), "1e0");
     assert_eq!(format!("{:e}", 1i32), "1e0");
     assert_eq!(format!("{:e}", 1i64), "1e0");
+    assert_eq!(format!("{:e}", 1i128), "1e0");
     assert_eq!(format!("{:E}", 1isize), "1E0");
     assert_eq!(format!("{:E}", 1i8), "1E0");
     assert_eq!(format!("{:E}", 1i16), "1E0");
     assert_eq!(format!("{:E}", 1i32), "1E0");
     assert_eq!(format!("{:E}", 1i64), "1E0");
+    assert_eq!(format!("{:E}", 1i128), "1E0");
 
+    // again, with unsigned
     assert_eq!(format!("{}", 1usize), "1");
     assert_eq!(format!("{}", 1u8), "1");
     assert_eq!(format!("{}", 1u16), "1");
     assert_eq!(format!("{}", 1u32), "1");
     assert_eq!(format!("{}", 1u64), "1");
+    assert_eq!(format!("{}", 1u128), "1");
     assert_eq!(format!("{:?}", 1usize), "1");
     assert_eq!(format!("{:?}", 1u8), "1");
     assert_eq!(format!("{:?}", 1u16), "1");
     assert_eq!(format!("{:?}", 1u32), "1");
     assert_eq!(format!("{:?}", 1u64), "1");
+    assert_eq!(format!("{:?}", 1u128), "1");
     assert_eq!(format!("{:b}", 1usize), "1");
     assert_eq!(format!("{:b}", 1u8), "1");
     assert_eq!(format!("{:b}", 1u16), "1");
     assert_eq!(format!("{:b}", 1u32), "1");
     assert_eq!(format!("{:b}", 1u64), "1");
+    assert_eq!(format!("{:b}", 1u128), "1");
     assert_eq!(format!("{:x}", 1usize), "1");
     assert_eq!(format!("{:x}", 1u8), "1");
     assert_eq!(format!("{:x}", 1u16), "1");
     assert_eq!(format!("{:x}", 1u32), "1");
     assert_eq!(format!("{:x}", 1u64), "1");
+    assert_eq!(format!("{:x}", 1u128), "1");
     assert_eq!(format!("{:X}", 1usize), "1");
     assert_eq!(format!("{:X}", 1u8), "1");
     assert_eq!(format!("{:X}", 1u16), "1");
     assert_eq!(format!("{:X}", 1u32), "1");
     assert_eq!(format!("{:X}", 1u64), "1");
+    assert_eq!(format!("{:X}", 1u128), "1");
     assert_eq!(format!("{:o}", 1usize), "1");
     assert_eq!(format!("{:o}", 1u8), "1");
     assert_eq!(format!("{:o}", 1u16), "1");
     assert_eq!(format!("{:o}", 1u32), "1");
     assert_eq!(format!("{:o}", 1u64), "1");
+    assert_eq!(format!("{:o}", 1u128), "1");
     assert_eq!(format!("{:e}", 1u8), "1e0");
     assert_eq!(format!("{:e}", 1u16), "1e0");
     assert_eq!(format!("{:e}", 1u32), "1e0");
     assert_eq!(format!("{:e}", 1u64), "1e0");
+    assert_eq!(format!("{:e}", 1u128), "1e0");
     assert_eq!(format!("{:E}", 1u8), "1E0");
     assert_eq!(format!("{:E}", 1u16), "1E0");
     assert_eq!(format!("{:E}", 1u32), "1E0");
     assert_eq!(format!("{:E}", 1u64), "1E0");
+    assert_eq!(format!("{:E}", 1u128), "1E0");
 
-    // Test a larger number
+    // again, with negative
+    assert_eq!(format!("{}", -1isize), "-1");
+    assert_eq!(format!("{}", -1i8), "-1");
+    assert_eq!(format!("{}", -1i16), "-1");
+    assert_eq!(format!("{}", -1i32), "-1");
+    assert_eq!(format!("{}", -1i64), "-1");
+    assert_eq!(format!("{}", -1i128), "-1");
+    assert_eq!(format!("{:?}", -1isize), "-1");
+    assert_eq!(format!("{:?}", -1i8), "-1");
+    assert_eq!(format!("{:?}", -1i16), "-1");
+    assert_eq!(format!("{:?}", -1i32), "-1");
+    assert_eq!(format!("{:?}", -1i64), "-1");
+    assert_eq!(format!("{:?}", -1i128), "-1");
+    assert_eq!(format!("{:b}", -1isize), "1".repeat(size_of::<isize>() * 8));
+    assert_eq!(format!("{:b}", -1i8), "11111111");
+    assert_eq!(format!("{:b}", -1i16), "1111111111111111");
+    assert_eq!(format!("{:b}", -1i32), "11111111111111111111111111111111");
+    assert_eq!(
+        format!("{:b}", -1i64),
+        "1111111111111111111111111111111111111111111111111111111111111111"
+    );
+    assert_eq!(
+        format!("{:b}", -1i128),
+        "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"
+    );
+    assert_eq!(format!("{:x}", -1isize), "ff".repeat(size_of::<isize>()));
+    assert_eq!(format!("{:x}", -1i8), "ff");
+    assert_eq!(format!("{:x}", -1i16), "ffff");
+    assert_eq!(format!("{:x}", -1i32), "ffffffff");
+    assert_eq!(format!("{:x}", -1i64), "ffffffffffffffff");
+    assert_eq!(format!("{:x}", -1i128), "ffffffffffffffffffffffffffffffff");
+    assert_eq!(format!("{:X}", -1isize), "FF".repeat(size_of::<isize>()));
+    assert_eq!(format!("{:X}", -1i8), "FF");
+    assert_eq!(format!("{:X}", -1i16), "FFFF");
+    assert_eq!(format!("{:X}", -1i32), "FFFFFFFF");
+    assert_eq!(format!("{:X}", -1i64), "FFFFFFFFFFFFFFFF");
+    assert_eq!(format!("{:X}", -1i128), "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF");
+    // octal test for isize omitted
+    assert_eq!(format!("{:o}", -1i8), "377");
+    assert_eq!(format!("{:o}", -1i16), "177777");
+    assert_eq!(format!("{:o}", -1i32), "37777777777");
+    assert_eq!(format!("{:o}", -1i64), "1777777777777777777777");
+    assert_eq!(format!("{:o}", -1i128), "3777777777777777777777777777777777777777777");
+    assert_eq!(format!("{:e}", -1isize), "-1e0");
+    assert_eq!(format!("{:e}", -1i8), "-1e0");
+    assert_eq!(format!("{:e}", -1i16), "-1e0");
+    assert_eq!(format!("{:e}", -1i32), "-1e0");
+    assert_eq!(format!("{:e}", -1i64), "-1e0");
+    assert_eq!(format!("{:e}", -1i128), "-1e0");
+    assert_eq!(format!("{:E}", -1isize), "-1E0");
+    assert_eq!(format!("{:E}", -1i8), "-1E0");
+    assert_eq!(format!("{:E}", -1i16), "-1E0");
+    assert_eq!(format!("{:E}", -1i32), "-1E0");
+    assert_eq!(format!("{:E}", -1i64), "-1E0");
+    assert_eq!(format!("{:E}", -1i128), "-1E0");
+}
+
+#[test]
+fn test_format_int_misc() {
     assert_eq!(format!("{:b}", 55), "110111");
     assert_eq!(format!("{:o}", 55), "67");
     assert_eq!(format!("{}", 55), "55");
@@ -103,6 +197,26 @@ fn test_format_int() {
 }
 
 #[test]
+fn test_format_int_limits() {
+    assert_eq!(format!("{}", i8::MIN), "-128");
+    assert_eq!(format!("{}", i8::MAX), "127");
+    assert_eq!(format!("{}", i16::MIN), "-32768");
+    assert_eq!(format!("{}", i16::MAX), "32767");
+    assert_eq!(format!("{}", i32::MIN), "-2147483648");
+    assert_eq!(format!("{}", i32::MAX), "2147483647");
+    assert_eq!(format!("{}", i64::MIN), "-9223372036854775808");
+    assert_eq!(format!("{}", i64::MAX), "9223372036854775807");
+    assert_eq!(format!("{}", i128::MIN), "-170141183460469231731687303715884105728");
+    assert_eq!(format!("{}", i128::MAX), "170141183460469231731687303715884105727");
+
+    assert_eq!(format!("{}", u8::MAX), "255");
+    assert_eq!(format!("{}", u16::MAX), "65535");
+    assert_eq!(format!("{}", u32::MAX), "4294967295");
+    assert_eq!(format!("{}", u64::MAX), "18446744073709551615");
+    assert_eq!(format!("{}", u128::MAX), "340282366920938463463374607431768211455");
+}
+
+#[test]
 fn test_format_int_exp_limits() {
     assert_eq!(format!("{:e}", i8::MIN), "-1.28e2");
     assert_eq!(format!("{:e}", i8::MAX), "1.27e2");
@@ -168,27 +282,6 @@ fn test_format_int_exp_precision() {
 }
 
 #[test]
-fn test_format_int_zero() {
-    assert_eq!(format!("{}", 0), "0");
-    assert_eq!(format!("{:?}", 0), "0");
-    assert_eq!(format!("{:b}", 0), "0");
-    assert_eq!(format!("{:o}", 0), "0");
-    assert_eq!(format!("{:x}", 0), "0");
-    assert_eq!(format!("{:X}", 0), "0");
-    assert_eq!(format!("{:e}", 0), "0e0");
-    assert_eq!(format!("{:E}", 0), "0E0");
-
-    assert_eq!(format!("{}", 0u32), "0");
-    assert_eq!(format!("{:?}", 0u32), "0");
-    assert_eq!(format!("{:b}", 0u32), "0");
-    assert_eq!(format!("{:o}", 0u32), "0");
-    assert_eq!(format!("{:x}", 0u32), "0");
-    assert_eq!(format!("{:X}", 0u32), "0");
-    assert_eq!(format!("{:e}", 0u32), "0e0");
-    assert_eq!(format!("{:E}", 0u32), "0E0");
-}
-
-#[test]
 fn test_format_int_flags() {
     assert_eq!(format!("{:3}", 1), "  1");
     assert_eq!(format!("{:>3}", 1), "  1");
@@ -226,14 +319,6 @@ fn test_format_int_sign_padding() {
 }
 
 #[test]
-fn test_format_int_twos_complement() {
-    assert_eq!(format!("{}", i8::MIN), "-128");
-    assert_eq!(format!("{}", i16::MIN), "-32768");
-    assert_eq!(format!("{}", i32::MIN), "-2147483648");
-    assert_eq!(format!("{}", i64::MIN), "-9223372036854775808");
-}
-
-#[test]
 fn test_format_debug_hex() {
     assert_eq!(format!("{:02x?}", b"Foo\0"), "[46, 6f, 6f, 00]");
     assert_eq!(format!("{:02X?}", b"Foo\0"), "[46, 6F, 6F, 00]");
diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
index 92b920dd775..5449132413b 100644
--- a/library/coretests/tests/lib.rs
+++ b/library/coretests/tests/lib.rs
@@ -94,6 +94,7 @@
 #![feature(try_blocks)]
 #![feature(try_find)]
 #![feature(try_trait_v2)]
+#![feature(uint_bit_width)]
 #![feature(unsize)]
 #![feature(unwrap_infallible)]
 // tidy-alphabetical-end
diff --git a/library/coretests/tests/num/uint_macros.rs b/library/coretests/tests/num/uint_macros.rs
index 6f3d160964f..7e02027bdd6 100644
--- a/library/coretests/tests/num/uint_macros.rs
+++ b/library/coretests/tests/num/uint_macros.rs
@@ -72,6 +72,14 @@ macro_rules! uint_module {
                 assert_eq_const_safe!(u32: X.trailing_ones(), 0);
             }
 
+            fn test_bit_width() {
+                assert_eq_const_safe!(u32: A.bit_width(), 6);
+                assert_eq_const_safe!(u32: B.bit_width(), 6);
+                assert_eq_const_safe!(u32: C.bit_width(), 7);
+                assert_eq_const_safe!(u32: _0.bit_width(), 0);
+                assert_eq_const_safe!(u32: _1.bit_width(), $T::BITS);
+            }
+
             fn test_rotate() {
                 assert_eq_const_safe!($T: A.rotate_left(6).rotate_right(2).rotate_right(4), A);
                 assert_eq_const_safe!($T: B.rotate_left(3).rotate_left(2).rotate_right(5), B);
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 53d78dcc488..ae7107938f3 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -32,7 +32,7 @@ rustc-demangle = { version = "0.1.24", features = ['rustc-dep-of-std'] }
 
 [target.'cfg(not(all(windows, target_env = "msvc", not(target_vendor = "uwp"))))'.dependencies]
 miniz_oxide = { version = "0.8.0", optional = true, default-features = false }
-addr2line = { version = "0.24.0", optional = true, default-features = false }
+addr2line = { version = "0.25.0", optional = true, default-features = false }
 
 [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
 libc = { version = "0.2.172", default-features = false, features = [
@@ -40,7 +40,7 @@ libc = { version = "0.2.172", default-features = false, features = [
 ], public = true }
 
 [target.'cfg(all(not(target_os = "aix"), not(all(windows, target_env = "msvc", not(target_vendor = "uwp")))))'.dependencies]
-object = { version = "0.36.0", default-features = false, optional = true, features = [
+object = { version = "0.37.1", default-features = false, optional = true, features = [
     'read_core',
     'elf',
     'macho',
@@ -50,7 +50,7 @@ object = { version = "0.36.0", default-features = false, optional = true, featur
 ] }
 
 [target.'cfg(target_os = "aix")'.dependencies]
-object = { version = "0.36.0", default-features = false, optional = true, features = [
+object = { version = "0.37.1", default-features = false, optional = true, features = [
     'read_core',
     'xcoff',
     'unaligned',
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/library/stdarch b/library/stdarch
-Subproject 5c1c436524c0bbc8db83577f42f8bea9006a7b7
+Subproject 1b4d15df12079504942d0a3f1030b2039b8a776
diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml
index ad373420a96..f8da09f7193 100644
--- a/library/unwind/Cargo.toml
+++ b/library/unwind/Cargo.toml
@@ -22,7 +22,7 @@ cfg-if = "1.0"
 libc = { version = "0.2.140", features = ['rustc-dep-of-std'], default-features = false }
 
 [target.'cfg(target_os = "xous")'.dependencies]
-unwinding = { version = "0.2.6", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false }
+unwinding = { version = "0.2.7", features = ['rustc-dep-of-std', 'unwinder', 'fde-custom'], default-features = false }
 
 [features]
 
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index 911a51b0e16..f47873590a1 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -89,7 +89,7 @@ impl Step for Std {
         let stage = self.custom_stage.unwrap_or(builder.top_stage);
 
         let target = self.target;
-        let compiler = builder.compiler(stage, builder.config.build);
+        let compiler = builder.compiler(stage, builder.config.host_target);
 
         if stage == 0 {
             let mut is_explicitly_called =
@@ -244,7 +244,7 @@ impl Step for Rustc {
     /// the `compiler` targeting the `target` architecture. The artifacts
     /// created will also be linked into the sysroot directory.
     fn run(self, builder: &Builder<'_>) {
-        let compiler = builder.compiler(builder.top_stage, builder.config.build);
+        let compiler = builder.compiler(builder.top_stage, builder.config.host_target);
         let target = self.target;
 
         if compiler.stage != 0 {
@@ -327,7 +327,7 @@ impl Step for CodegenBackend {
             return;
         }
 
-        let compiler = builder.compiler(builder.top_stage, builder.config.build);
+        let compiler = builder.compiler(builder.top_stage, builder.config.host_target);
         let target = self.target;
         let backend = self.backend;
 
@@ -382,7 +382,7 @@ impl Step for RustAnalyzer {
     }
 
     fn run(self, builder: &Builder<'_>) {
-        let compiler = builder.compiler(builder.top_stage, builder.config.build);
+        let compiler = builder.compiler(builder.top_stage, builder.config.host_target);
         let target = self.target;
 
         builder.ensure(Rustc::new(target, builder));
@@ -448,7 +448,7 @@ impl Step for Compiletest {
 
         let compiler = builder.compiler(
             if mode == Mode::ToolBootstrap { 0 } else { builder.top_stage },
-            builder.config.build,
+            builder.config.host_target,
         );
 
         if mode != Mode::ToolBootstrap {
@@ -527,7 +527,7 @@ fn run_tool_check_step(
     path: &str,
 ) {
     let display_name = path.rsplit('/').next().unwrap();
-    let compiler = builder.compiler(builder.top_stage, builder.config.build);
+    let compiler = builder.compiler(builder.top_stage, builder.config.host_target);
 
     builder.ensure(Rustc::new(target, builder));
 
@@ -614,7 +614,7 @@ impl Step for CoverageDump {
         // Make sure we haven't forgotten any fields, if there are any.
         let Self {} = self;
         let display_name = "coverage-dump";
-        let host = builder.config.build;
+        let host = builder.config.host_target;
         let target = host;
         let mode = Mode::ToolBootstrap;
 
diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs
index 0652c08ff49..788a3b9601d 100644
--- a/src/bootstrap/src/core/build_steps/clippy.rs
+++ b/src/bootstrap/src/core/build_steps/clippy.rs
@@ -144,7 +144,7 @@ impl Step for Std {
         builder.require_submodule("library/stdarch", None);
 
         let target = self.target;
-        let compiler = builder.compiler(builder.top_stage, builder.config.build);
+        let compiler = builder.compiler(builder.top_stage, builder.config.host_target);
 
         let mut cargo = builder::Cargo::new(
             builder,
@@ -204,7 +204,7 @@ impl Step for Rustc {
     /// This will lint the compiler for a particular stage of the build using
     /// the `compiler` targeting the `target` architecture.
     fn run(self, builder: &Builder<'_>) {
-        let compiler = builder.compiler(builder.top_stage, builder.config.build);
+        let compiler = builder.compiler(builder.top_stage, builder.config.host_target);
         let target = self.target;
 
         if !builder.download_rustc() {
@@ -285,7 +285,7 @@ macro_rules! lint_any {
             }
 
             fn run(self, builder: &Builder<'_>) -> Self::Output {
-                let compiler = builder.compiler(builder.top_stage, builder.config.build);
+                let compiler = builder.compiler(builder.top_stage, builder.config.host_target);
                 let target = self.target;
 
                 if !builder.download_rustc() {
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 5ecce31fe15..560925abba6 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -35,6 +35,7 @@ use crate::utils::helpers::{
 };
 use crate::{CLang, Compiler, DependencyType, FileType, GitRepo, LLVM_TOOLS, Mode, debug, trace};
 
+/// Build a standard library for the given `target` using the given `compiler`.
 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct Std {
     pub target: TargetSelection,
@@ -159,7 +160,7 @@ impl Step for Std {
         let compiler = if builder.download_rustc() && self.force_recompile {
             // When there are changes in the library tree with CI-rustc, we want to build
             // the stageN library and that requires using stageN-1 compiler.
-            builder.compiler(self.compiler.stage.saturating_sub(1), builder.config.build)
+            builder.compiler(self.compiler.stage.saturating_sub(1), builder.config.host_target)
         } else {
             self.compiler
         };
@@ -301,7 +302,7 @@ impl Step for Std {
 
         builder.ensure(StdLink::from_std(
             self,
-            builder.compiler(compiler.stage, builder.config.build),
+            builder.compiler(compiler.stage, builder.config.host_target),
         ));
     }
 }
@@ -960,11 +961,18 @@ fn cp_rustc_component_to_ci_sysroot(builder: &Builder<'_>, sysroot: &Path, conte
     }
 }
 
+/// Build rustc using the passed `build_compiler`.
+///
+/// - Makes sure that `build_compiler` has a standard library prepared for its host target,
+///   so that it can compile build scripts and proc macros when building this `rustc`.
+/// - Makes sure that `build_compiler` has a standard library prepared for `target`,
+///   so that the built `rustc` can *link to it* and use it at runtime.
 #[derive(Debug, PartialOrd, Ord, Clone, PartialEq, Eq, Hash)]
 pub struct Rustc {
+    /// The target on which rustc will run (its host).
     pub target: TargetSelection,
-    /// The **previous** compiler used to compile this compiler.
-    pub compiler: Compiler,
+    /// The **previous** compiler used to compile this rustc.
+    pub build_compiler: Compiler,
     /// Whether to build a subset of crates, rather than the whole compiler.
     ///
     /// This should only be requested by the user, not used within bootstrap itself.
@@ -974,8 +982,8 @@ pub struct Rustc {
 }
 
 impl Rustc {
-    pub fn new(compiler: Compiler, target: TargetSelection) -> Self {
-        Self { target, compiler, crates: Default::default() }
+    pub fn new(build_compiler: Compiler, target: TargetSelection) -> Self {
+        Self { target, build_compiler, crates: Default::default() }
     }
 }
 
@@ -1007,7 +1015,7 @@ impl Step for Rustc {
     fn make_run(run: RunConfig<'_>) {
         let crates = run.cargo_crates_in_set();
         run.builder.ensure(Rustc {
-            compiler: run
+            build_compiler: run
                 .builder
                 .compiler(run.builder.top_stage.saturating_sub(1), run.build_triple()),
             target: run.target,
@@ -1018,7 +1026,7 @@ impl Step for Rustc {
     /// Builds the compiler.
     ///
     /// This will build the compiler for a particular stage of the build using
-    /// the `compiler` targeting the `target` architecture. The artifacts
+    /// the `build_compiler` targeting the `target` architecture. The artifacts
     /// created will also be linked into the sysroot directory.
     #[cfg_attr(
         feature = "tracing",
@@ -1026,54 +1034,58 @@ impl Step for Rustc {
             level = "debug",
             name = "Rustc::run",
             skip_all,
-            fields(previous_compiler = ?self.compiler, target = ?self.target),
+            fields(previous_compiler = ?self.build_compiler, target = ?self.target),
         ),
     )]
     fn run(self, builder: &Builder<'_>) -> u32 {
-        let compiler = self.compiler;
+        let build_compiler = self.build_compiler;
         let target = self.target;
 
         // NOTE: the ABI of the stage0 compiler is different from the ABI of the downloaded compiler,
         // so its artifacts can't be reused.
-        if builder.download_rustc() && compiler.stage != 0 {
-            trace!(stage = compiler.stage, "`download_rustc` requested");
+        if builder.download_rustc() && build_compiler.stage != 0 {
+            trace!(stage = build_compiler.stage, "`download_rustc` requested");
 
-            let sysroot = builder.ensure(Sysroot { compiler, force_recompile: false });
+            let sysroot =
+                builder.ensure(Sysroot { compiler: build_compiler, force_recompile: false });
             cp_rustc_component_to_ci_sysroot(
                 builder,
                 &sysroot,
                 builder.config.ci_rustc_dev_contents(),
             );
-            return compiler.stage;
+            return build_compiler.stage;
         }
 
-        builder.ensure(Std::new(compiler, target));
+        // Build a standard library for `target` using the `build_compiler`.
+        // This will be the standard library that the rustc which we build *links to*.
+        builder.ensure(Std::new(build_compiler, target));
 
-        if builder.config.keep_stage.contains(&compiler.stage) {
-            trace!(stage = compiler.stage, "`keep-stage` requested");
+        if builder.config.keep_stage.contains(&build_compiler.stage) {
+            trace!(stage = build_compiler.stage, "`keep-stage` requested");
 
             builder.info("WARNING: Using a potentially old librustc. This may not behave well.");
             builder.info("WARNING: Use `--keep-stage-std` if you want to rebuild the compiler when it changes");
-            builder.ensure(RustcLink::from_rustc(self, compiler));
+            builder.ensure(RustcLink::from_rustc(self, build_compiler));
 
-            return compiler.stage;
+            return build_compiler.stage;
         }
 
-        let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
-        if compiler_to_use != compiler {
+        let compiler_to_use =
+            builder.compiler_for(build_compiler.stage, build_compiler.host, target);
+        if compiler_to_use != build_compiler {
             builder.ensure(Rustc::new(compiler_to_use, target));
             let msg = if compiler_to_use.host == target {
                 format!(
                     "Uplifting rustc (stage{} -> stage{})",
                     compiler_to_use.stage,
-                    compiler.stage + 1
+                    build_compiler.stage + 1
                 )
             } else {
                 format!(
                     "Uplifting rustc (stage{}:{} -> stage{}:{})",
                     compiler_to_use.stage,
                     compiler_to_use.host,
-                    compiler.stage + 1,
+                    build_compiler.stage + 1,
                     target
                 )
             };
@@ -1082,22 +1094,26 @@ impl Step for Rustc {
             return compiler_to_use.stage;
         }
 
-        // Ensure that build scripts and proc macros have a std / libproc_macro to link against.
+        // Build a standard library for the current host target using the `build_compiler`.
+        // This standard library will be used when building `rustc` for compiling
+        // build scripts and proc macros.
+        // If we are not cross-compiling, the Std build above will be the same one as the one we
+        // prepare here.
         builder.ensure(Std::new(
-            builder.compiler(self.compiler.stage, builder.config.build),
-            builder.config.build,
+            builder.compiler(self.build_compiler.stage, builder.config.host_target),
+            builder.config.host_target,
         ));
 
         let mut cargo = builder::Cargo::new(
             builder,
-            compiler,
+            build_compiler,
             Mode::Rustc,
             SourceType::InTree,
             target,
             Kind::Build,
         );
 
-        rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates);
+        rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates);
 
         // NB: all RUSTFLAGS should be added to `rustc_cargo()` so they will be
         // consistently applied by check/doc/test modes too.
@@ -1106,19 +1122,19 @@ impl Step for Rustc {
             cargo.arg("-p").arg(krate);
         }
 
-        if builder.build.config.enable_bolt_settings && compiler.stage == 1 {
+        if builder.build.config.enable_bolt_settings && build_compiler.stage == 1 {
             // Relocations are required for BOLT to work.
             cargo.env("RUSTC_BOLT_LINK_FLAGS", "1");
         }
 
         let _guard = builder.msg_sysroot_tool(
             Kind::Build,
-            compiler.stage,
+            build_compiler.stage,
             format_args!("compiler artifacts{}", crate_description(&self.crates)),
-            compiler.host,
+            build_compiler.host,
             target,
         );
-        let stamp = build_stamp::librustc_stamp(builder, compiler, target);
+        let stamp = build_stamp::librustc_stamp(builder, build_compiler, target);
         run_cargo(
             builder,
             cargo,
@@ -1150,10 +1166,10 @@ impl Step for Rustc {
 
         builder.ensure(RustcLink::from_rustc(
             self,
-            builder.compiler(compiler.stage, builder.config.build),
+            builder.compiler(build_compiler.stage, builder.config.host_target),
         ));
 
-        compiler.stage
+        build_compiler.stage
     }
 }
 
@@ -1161,7 +1177,7 @@ pub fn rustc_cargo(
     builder: &Builder<'_>,
     cargo: &mut Cargo,
     target: TargetSelection,
-    compiler: &Compiler,
+    build_compiler: &Compiler,
     crates: &[String],
 ) {
     cargo
@@ -1190,11 +1206,11 @@ pub fn rustc_cargo(
     // We want to link against registerEnzyme and in the future we want to use additional
     // functionality from Enzyme core. For that we need to link against Enzyme.
     if builder.config.llvm_enzyme {
-        let arch = builder.build.build;
+        let arch = builder.build.host_target;
         let enzyme_dir = builder.build.out.join(arch).join("enzyme").join("lib");
         cargo.rustflag("-L").rustflag(enzyme_dir.to_str().expect("Invalid path"));
 
-        if let Some(llvm_config) = builder.llvm_config(builder.config.build) {
+        if let Some(llvm_config) = builder.llvm_config(builder.config.host_target) {
             let llvm_version_major = llvm::get_llvm_version_major(builder, &llvm_config);
             cargo.rustflag("-l").rustflag(&format!("Enzyme-{llvm_version_major}"));
         }
@@ -1208,7 +1224,7 @@ pub fn rustc_cargo(
         cargo.rustflag("-Zdefault-visibility=protected");
     }
 
-    if is_lto_stage(compiler) {
+    if is_lto_stage(build_compiler) {
         match builder.config.rust_lto {
             RustcLto::Thin | RustcLto::Fat => {
                 // Since using LTO for optimizing dylibs is currently experimental,
@@ -1241,7 +1257,7 @@ pub fn rustc_cargo(
     // is already on by default in MSVC optimized builds, which is interpreted as --icf=all:
     // https://github.com/llvm/llvm-project/blob/3329cec2f79185bafd678f310fafadba2a8c76d2/lld/COFF/Driver.cpp#L1746
     // https://github.com/rust-lang/rust/blob/f22819bcce4abaff7d1246a56eec493418f9f4ee/compiler/rustc_codegen_ssa/src/back/linker.rs#L827
-    if builder.config.lld_mode.is_used() && !compiler.host.is_msvc() {
+    if builder.config.lld_mode.is_used() && !build_compiler.host.is_msvc() {
         cargo.rustflag("-Clink-args=-Wl,--icf=all");
     }
 
@@ -1249,7 +1265,7 @@ pub fn rustc_cargo(
         panic!("Cannot use and generate PGO profiles at the same time");
     }
     let is_collecting = if let Some(path) = &builder.config.rust_profile_generate {
-        if compiler.stage == 1 {
+        if build_compiler.stage == 1 {
             cargo.rustflag(&format!("-Cprofile-generate={path}"));
             // Apparently necessary to avoid overflowing the counters during
             // a Cargo build profile
@@ -1259,7 +1275,7 @@ pub fn rustc_cargo(
             false
         }
     } else if let Some(path) = &builder.config.rust_profile_use {
-        if compiler.stage == 1 {
+        if build_compiler.stage == 1 {
             cargo.rustflag(&format!("-Cprofile-use={path}"));
             if builder.is_verbose() {
                 cargo.rustflag("-Cllvm-args=-pgo-warn-missing-function");
@@ -1284,20 +1300,20 @@ pub fn rustc_cargo(
     // useful.
     // This is only performed for non-incremental builds, as ccache cannot deal with these.
     if let Some(ref ccache) = builder.config.ccache
-        && compiler.stage == 0
+        && build_compiler.stage == 0
         && !builder.config.incremental
     {
         cargo.env("RUSTC_WRAPPER", ccache);
     }
 
-    rustc_cargo_env(builder, cargo, target, compiler.stage);
+    rustc_cargo_env(builder, cargo, target, build_compiler.stage);
 }
 
 pub fn rustc_cargo_env(
     builder: &Builder<'_>,
     cargo: &mut Cargo,
     target: TargetSelection,
-    stage: u32,
+    build_stage: u32,
 ) {
     // Set some configuration variables picked up by build scripts and
     // the compiler alike
@@ -1364,7 +1380,7 @@ pub fn rustc_cargo_env(
             crate::core::build_steps::llvm::prebuilt_llvm_config(builder, target, false)
                 .should_build();
         // `top_stage == stage` might be false for `check --stage 1`, if we are building the stage 1 compiler
-        let can_skip_build = builder.kind == Kind::Check && builder.top_stage == stage;
+        let can_skip_build = builder.kind == Kind::Check && builder.top_stage == build_stage;
         let should_skip_build = building_is_expensive && can_skip_build;
         if !should_skip_build {
             rustc_llvm_env(builder, cargo, target)
@@ -1475,7 +1491,7 @@ impl RustcLink {
     fn from_rustc(rustc: Rustc, host_compiler: Compiler) -> Self {
         Self {
             compiler: host_compiler,
-            previous_stage_compiler: rustc.compiler,
+            previous_stage_compiler: rustc.build_compiler,
             target: rustc.target,
             crates: rustc.crates,
         }
@@ -1813,7 +1829,7 @@ impl Step for Sysroot {
         // If we're downloading a compiler from CI, we can use the same compiler for all stages other than 0.
         if builder.download_rustc() && compiler.stage != 0 {
             assert_eq!(
-                builder.config.build, compiler.host,
+                builder.config.host_target, compiler.host,
                 "Cross-compiling is not yet supported with `download-rustc`",
             );
 
@@ -1967,7 +1983,7 @@ impl Step for Assemble {
         if target_compiler.stage == 0 {
             trace!("stage 0 build compiler is always available, simply returning");
             assert_eq!(
-                builder.config.build, target_compiler.host,
+                builder.config.host_target, target_compiler.host,
                 "Cannot obtain compiler for non-native build triple at stage 0"
             );
             // The stage 0 compiler for the build triple is always pre-built.
@@ -2080,15 +2096,16 @@ impl Step for Assemble {
         debug!(
             "ensuring build compiler is available: compiler(stage = {}, host = {:?})",
             target_compiler.stage - 1,
-            builder.config.build,
+            builder.config.host_target,
         );
-        let mut build_compiler = builder.compiler(target_compiler.stage - 1, builder.config.build);
+        let mut build_compiler =
+            builder.compiler(target_compiler.stage - 1, builder.config.host_target);
 
         // Build enzyme
         if builder.config.llvm_enzyme && !builder.config.dry_run() {
             debug!("`llvm_enzyme` requested");
             let enzyme_install = builder.ensure(llvm::Enzyme { target: build_compiler.host });
-            let llvm_config = builder.llvm_config(builder.config.build).unwrap();
+            let llvm_config = builder.llvm_config(builder.config.host_target).unwrap();
             let llvm_version_major = llvm::get_llvm_version_major(builder, &llvm_config);
             let lib_ext = std::env::consts::DLL_EXTENSION;
             let libenzyme = format!("libEnzyme-{llvm_version_major}");
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 587fca80374..e0f632eda0e 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -422,7 +422,7 @@ impl Step for Rustc {
             }
 
             let ra_proc_macro_srv_compiler =
-                builder.compiler_for(compiler.stage, builder.config.build, compiler.host);
+                builder.compiler_for(compiler.stage, builder.config.host_target, compiler.host);
             builder.ensure(compile::Rustc::new(ra_proc_macro_srv_compiler, compiler.host));
 
             if let Some(ra_proc_macro_srv) = builder.ensure_if_default(
@@ -696,7 +696,7 @@ impl Step for Std {
         run.builder.ensure(Std {
             compiler: run.builder.compiler_for(
                 run.builder.top_stage,
-                run.builder.config.build,
+                run.builder.config.host_target,
                 run.target,
             ),
             target: run.target,
@@ -748,7 +748,7 @@ impl Step for RustcDev {
         run.builder.ensure(RustcDev {
             compiler: run.builder.compiler_for(
                 run.builder.top_stage,
-                run.builder.config.build,
+                run.builder.config.host_target,
                 run.target,
             ),
             target: run.target,
@@ -815,7 +815,7 @@ impl Step for Analysis {
             // through the sysroot uplifting.
             compiler: run.builder.compiler_for(
                 run.builder.top_stage,
-                run.builder.config.build,
+                run.builder.config.host_target,
                 run.target,
             ),
             target: run.target,
@@ -1168,7 +1168,7 @@ impl Step for Cargo {
         run.builder.ensure(Cargo {
             compiler: run.builder.compiler_for(
                 run.builder.top_stage,
-                run.builder.config.build,
+                run.builder.config.host_target,
                 run.target,
             ),
             target: run.target,
@@ -1224,7 +1224,7 @@ impl Step for RustAnalyzer {
         run.builder.ensure(RustAnalyzer {
             compiler: run.builder.compiler_for(
                 run.builder.top_stage,
-                run.builder.config.build,
+                run.builder.config.host_target,
                 run.target,
             ),
             target: run.target,
@@ -1268,7 +1268,7 @@ impl Step for Clippy {
         run.builder.ensure(Clippy {
             compiler: run.builder.compiler_for(
                 run.builder.top_stage,
-                run.builder.config.build,
+                run.builder.config.host_target,
                 run.target,
             ),
             target: run.target,
@@ -1317,7 +1317,7 @@ impl Step for Miri {
         run.builder.ensure(Miri {
             compiler: run.builder.compiler_for(
                 run.builder.top_stage,
-                run.builder.config.build,
+                run.builder.config.host_target,
                 run.target,
             ),
             target: run.target,
@@ -1462,7 +1462,7 @@ impl Step for Rustfmt {
         run.builder.ensure(Rustfmt {
             compiler: run.builder.compiler_for(
                 run.builder.top_stage,
-                run.builder.config.build,
+                run.builder.config.host_target,
                 run.target,
             ),
             target: run.target,
@@ -1507,7 +1507,7 @@ impl Step for Extended {
     fn make_run(run: RunConfig<'_>) {
         run.builder.ensure(Extended {
             stage: run.builder.top_stage,
-            host: run.builder.config.build,
+            host: run.builder.config.host_target,
             target: run.target,
         });
     }
@@ -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);
 
@@ -2156,7 +2157,7 @@ fn maybe_install_llvm(
         cmd.arg("--libfiles");
         builder.verbose(|| println!("running {cmd:?}"));
         let files = cmd.run_capture_stdout(builder).stdout();
-        let build_llvm_out = &builder.llvm_out(builder.config.build);
+        let build_llvm_out = &builder.llvm_out(builder.config.host_target);
         let target_llvm_out = &builder.llvm_out(target);
         for file in files.trim_end().split(' ') {
             // If we're not using a custom LLVM, make sure we package for the target.
@@ -2340,7 +2341,7 @@ impl Step for LlvmBitcodeLinker {
         run.builder.ensure(LlvmBitcodeLinker {
             compiler: run.builder.compiler_for(
                 run.builder.top_stage,
-                run.builder.config.build,
+                run.builder.config.host_target,
                 run.target,
             ),
             target: run.target,
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index 7fccf85a0ea..215c155651a 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -209,7 +209,7 @@ impl Step for TheBook {
 
     fn make_run(run: RunConfig<'_>) {
         run.builder.ensure(TheBook {
-            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
+            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target),
             target: run.target,
         });
     }
@@ -329,7 +329,7 @@ impl Step for Standalone {
 
     fn make_run(run: RunConfig<'_>) {
         run.builder.ensure(Standalone {
-            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
+            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target),
             target: run.target,
         });
     }
@@ -431,7 +431,7 @@ impl Step for Releases {
 
     fn make_run(run: RunConfig<'_>) {
         run.builder.ensure(Releases {
-            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
+            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target),
             target: run.target,
         });
     }
@@ -449,7 +449,7 @@ impl Step for Releases {
         t!(fs::create_dir_all(&out));
 
         builder.ensure(Standalone {
-            compiler: builder.compiler(builder.top_stage, builder.config.build),
+            compiler: builder.compiler(builder.top_stage, builder.config.host_target),
             target,
         });
 
@@ -700,7 +700,7 @@ fn doc_std(
     extra_args: &[&str],
     requested_crates: &[String],
 ) {
-    let compiler = builder.compiler(stage, builder.config.build);
+    let compiler = builder.compiler(stage, builder.config.host_target);
 
     let target_doc_dir_name = if format == DocumentationFormat::Json { "json-doc" } else { "doc" };
     let target_dir = builder.stage_out(compiler, Mode::Std).join(target).join(target_doc_dir_name);
@@ -803,8 +803,8 @@ impl Step for Rustc {
 
         // Build the standard library, so that proc-macros can use it.
         // (Normally, only the metadata would be necessary, but proc-macros are special since they run at compile-time.)
-        let compiler = builder.compiler(stage, builder.config.build);
-        builder.ensure(compile::Std::new(compiler, builder.config.build));
+        let compiler = builder.compiler(stage, builder.config.host_target);
+        builder.ensure(compile::Std::new(compiler, builder.config.host_target));
 
         let _guard = builder.msg_sysroot_tool(
             Kind::Doc,
@@ -946,7 +946,7 @@ macro_rules! tool_doc {
                 let out = builder.compiler_doc_out(target);
                 t!(fs::create_dir_all(&out));
 
-                let compiler = builder.compiler(stage, builder.config.build);
+                let compiler = builder.compiler(stage, builder.config.host_target);
                 builder.ensure(compile::Std::new(compiler, target));
 
                 if true $(&& $rustc_tool)? {
@@ -1174,7 +1174,7 @@ impl Step for RustcBook {
 
     fn make_run(run: RunConfig<'_>) {
         run.builder.ensure(RustcBook {
-            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
+            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target),
             target: run.target,
             validate: false,
         });
@@ -1261,7 +1261,7 @@ impl Step for Reference {
 
     fn make_run(run: RunConfig<'_>) {
         run.builder.ensure(Reference {
-            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
+            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target),
             target: run.target,
         });
     }
@@ -1272,7 +1272,7 @@ impl Step for Reference {
 
         // This is needed for generating links to the standard library using
         // the mdbook-spec plugin.
-        builder.ensure(compile::Std::new(self.compiler, builder.config.build));
+        builder.ensure(compile::Std::new(self.compiler, builder.config.host_target));
 
         // Run rustbook/mdbook to generate the HTML pages.
         builder.ensure(RustbookSrc {
diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs
index ee8bd8286da..899e3fd9a45 100644
--- a/src/bootstrap/src/core/build_steps/gcc.rs
+++ b/src/bootstrap/src/core/build_steps/gcc.rs
@@ -285,7 +285,7 @@ pub fn add_cg_gcc_cargo_flags(cargo: &mut Cargo, gcc: &GccOutput) {
 /// The absolute path to the downloaded GCC artifacts.
 #[cfg(not(test))]
 fn ci_gcc_root(config: &crate::Config) -> PathBuf {
-    config.out.join(config.build).join("ci-gcc")
+    config.out.join(config.host_target).join("ci-gcc")
 }
 
 /// Detect whether GCC sources have been modified locally or not.
diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs
index 5419540aa2e..4434d6658eb 100644
--- a/src/bootstrap/src/core/build_steps/install.rs
+++ b/src/bootstrap/src/core/build_steps/install.rs
@@ -73,7 +73,7 @@ fn install_sh(
     let prefix = default_path(&builder.config.prefix, "/usr/local");
     let sysconfdir = prefix.join(default_path(&builder.config.sysconfdir, "/etc"));
     let destdir_env = env::var_os("DESTDIR").map(PathBuf::from);
-    let is_cygwin = builder.config.build.is_cygwin();
+    let is_cygwin = builder.config.host_target.is_cygwin();
 
     // Sanity checks on the write access of user.
     //
@@ -187,7 +187,7 @@ macro_rules! install {
 
             fn make_run(run: RunConfig<'_>) {
                 run.builder.ensure($name {
-                    compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
+                    compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target),
                     target: run.target,
                 });
             }
@@ -246,7 +246,7 @@ install!((self, builder, _config),
             );
         }
     };
-    LlvmTools, alias = "llvm-tools", _config.llvm_tools_enabled && _config.llvm_enabled(_config.build), only_hosts: true, {
+    LlvmTools, alias = "llvm-tools", _config.llvm_tools_enabled && _config.llvm_enabled(_config.host_target), only_hosts: true, {
         if let Some(tarball) = builder.ensure(dist::LlvmTools { target: self.target }) {
             install_sh(builder, "llvm-tools", self.compiler.stage, Some(self.target), &tarball);
         } else {
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index 2b7703000cb..8f2f143c352 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -132,14 +132,14 @@ pub fn prebuilt_llvm_config(
     let build_llvm_config = if let Some(build_llvm_config) = builder
         .config
         .target_config
-        .get(&builder.config.build)
+        .get(&builder.config.host_target)
         .and_then(|config| config.llvm_config.clone())
     {
         build_llvm_config
     } else {
-        let mut llvm_config_ret_dir = builder.llvm_out(builder.config.build);
+        let mut llvm_config_ret_dir = builder.llvm_out(builder.config.host_target);
         llvm_config_ret_dir.push("bin");
-        llvm_config_ret_dir.join(exe("llvm-config", builder.config.build))
+        llvm_config_ret_dir.join(exe("llvm-config", builder.config.host_target))
     };
 
     let llvm_cmake_dir = out_dir.join("lib/cmake/llvm");
@@ -235,8 +235,8 @@ pub(crate) fn is_ci_llvm_available_for_target(config: &Config, asserts: bool) ->
         ("x86_64-unknown-netbsd", false),
     ];
 
-    if !supported_platforms.contains(&(&*config.build.triple, asserts))
-        && (asserts || !supported_platforms.contains(&(&*config.build.triple, true)))
+    if !supported_platforms.contains(&(&*config.host_target.triple, asserts))
+        && (asserts || !supported_platforms.contains(&(&*config.host_target.triple, true)))
     {
         return false;
     }
@@ -480,7 +480,7 @@ impl Step for Llvm {
         // https://llvm.org/docs/HowToCrossCompileLLVM.html
         if !builder.config.is_host_target(target) {
             let LlvmResult { llvm_config, .. } =
-                builder.ensure(Llvm { target: builder.config.build });
+                builder.ensure(Llvm { target: builder.config.host_target });
             if !builder.config.dry_run() {
                 let llvm_bindir =
                     command(&llvm_config).arg("--bindir").run_capture_stdout(builder).stdout();
@@ -494,7 +494,8 @@ impl Step for Llvm {
             }
             cfg.define("LLVM_CONFIG_PATH", llvm_config);
             if builder.config.llvm_clang {
-                let build_bin = builder.llvm_out(builder.config.build).join("build").join("bin");
+                let build_bin =
+                    builder.llvm_out(builder.config.host_target).join("build").join("bin");
                 let clang_tblgen = build_bin.join("clang-tblgen").with_extension(EXE_EXTENSION);
                 if !builder.config.dry_run() && !clang_tblgen.exists() {
                     panic!("unable to find {}", clang_tblgen.display());
@@ -628,7 +629,7 @@ fn configure_cmake(
     if builder.ninja() {
         cfg.generator("Ninja");
     }
-    cfg.target(&target.triple).host(&builder.config.build.triple);
+    cfg.target(&target.triple).host(&builder.config.host_target.triple);
 
     if !builder.config.is_host_target(target) {
         cfg.define("CMAKE_CROSSCOMPILING", "True");
@@ -813,7 +814,7 @@ fn configure_cmake(
         ldflags.push_all(flags);
     }
 
-    if let Some(flags) = get_var("LDFLAGS", &builder.config.build.triple, &target.triple) {
+    if let Some(flags) = get_var("LDFLAGS", &builder.config.host_target.triple, &target.triple) {
         ldflags.push_all(&flags);
     }
 
@@ -1135,7 +1136,8 @@ impl Step for Sanitizers {
             return runtimes;
         }
 
-        let LlvmResult { llvm_config, .. } = builder.ensure(Llvm { target: builder.config.build });
+        let LlvmResult { llvm_config, .. } =
+            builder.ensure(Llvm { target: builder.config.host_target });
 
         static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new();
         let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| {
@@ -1345,7 +1347,7 @@ impl Step for CrtBeginEnd {
         cfg.cargo_metadata(false)
             .out_dir(&out_dir)
             .target(&self.target.triple)
-            .host(&builder.config.build.triple)
+            .host(&builder.config.host_target.triple)
             .warnings(false)
             .debug(false)
             .opt_level(3)
@@ -1424,7 +1426,7 @@ impl Step for Libunwind {
                 cfg.archiver(ar);
             }
             cfg.target(&self.target.triple);
-            cfg.host(&builder.config.build.triple);
+            cfg.host(&builder.config.host_target.triple);
             cfg.warnings(false);
             cfg.debug(false);
             // get_compiler() need set opt_level first.
diff --git a/src/bootstrap/src/core/build_steps/perf.rs b/src/bootstrap/src/core/build_steps/perf.rs
index 14c7b7cf5e9..c43043b48f4 100644
--- a/src/bootstrap/src/core/build_steps/perf.rs
+++ b/src/bootstrap/src/core/build_steps/perf.rs
@@ -136,8 +136,8 @@ impl Display for Scenario {
 /// Performs profiling using `rustc-perf` on a built version of the compiler.
 pub fn perf(builder: &Builder<'_>, args: &PerfArgs) {
     let collector = builder.ensure(RustcPerf {
-        compiler: builder.compiler(0, builder.config.build),
-        target: builder.config.build,
+        compiler: builder.compiler(0, builder.config.host_target),
+        target: builder.config.host_target,
     });
 
     let is_profiling = match &args.cmd {
@@ -151,8 +151,8 @@ pub fn perf(builder: &Builder<'_>, args: &PerfArgs) {
 Consider setting `rust.debuginfo-level = 1` in `bootstrap.toml`."#);
     }
 
-    let compiler = builder.compiler(builder.top_stage, builder.config.build);
-    builder.ensure(Std::new(compiler, builder.config.build));
+    let compiler = builder.compiler(builder.top_stage, builder.config.host_target);
+    builder.ensure(Std::new(compiler, builder.config.host_target));
 
     if let Some(opts) = args.cmd.shared_opts()
         && opts.profiles.contains(&Profile::Doc)
diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs
index 6ef1b13abcd..b3104ae05e8 100644
--- a/src/bootstrap/src/core/build_steps/run.rs
+++ b/src/bootstrap/src/core/build_steps/run.rs
@@ -116,7 +116,7 @@ impl Step for Miri {
     }
 
     fn run(self, builder: &Builder<'_>) {
-        let host = builder.build.build;
+        let host = builder.build.host_target;
         let target = self.target;
 
         // `x run` uses stage 0 by default but miri does not work well with stage 0.
@@ -448,7 +448,7 @@ impl Step for Rustfmt {
     }
 
     fn run(self, builder: &Builder<'_>) {
-        let host = builder.build.build;
+        let host = builder.build.host_target;
 
         // `x run` uses stage 0 by default but rustfmt does not work well with stage 0.
         // Change the stage to 1 if it's not set explicitly.
diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs
index 25adfdf1601..86b7456d7b4 100644
--- a/src/bootstrap/src/core/build_steps/setup.rs
+++ b/src/bootstrap/src/core/build_steps/setup.rs
@@ -260,7 +260,7 @@ impl Step for Link {
         }
 
         let stage_path =
-            ["build", config.build.rustc_target_arg(), "stage1"].join(MAIN_SEPARATOR_STR);
+            ["build", config.host_target.rustc_target_arg(), "stage1"].join(MAIN_SEPARATOR_STR);
 
         if stage_dir_exists(&stage_path[..]) && !config.dry_run() {
             attempt_toolchain_link(builder, &stage_path[..]);
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index dddce8fe05d..ebb926d81ce 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -70,7 +70,7 @@ impl Step for CrateBootstrap {
     }
 
     fn run(self, builder: &Builder<'_>) {
-        let bootstrap_host = builder.config.build;
+        let bootstrap_host = builder.config.host_target;
         let compiler = builder.compiler(0, bootstrap_host);
         let mut path = self.path.to_str().unwrap();
 
@@ -128,7 +128,7 @@ You can skip linkcheck with --skip src/tools/linkchecker"
         builder.info(&format!("Linkcheck ({host})"));
 
         // Test the linkchecker itself.
-        let bootstrap_host = builder.config.build;
+        let bootstrap_host = builder.config.host_target;
         let compiler = builder.compiler(0, bootstrap_host);
 
         let cargo = tool::prepare_tool_cargo(
@@ -525,7 +525,7 @@ impl Step for Miri {
 
     /// Runs `cargo test` for miri.
     fn run(self, builder: &Builder<'_>) {
-        let host = builder.build.build;
+        let host = builder.build.host_target;
         let target = self.target;
         let stage = builder.top_stage;
         if stage == 0 {
@@ -637,7 +637,7 @@ impl Step for CargoMiri {
 
     /// Tests `cargo miri test`.
     fn run(self, builder: &Builder<'_>) {
-        let host = builder.build.build;
+        let host = builder.build.host_target;
         let target = self.target;
         let stage = builder.top_stage;
         if stage == 0 {
@@ -915,7 +915,7 @@ impl Step for RustdocJSStd {
             Kind::Test,
             builder.top_stage,
             "rustdoc-js-std",
-            builder.config.build,
+            builder.config.host_target,
             self.target,
         );
         command.run(builder);
@@ -1607,7 +1607,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
             // At stage 0 (stage - 1) we are using the stage0 compiler. Using `self.target` can lead
             // finding an incorrect compiler path on cross-targets, as the stage 0 is always equal to
             // `build.build` in the configuration.
-            let build = builder.build.build;
+            let build = builder.build.host_target;
             compiler = builder.compiler(compiler.stage - 1, build);
             let test_stage = compiler.stage + 1;
             (test_stage, format!("stage{test_stage}-{build}"))
@@ -1729,7 +1729,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
         cmd.arg("--mode").arg(mode);
         cmd.arg("--target").arg(target.rustc_target_arg());
         cmd.arg("--host").arg(&*compiler.host.triple);
-        cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.build));
+        cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.host_target));
 
         if builder.build.config.llvm_enzyme {
             cmd.arg("--has-enzyme");
@@ -1900,7 +1900,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
         let mut copts_passed = false;
         if builder.config.llvm_enabled(compiler.host) {
             let llvm::LlvmResult { llvm_config, .. } =
-                builder.ensure(llvm::Llvm { target: builder.config.build });
+                builder.ensure(llvm::Llvm { target: builder.config.host_target });
             if !builder.config.dry_run() {
                 let llvm_version = get_llvm_version(builder, &llvm_config);
                 let llvm_components =
@@ -1947,7 +1947,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
                 // If LLD is available, add it to the PATH
                 if builder.config.lld_enabled {
                     let lld_install_root =
-                        builder.ensure(llvm::Lld { target: builder.config.build });
+                        builder.ensure(llvm::Lld { target: builder.config.host_target });
 
                     let lld_bin_path = lld_install_root.join("bin");
 
@@ -2202,7 +2202,7 @@ impl BookTest {
             let mut lib_paths = vec![];
             for dep in self.dependencies {
                 let mode = Mode::ToolRustc;
-                let target = builder.config.build;
+                let target = builder.config.host_target;
                 let cargo = tool::prepare_tool_cargo(
                     builder,
                     compiler,
@@ -2384,7 +2384,7 @@ impl Step for ErrorIndex {
         // error_index_generator depends on librustdoc. Use the compiler that
         // is normally used to build rustdoc for other tests (like compiletest
         // tests in tests/rustdoc) so that it shares the same artifacts.
-        let compiler = run.builder.compiler(run.builder.top_stage, run.builder.config.build);
+        let compiler = run.builder.compiler(run.builder.top_stage, run.builder.config.host_target);
         run.builder.ensure(ErrorIndex { compiler });
     }
 
@@ -2983,7 +2983,7 @@ impl Step for Distcheck {
             .arg("--enable-vendor")
             .current_dir(&dir)
             .run(builder);
-        command(helpers::make(&builder.config.build.triple))
+        command(helpers::make(&builder.config.host_target.triple))
             .arg("check")
             .current_dir(&dir)
             .run(builder);
@@ -3024,7 +3024,7 @@ impl Step for Bootstrap {
 
     /// Tests the build system itself.
     fn run(self, builder: &Builder<'_>) {
-        let host = builder.config.build;
+        let host = builder.config.host_target;
         let compiler = builder.compiler(0, host);
         let _guard = builder.msg(Kind::Test, 0, "bootstrap", host, host);
 
@@ -3035,7 +3035,7 @@ impl Step for Bootstrap {
         check_bootstrap
             .args(["-m", "unittest", "bootstrap_test.py"])
             .env("BUILD_DIR", &builder.out)
-            .env("BUILD_PLATFORM", builder.build.build.triple)
+            .env("BUILD_PLATFORM", builder.build.host_target.triple)
             .env("BOOTSTRAP_TEST_RUSTC_BIN", &builder.initial_rustc)
             .env("BOOTSTRAP_TEST_CARGO_BIN", &builder.initial_cargo)
             .current_dir(builder.src.join("src/bootstrap/"));
@@ -3090,8 +3090,11 @@ impl Step for TierCheck {
     }
 
     fn make_run(run: RunConfig<'_>) {
-        let compiler =
-            run.builder.compiler_for(run.builder.top_stage, run.builder.build.build, run.target);
+        let compiler = run.builder.compiler_for(
+            run.builder.top_stage,
+            run.builder.build.host_target,
+            run.target,
+        );
         run.builder.ensure(TierCheck { compiler });
     }
 
@@ -3142,7 +3145,7 @@ impl Step for LintDocs {
 
     fn make_run(run: RunConfig<'_>) {
         run.builder.ensure(LintDocs {
-            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
+            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target),
             target: run.target,
         });
     }
@@ -3168,7 +3171,7 @@ impl Step for RustInstaller {
 
     /// Ensure the version placeholder replacement tool builds
     fn run(self, builder: &Builder<'_>) {
-        let bootstrap_host = builder.config.build;
+        let bootstrap_host = builder.config.host_target;
         let compiler = builder.compiler(0, bootstrap_host);
         let cargo = tool::prepare_tool_cargo(
             builder,
@@ -3270,7 +3273,7 @@ impl Step for TestHelpers {
         cfg.cargo_metadata(false)
             .out_dir(&dst)
             .target(&target.triple)
-            .host(&builder.config.build.triple)
+            .host(&builder.config.host_target.triple)
             .opt_level(0)
             .warnings(false)
             .debug(false)
@@ -3560,7 +3563,7 @@ impl Step for TestFloatParse {
     }
 
     fn run(self, builder: &Builder<'_>) {
-        let bootstrap_host = builder.config.build;
+        let bootstrap_host = builder.config.host_target;
         let compiler = builder.compiler(builder.top_stage, bootstrap_host);
         let path = self.path.to_str().unwrap();
         let crate_name = self.path.iter().next_back().unwrap().to_str().unwrap();
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 9861637d8c8..f64d67341cf 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};
@@ -137,6 +136,19 @@ impl Step for ToolBuild {
             _ => panic!("unexpected Mode for tool build"),
         }
 
+        // build.tool.TOOL_NAME.features in bootstrap.toml allows specifying which features to
+        // enable for a specific tool. `extra_features` instead is not controlled by the toml and
+        // provides features that are always enabled for a specific tool (e.g. "in-rust-tree" for
+        // rust-analyzer). Finally, `prepare_tool_cargo` might add more features to adapt the build
+        // to the chosen flags (e.g. "all-static" for cargo if `cargo_native_static` is true).
+        let mut features = builder
+            .config
+            .tool
+            .get(self.tool)
+            .and_then(|tool| tool.features.clone())
+            .unwrap_or_default();
+        features.extend(self.extra_features.clone());
+
         let mut cargo = prepare_tool_cargo(
             builder,
             self.compiler,
@@ -145,7 +157,7 @@ impl Step for ToolBuild {
             Kind::Build,
             path,
             self.source_type,
-            &self.extra_features,
+            &features,
         );
 
         // The stage0 compiler changes infrequently and does not directly depend on code
@@ -278,7 +290,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);
     }
@@ -342,14 +354,14 @@ pub(crate) fn get_tool_rustc_compiler(
 
     if builder.download_rustc() && target_compiler.stage == 1 {
         // We shouldn't drop to stage0 compiler when using CI rustc.
-        return builder.compiler(1, builder.config.build);
+        return builder.compiler(1, builder.config.host_target);
     }
 
     // Similar to `compile::Assemble`, build with the previous stage's compiler. Otherwise
     // we'd have stageN/bin/rustc and stageN/bin/$rustc_tool be effectively different stage
     // compilers, which isn't what we want. Rustc tools should be linked in the same way as the
     // compiler it's paired with, so it must be built with the previous stage compiler.
-    builder.compiler(target_compiler.stage.saturating_sub(1), builder.config.build)
+    builder.compiler(target_compiler.stage.saturating_sub(1), builder.config.host_target)
 }
 
 /// Links a built tool binary with the given `name` from the build directory to the
@@ -390,8 +402,8 @@ macro_rules! bootstrap_tool {
                 match tool {
                     $(Tool::$name =>
                         self.ensure($name {
-                            compiler: self.compiler(0, self.config.build),
-                            target: self.config.build,
+                            compiler: self.compiler(0, self.config.host_target),
+                            target: self.config.host_target,
                         }).tool_path,
                     )+
                 }
@@ -415,7 +427,7 @@ macro_rules! bootstrap_tool {
             fn make_run(run: RunConfig<'_>) {
                 run.builder.ensure($name {
                     // snapshot compiler
-                    compiler: run.builder.compiler(0, run.builder.config.build),
+                    compiler: run.builder.compiler(0, run.builder.config.host_target),
                     target: run.target,
                 });
             }
@@ -532,7 +544,7 @@ impl Step for RustcPerf {
 
     fn make_run(run: RunConfig<'_>) {
         run.builder.ensure(RustcPerf {
-            compiler: run.builder.compiler(0, run.builder.config.build),
+            compiler: run.builder.compiler(0, run.builder.config.host_target),
             target: run.target,
         });
     }
@@ -573,7 +585,7 @@ impl ErrorIndex {
     pub fn command(builder: &Builder<'_>) -> BootstrapCommand {
         // Error-index-generator links with the rustdoc library, so we need to add `rustc_lib_paths`
         // for rustc_private and libLLVM.so, and `sysroot_lib` for libstd, etc.
-        let host = builder.config.build;
+        let host = builder.config.host_target;
         let compiler = builder.compiler_for(builder.top_stage, host, host);
         let mut cmd = command(builder.ensure(ErrorIndex { compiler }).tool_path);
         let mut dylib_paths = builder.rustc_lib_paths(compiler);
@@ -596,7 +608,7 @@ impl Step for ErrorIndex {
         // src/tools/error-index-generator` which almost nobody does.
         // Normally, `x.py test` or `x.py doc` will use the
         // `ErrorIndex::command` function instead.
-        let compiler = run.builder.compiler(run.builder.top_stage, run.builder.config.build);
+        let compiler = run.builder.compiler(run.builder.top_stage, run.builder.config.host_target);
         run.builder.ensure(ErrorIndex { compiler });
     }
 
@@ -631,7 +643,7 @@ impl Step for RemoteTestServer {
 
     fn make_run(run: RunConfig<'_>) {
         run.builder.ensure(RemoteTestServer {
-            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
+            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target),
             target: run.target,
         });
     }
@@ -788,7 +800,7 @@ impl Step for Cargo {
 
     fn make_run(run: RunConfig<'_>) {
         run.builder.ensure(Cargo {
-            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
+            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target),
             target: run.target,
         });
     }
@@ -906,7 +918,7 @@ impl Step for RustAnalyzer {
 
     fn make_run(run: RunConfig<'_>) {
         run.builder.ensure(RustAnalyzer {
-            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
+            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target),
             target: run.target,
         });
     }
@@ -951,7 +963,7 @@ impl Step for RustAnalyzerProcMacroSrv {
 
     fn make_run(run: RunConfig<'_>) {
         run.builder.ensure(RustAnalyzerProcMacroSrv {
-            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
+            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target),
             target: run.target,
         });
     }
@@ -1004,7 +1016,7 @@ impl Step for LlvmBitcodeLinker {
 
     fn make_run(run: RunConfig<'_>) {
         run.builder.ensure(LlvmBitcodeLinker {
-            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
+            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target),
             extra_features: Vec::new(),
             target: run.target,
         });
@@ -1142,7 +1154,7 @@ macro_rules! tool_extended {
 
             fn make_run(run: RunConfig<'_>) {
                 run.builder.ensure($name {
-                    compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
+                    compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.host_target),
                     target: run.target,
                 });
             }
@@ -1284,7 +1296,7 @@ impl Step for TestFloatParse {
     }
 
     fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
-        let bootstrap_host = builder.config.build;
+        let bootstrap_host = builder.config.host_target;
         let compiler = builder.compiler(builder.top_stage, bootstrap_host);
 
         builder.ensure(ToolBuild {
@@ -1307,7 +1319,7 @@ impl Builder<'_> {
     /// `host`.
     pub fn tool_cmd(&self, tool: Tool) -> BootstrapCommand {
         let mut cmd = command(self.tool_exe(tool));
-        let compiler = self.compiler(0, self.config.build);
+        let compiler = self.compiler(0, self.config.host_target);
         let host = &compiler.host;
         // Prepares the `cmd` provided to be able to run the `compiler` provided.
         //
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..887db683f78 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};
 
@@ -136,7 +137,7 @@ pub struct RunConfig<'a> {
 
 impl RunConfig<'_> {
     pub fn build_triple(&self) -> TargetSelection {
-        self.builder.build.build
+        self.builder.build.host_target
     }
 
     /// Return a list of crate names selected by `run.paths`.
@@ -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 {:?}",
@@ -1294,10 +1297,10 @@ impl<'a> Builder<'a> {
     ) -> Compiler {
         let mut resolved_compiler = if self.build.force_use_stage2(stage) {
             trace!(target: "COMPILER_FOR", ?stage, "force_use_stage2");
-            self.compiler(2, self.config.build)
+            self.compiler(2, self.config.host_target)
         } else if self.build.force_use_stage1(stage, target) {
             trace!(target: "COMPILER_FOR", ?stage, "force_use_stage1");
-            self.compiler(1, self.config.build)
+            self.compiler(1, self.config.host_target)
         } else {
             trace!(target: "COMPILER_FOR", ?stage, ?host, "no force, fallback to `compiler()`");
             self.compiler(stage, host)
@@ -1355,7 +1358,7 @@ impl<'a> Builder<'a> {
     /// Windows.
     pub fn libdir_relative(&self, compiler: Compiler) -> &Path {
         if compiler.is_snapshot(self) {
-            libdir(self.config.build).as_ref()
+            libdir(self.config.host_target).as_ref()
         } else {
             match self.config.libdir_relative() {
                 Some(relative_libdir) if compiler.stage >= 1 => relative_libdir,
@@ -1436,9 +1439,10 @@ impl<'a> Builder<'a> {
             return cmd;
         }
 
-        let _ = self.ensure(tool::Clippy { compiler: run_compiler, target: self.build.build });
-        let cargo_clippy =
-            self.ensure(tool::CargoClippy { compiler: run_compiler, target: self.build.build });
+        let _ =
+            self.ensure(tool::Clippy { compiler: run_compiler, target: self.build.host_target });
+        let cargo_clippy = self
+            .ensure(tool::CargoClippy { compiler: run_compiler, target: self.build.host_target });
         let mut dylib_path = helpers::dylib_path();
         dylib_path.insert(0, self.sysroot(run_compiler).join("lib"));
 
@@ -1451,9 +1455,10 @@ impl<'a> Builder<'a> {
     pub fn cargo_miri_cmd(&self, run_compiler: Compiler) -> BootstrapCommand {
         assert!(run_compiler.stage > 0, "miri can not be invoked at stage 0");
         // Prepare the tools
-        let miri = self.ensure(tool::Miri { compiler: run_compiler, target: self.build.build });
+        let miri =
+            self.ensure(tool::Miri { compiler: run_compiler, target: self.build.host_target });
         let cargo_miri =
-            self.ensure(tool::CargoMiri { compiler: run_compiler, target: self.build.build });
+            self.ensure(tool::CargoMiri { compiler: run_compiler, target: self.build.host_target });
         // Invoke cargo-miri, make sure it can find miri and cargo.
         let mut cmd = command(cargo_miri.tool_path);
         cmd.env("MIRI", &miri.tool_path);
@@ -1633,4 +1638,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..a26a96f2815 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.
@@ -46,7 +46,7 @@ fn configure_with_args(cmd: &[String], host: &[&str], target: &[&str]) -> Config
         .join(&thread::current().name().unwrap_or("unknown").replace(":", "-"));
     t!(fs::create_dir_all(&dir));
     config.out = dir;
-    config.build = TargetSelection::from_user(TEST_TRIPLE_1);
+    config.host_target = TargetSelection::from_user(TEST_TRIPLE_1);
     config.hosts = host.iter().map(|s| TargetSelection::from_user(s)).collect();
     config.targets = target.iter().map(|s| TargetSelection::from_user(s)).collect();
     config
@@ -1102,7 +1102,7 @@ fn test_prebuilt_llvm_config_path_resolution() {
     let actual = drop_win_disk_prefix_if_present(actual);
     assert_eq!(expected, actual);
 
-    let actual = prebuilt_llvm_config(&builder, builder.config.build, false)
+    let actual = prebuilt_llvm_config(&builder, builder.config.host_target, false)
         .llvm_result()
         .llvm_config
         .clone();
@@ -1120,15 +1120,15 @@ fn test_prebuilt_llvm_config_path_resolution() {
     let build = Build::new(config.clone());
     let builder = Builder::new(&build);
 
-    let actual = prebuilt_llvm_config(&builder, builder.config.build, false)
+    let actual = prebuilt_llvm_config(&builder, builder.config.host_target, false)
         .llvm_result()
         .llvm_config
         .clone();
     let expected = builder
         .out
-        .join(builder.config.build)
+        .join(builder.config.host_target)
         .join("llvm/bin")
-        .join(exe("llvm-config", builder.config.build));
+        .join(exe("llvm-config", builder.config.host_target));
     assert_eq!(expected, actual);
 
     let config = configure(
@@ -1143,15 +1143,15 @@ fn test_prebuilt_llvm_config_path_resolution() {
         let build = Build::new(config.clone());
         let builder = Builder::new(&build);
 
-        let actual = prebuilt_llvm_config(&builder, builder.config.build, false)
+        let actual = prebuilt_llvm_config(&builder, builder.config.host_target, false)
             .llvm_result()
             .llvm_config
             .clone();
         let expected = builder
             .out
-            .join(builder.config.build)
+            .join(builder.config.host_target)
             .join("ci-llvm/bin")
-            .join(exe("llvm-config", builder.config.build));
+            .join(exe("llvm-config", builder.config.host_target));
         assert_eq!(expected, actual);
     }
 }
@@ -1163,7 +1163,7 @@ fn test_is_builder_target() {
 
     for (target1, target2) in [(target1, target2), (target2, target1)] {
         let mut config = configure("build", &[], &[]);
-        config.build = target1;
+        config.host_target = target1;
         let build = Build::new(config);
         let builder = Builder::new(&build);
 
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 824b159c326..970a982dae4 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};
@@ -35,7 +35,7 @@ pub use crate::core::config::flags::Subcommand;
 use crate::core::config::flags::{Color, Flags};
 use crate::core::config::target_selection::TargetSelectionList;
 use crate::core::config::toml::TomlConfig;
-use crate::core::config::toml::build::Build;
+use crate::core::config::toml::build::{Build, Tool};
 use crate::core::config::toml::change_id::ChangeId;
 use crate::core::config::toml::rust::{
     LldMode, RustOptimize, check_incompatible_options_for_ci_rustc,
@@ -47,42 +47,31 @@ 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.
+/// Each path in this list 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
 /// when "if-unchanged" is set.
-pub fn rustc_if_unchanged_allowed_paths() -> Vec<&'static str> {
-    // NOTE: Paths must have the ":!" prefix to tell git to ignore changes in those paths during
-    // the diff check.
-    //
-    // WARNING: Be cautious when adding paths to this list. If a path that influences the compiler build
-    // is added here, it will cause bootstrap to skip necessary rebuilds, which may lead to risky results.
-    // For example, "src/bootstrap" should never be included in this list as it plays a crucial role in the
-    // final output/compiler, which can be significantly affected by changes made to the bootstrap sources.
-    let mut paths = vec![
-        ":!library",
-        ":!src/tools",
-        ":!src/librustdoc",
-        ":!src/rustdoc-json-types",
-        ":!tests",
-        ":!triagebot.toml",
-    ];
-
-    if !CiEnv::is_ci() {
-        // When a dependency is added/updated/removed in the library tree (or in some tools),
-        // `Cargo.lock` will be updated by `cargo`. This update will incorrectly invalidate the
-        // `download-rustc=if-unchanged` cache.
-        //
-        // To prevent this, add `Cargo.lock` to the list of allowed paths when not running on CI.
-        // This is generally safe because changes to dependencies typically involve modifying
-        // `Cargo.toml`, which would already invalidate the CI-rustc cache on non-allowed paths.
-        paths.push(":!Cargo.lock");
-    }
-
-    paths
-}
+///
+/// NOTE: Paths must have the ":!" prefix to tell git to ignore changes in those paths during
+/// the diff check.
+///
+/// WARNING: Be cautious when adding paths to this list. If a path that influences the compiler build
+/// is added here, it will cause bootstrap to skip necessary rebuilds, which may lead to risky results.
+/// For example, "src/bootstrap" should never be included in this list as it plays a crucial role in the
+/// final output/compiler, which can be significantly affected by changes made to the bootstrap sources.
+#[rustfmt::skip] // We don't want rustfmt to oneline this list
+pub const RUSTC_IF_UNCHANGED_ALLOWED_PATHS: &[&str] = &[
+    ":!library",
+    ":!src/tools",
+    ":!src/librustdoc",
+    ":!src/rustdoc-json-types",
+    ":!tests",
+    ":!triagebot.toml",
+];
 
 /// Global configuration for the entire build and/or bootstrap.
 ///
@@ -112,6 +101,9 @@ pub struct Config {
     pub bootstrap_cache_path: Option<PathBuf>,
     pub extended: bool,
     pub tools: Option<HashSet<String>>,
+    /// Specify build configuration specific for some tool, such as enabled features, see [Tool].
+    /// The key in the map is the name of the tool, and the value is tool-specific configuration.
+    pub tool: HashMap<String, Tool>,
     pub sanitizers: bool,
     pub profiler: bool,
     pub omit_git_hash: bool,
@@ -142,7 +134,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.
@@ -233,7 +224,7 @@ pub struct Config {
 
     pub reproducible_artifacts: Vec<String>,
 
-    pub build: TargetSelection,
+    pub host_target: TargetSelection,
     pub hosts: Vec<TargetSelection>,
     pub targets: Vec<TargetSelection>,
     pub local_rebuild: bool,
@@ -317,6 +308,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 {
@@ -356,7 +349,7 @@ impl Config {
             stderr_is_tty: std::io::stderr().is_terminal(),
 
             // set by build.rs
-            build: TargetSelection::from_user(env!("BUILD_TRIPLE")),
+            host_target: TargetSelection::from_user(env!("BUILD_TRIPLE")),
 
             src: {
                 let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
@@ -373,6 +366,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 +396,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 +429,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 +459,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 +556,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());
         }
 
@@ -678,6 +679,7 @@ impl Config {
             bootstrap_cache_path,
             extended,
             tools,
+            tool,
             verbose,
             sanitizers,
             profiler,
@@ -729,7 +731,7 @@ impl Config {
         config.jobs = Some(threads_from_config(flags.jobs.unwrap_or(jobs.unwrap_or(0))));
 
         if let Some(file_build) = build {
-            config.build = TargetSelection::from_user(&file_build);
+            config.host_target = TargetSelection::from_user(&file_build);
         };
 
         set(&mut config.out, flags.build_dir.or_else(|| build_dir.map(PathBuf::from)));
@@ -755,14 +757,19 @@ impl Config {
             config.download_beta_toolchain();
             config
                 .out
-                .join(config.build)
+                .join(config.host_target)
                 .join("stage0")
                 .join("bin")
-                .join(exe("rustc", config.build))
+                .join(exe("rustc", config.host_target))
         };
 
         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;
@@ -774,7 +781,7 @@ impl Config {
             cargo
         } else {
             config.download_beta_toolchain();
-            config.initial_sysroot.join("bin").join(exe("cargo", config.build))
+            config.initial_sysroot.join("bin").join(exe("cargo", config.host_target))
         };
 
         // NOTE: it's important this comes *after* we set `initial_rustc` just above.
@@ -789,7 +796,7 @@ impl Config {
         } else if let Some(file_host) = host {
             file_host.iter().map(|h| TargetSelection::from_user(h)).collect()
         } else {
-            vec![config.build]
+            vec![config.host_target]
         };
         config.targets = if let Some(TargetSelectionList(arg_target)) = flags.target {
             arg_target
@@ -819,6 +826,7 @@ impl Config {
         set(&mut config.full_bootstrap, full_bootstrap);
         set(&mut config.extended, extended);
         config.tools = tools;
+        set(&mut config.tool, tool);
         set(&mut config.verbose, verbose);
         set(&mut config.sanitizers, sanitizers);
         set(&mut config.profiler, profiler);
@@ -858,19 +866,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()
@@ -921,17 +931,19 @@ impl Config {
         }
 
         if config.llvm_from_ci {
-            let triple = &config.build.triple;
+            let triple = &config.host_target.triple;
             let ci_llvm_bin = config.ci_llvm_root().join("bin");
             let build_target = config
                 .target_config
-                .entry(config.build)
+                .entry(config.host_target)
                 .or_insert_with(|| Target::from_triple(triple));
 
             check_ci_llvm!(build_target.llvm_config);
             check_ci_llvm!(build_target.llvm_filecheck);
-            build_target.llvm_config = Some(ci_llvm_bin.join(exe("llvm-config", config.build)));
-            build_target.llvm_filecheck = Some(ci_llvm_bin.join(exe("FileCheck", config.build)));
+            build_target.llvm_config =
+                Some(ci_llvm_bin.join(exe("llvm-config", config.host_target)));
+            build_target.llvm_filecheck =
+                Some(ci_llvm_bin.join(exe("FileCheck", config.host_target)));
         }
 
         config.apply_dist_config(toml.dist);
@@ -948,7 +960,7 @@ impl Config {
             );
         }
 
-        if config.lld_enabled && config.is_system_llvm(config.build) {
+        if config.lld_enabled && config.is_system_llvm(config.host_target) {
             eprintln!(
                 "Warning: LLD is enabled when using external llvm-config. LLD will not be built and copied to the sysroot."
             );
@@ -1030,28 +1042,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 +1082,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.
@@ -1157,13 +1154,13 @@ impl Config {
     /// The absolute path to the downloaded LLVM artifacts.
     pub(crate) fn ci_llvm_root(&self) -> PathBuf {
         assert!(self.llvm_from_ci);
-        self.out.join(self.build).join("ci-llvm")
+        self.out.join(self.host_target).join("ci-llvm")
     }
 
     /// Directory where the extracted `rustc-dev` component is stored.
     pub(crate) fn ci_rustc_dir(&self) -> PathBuf {
         assert!(self.download_rustc());
-        self.out.join(self.build).join("ci-rustc")
+        self.out.join(self.host_target).join("ci-rustc")
     }
 
     /// Determine whether llvm should be linked dynamically.
@@ -1247,7 +1244,7 @@ impl Config {
                         // Check the config compatibility
                         // FIXME: this doesn't cover `--set` flags yet.
                         let res = check_incompatible_options_for_ci_rustc(
-                            self.build,
+                            self.host_target,
                             current_config_toml,
                             ci_config_toml,
                         );
@@ -1273,9 +1270,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 +1332,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 +1351,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,21 +1384,20 @@ 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 = branch.strip_prefix("heads/").unwrap_or(&branch);
+                let branch = current_branch.stdout();
+                let branch = branch.trim();
+                let branch = branch.strip_prefix("heads/").unwrap_or(branch);
                 git.arg("-c").arg(format!("branch.{branch}.remote=origin"));
             }
             git.args(["submodule", "update", "--init", "--recursive", "--depth=1"]);
@@ -1448,7 +1442,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();
@@ -1485,7 +1480,7 @@ impl Config {
         debug_assertions_requested: bool,
         llvm_assertions: bool,
     ) -> Option<String> {
-        if !is_download_ci_available(&self.build.triple, llvm_assertions) {
+        if !is_download_ci_available(&self.host_target.triple, llvm_assertions) {
             return None;
         }
 
@@ -1516,7 +1511,7 @@ impl Config {
         let commit = if self.rust_info.is_managed_git_subrepository() {
             // Look for a version to compare to based on the current commit.
             // Only commits merged by bors will have CI artifacts.
-            let freshness = self.check_path_modifications(&rustc_if_unchanged_allowed_paths());
+            let freshness = self.check_path_modifications(RUSTC_IF_UNCHANGED_ALLOWED_PATHS);
             self.verbose(|| {
                 eprintln!("rustc freshness: {freshness:?}");
             });
@@ -1721,7 +1716,7 @@ impl Config {
 
     /// Checks if the given target is the same as the host target.
     pub fn is_host_target(&self, target: TargetSelection) -> bool {
-        self.build == target
+        self.host_target == target
     }
 
     /// Returns `true` if this is an external version of LLVM not managed by bootstrap.
@@ -1754,4 +1749,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..ea0251e209a 100644
--- a/src/bootstrap/src/core/config/flags.rs
+++ b/src/bootstrap/src/core/config/flags.rs
@@ -59,7 +59,7 @@ pub struct Flags {
     pub build_dir: Option<PathBuf>,
 
     #[arg(global = true, long, value_hint = clap::ValueHint::Other, value_name = "BUILD")]
-    /// build target of the stage0 compiler
+    /// host target of the stage0 compiler
     pub build: Option<String>,
 
     #[arg(global = true, long, value_hint = clap::ValueHint::Other, value_name = "HOST", value_parser = target_selection_list)]
@@ -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/config/tests.rs b/src/bootstrap/src/core/config/tests.rs
index e660addfb2c..50eba12aba7 100644
--- a/src/bootstrap/src/core/config/tests.rs
+++ b/src/bootstrap/src/core/config/tests.rs
@@ -11,7 +11,7 @@ use serde::Deserialize;
 
 use super::flags::Flags;
 use super::toml::change_id::ChangeIdWrapper;
-use super::{Config, rustc_if_unchanged_allowed_paths};
+use super::{Config, RUSTC_IF_UNCHANGED_ALLOWED_PATHS};
 use crate::ChangeId;
 use crate::core::build_steps::clippy::{LintConfig, get_clippy_rules_in_order};
 use crate::core::build_steps::llvm;
@@ -459,7 +459,7 @@ fn jobs_precedence() {
 #[test]
 fn check_rustc_if_unchanged_paths() {
     let config = parse("");
-    let normalised_allowed_paths: Vec<_> = rustc_if_unchanged_allowed_paths()
+    let normalised_allowed_paths: Vec<_> = RUSTC_IF_UNCHANGED_ALLOWED_PATHS
         .iter()
         .map(|t| {
             t.strip_prefix(":!").expect(&format!("{t} doesn't have ':!' prefix, but it should."))
diff --git a/src/bootstrap/src/core/config/toml/build.rs b/src/bootstrap/src/core/config/toml/build.rs
index 85ded3c87d9..98e1194de72 100644
--- a/src/bootstrap/src/core/config/toml/build.rs
+++ b/src/bootstrap/src/core/config/toml/build.rs
@@ -6,6 +6,8 @@
 //! various feature flags. These options apply across different stages and components
 //! unless specifically overridden by other configuration sections or command-line flags.
 
+use std::collections::HashMap;
+
 use serde::{Deserialize, Deserializer};
 
 use crate::core::config::toml::ReplaceOpt;
@@ -42,6 +44,7 @@ define_config! {
         bootstrap_cache_path: Option<PathBuf> = "bootstrap-cache-path",
         extended: Option<bool> = "extended",
         tools: Option<HashSet<String>> = "tools",
+        tool: Option<HashMap<String, Tool>> = "tool",
         verbose: Option<usize> = "verbose",
         sanitizers: Option<bool> = "sanitizers",
         profiler: Option<bool> = "profiler",
@@ -70,3 +73,11 @@ define_config! {
         exclude: Option<Vec<PathBuf>> = "exclude",
     }
 }
+
+define_config! {
+    /// Configuration specific for some tool, e.g. which features to enable during build.
+    #[derive(Default, Clone)]
+    struct Tool {
+        features: Option<Vec<String>> = "features",
+    }
+}
diff --git a/src/bootstrap/src/core/config/toml/mod.rs b/src/bootstrap/src/core/config/toml/mod.rs
index ac4e249e580..01eb243159c 100644
--- a/src/bootstrap/src/core/config/toml/mod.rs
+++ b/src/bootstrap/src/core/config/toml/mod.rs
@@ -147,7 +147,7 @@ impl Config {
         }
 
         let builder_config_path =
-            self.out.join(self.build.triple).join(build_name).join(BUILDER_CONFIG_FILENAME);
+            self.out.join(self.host_target.triple).join(build_name).join(BUILDER_CONFIG_FILENAME);
         Self::get_toml(&builder_config_path)
     }
 
diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs
index 81f95f356a5..642f2f2271d 100644
--- a/src/bootstrap/src/core/config/toml/rust.rs
+++ b/src/bootstrap/src/core/config/toml/rust.rs
@@ -321,11 +321,11 @@ pub fn check_incompatible_options_for_ci_rustc(
         rpath,
         channel,
         description,
-        incremental,
         default_linker,
         std_features,
 
         // Rest of the options can simply be ignored.
+        incremental: _,
         debug: _,
         codegen_units: _,
         codegen_units_std: _,
@@ -389,7 +389,6 @@ pub fn check_incompatible_options_for_ci_rustc(
 
     warn!(current_rust_config.channel, channel, "rust");
     warn!(current_rust_config.description, description, "rust");
-    warn!(current_rust_config.incremental, incremental, "rust");
 
     Ok(())
 }
@@ -622,13 +621,13 @@ impl Config {
         //   thus, disabled
         // - similarly, lld will not be built nor used by default when explicitly asked not to, e.g.
         //   when the config sets `rust.lld = false`
-        if self.build.triple == "x86_64-unknown-linux-gnu"
-            && self.hosts == [self.build]
+        if self.host_target.triple == "x86_64-unknown-linux-gnu"
+            && self.hosts == [self.host_target]
             && (self.channel == "dev" || self.channel == "nightly")
         {
             let no_llvm_config = self
                 .target_config
-                .get(&self.build)
+                .get(&self.host_target)
                 .is_some_and(|target_config| target_config.llvm_config.is_none());
             let enable_lld = self.llvm_from_ci || no_llvm_config;
             // Prefer the config setting in case an explicit opt-out is needed.
diff --git a/src/bootstrap/src/core/config/toml/target.rs b/src/bootstrap/src/core/config/toml/target.rs
index 7f074d1b25e..b9f6780ca3f 100644
--- a/src/bootstrap/src/core/config/toml/target.rs
+++ b/src/bootstrap/src/core/config/toml/target.rs
@@ -84,7 +84,7 @@ pub struct Target {
 impl Target {
     pub fn from_triple(triple: &str) -> Self {
         let mut target: Self = Default::default();
-        if triple.contains("-none") || triple.contains("nvptx") || triple.contains("switch") {
+        if !build_helper::targets::target_supports_std(triple) {
             target.no_std = true;
         }
         if triple.contains("emscripten") {
@@ -101,7 +101,7 @@ impl Config {
                 let mut target = Target::from_triple(&triple);
 
                 if let Some(ref s) = cfg.llvm_config {
-                    if self.download_rustc_commit.is_some() && triple == *self.build.triple {
+                    if self.download_rustc_commit.is_some() && triple == *self.host_target.triple {
                         panic!(
                             "setting llvm_config for the host is incompatible with download-rustc"
                         );
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index ba00b405c61..88a58e580e6 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,15 +251,15 @@ 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);
         if !self.check_run(&mut curl) {
-            if self.build.contains("windows-msvc") {
+            if self.host_target.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");
                 }
             }
@@ -424,7 +411,7 @@ impl Config {
 
         let date = &self.stage0_metadata.compiler.date;
         let version = &self.stage0_metadata.compiler.version;
-        let host = self.build;
+        let host = self.host_target;
 
         let clippy_stamp =
             BuildStamp::new(&self.initial_sysroot).with_prefix("clippy").add_stamp(date);
@@ -462,7 +449,7 @@ impl Config {
         let VersionMetadata { date, version } = self.stage0_metadata.rustfmt.as_ref()?;
         let channel = format!("{version}-{date}");
 
-        let host = self.build;
+        let host = self.host_target;
         let bin_root = self.out.join(host).join("rustfmt");
         let rustfmt_path = bin_root.join("bin").join(exe("rustfmt", host));
         let rustfmt_stamp = BuildStamp::new(&bin_root).with_prefix("rustfmt").add_stamp(channel);
@@ -570,11 +557,11 @@ impl Config {
         extra_components: &[&str],
         download_component: fn(&Config, String, &str, &str),
     ) {
-        let host = self.build.triple;
+        let host = self.host_target.triple;
         let bin_root = self.out.join(host).join(sysroot);
         let rustc_stamp = BuildStamp::new(&bin_root).with_prefix("rustc").add_stamp(stamp_key);
 
-        if !bin_root.join("bin").join(exe("rustc", self.build)).exists()
+        if !bin_root.join("bin").join(exe("rustc", self.host_target)).exists()
             || !rustc_stamp.is_up_to_date()
         {
             if bin_root.exists() {
@@ -643,7 +630,7 @@ impl Config {
             t!(fs::create_dir_all(&cache_dir));
         }
 
-        let bin_root = self.out.join(self.build).join(destination);
+        let bin_root = self.out.join(self.host_target).join(destination);
         let tarball = cache_dir.join(&filename);
         let (base_url, url, should_verify) = match mode {
             DownloadSource::CI => {
@@ -772,7 +759,7 @@ download-rustc = false
             let now = std::time::SystemTime::now();
             let file_times = fs::FileTimes::new().set_accessed(now).set_modified(now);
 
-            let llvm_config = llvm_root.join("bin").join(exe("llvm-config", self.build));
+            let llvm_config = llvm_root.join("bin").join(exe("llvm-config", self.host_target));
             t!(crate::utils::helpers::set_file_times(llvm_config, file_times));
 
             if self.should_fix_bins_and_dylibs() {
@@ -827,7 +814,7 @@ download-rustc = false
             &self.stage0_metadata.config.artifacts_server
         };
         let version = self.artifact_version_part(llvm_sha);
-        let filename = format!("rust-dev-{}-{}.tar.xz", version, self.build.triple);
+        let filename = format!("rust-dev-{}-{}.tar.xz", version, self.host_target.triple);
         let tarball = rustc_cache.join(&filename);
         if !tarball.exists() {
             let help_on_error = "ERROR: failed to download llvm from ci
@@ -857,7 +844,7 @@ download-rustc = false
         }
         let base = &self.stage0_metadata.config.artifacts_server;
         let version = self.artifact_version_part(gcc_sha);
-        let filename = format!("gcc-{version}-{}.tar.xz", self.build.triple);
+        let filename = format!("gcc-{version}-{}.tar.xz", self.host_target.triple);
         let tarball = gcc_cache.join(&filename);
         if !tarball.exists() {
             let help_on_error = "ERROR: failed to download gcc from ci
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index 59ae303e21e..ef776e21943 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -109,9 +109,9 @@ pub fn check(build: &mut Build) {
 
     // Ensure that a compatible version of libstdc++ is available on the system when using `llvm.download-ci-llvm`.
     #[cfg(not(test))]
-    if !build.config.dry_run() && !build.build.is_msvc() && build.config.llvm_from_ci {
+    if !build.config.dry_run() && !build.host_target.is_msvc() && build.config.llvm_from_ci {
         let builder = Builder::new(build);
-        let libcxx_version = builder.ensure(tool::LibcxxVersionTool { target: build.build });
+        let libcxx_version = builder.ensure(tool::LibcxxVersionTool { target: build.host_target });
 
         match libcxx_version {
             tool::LibcxxVersion::Gnu(version) => {
@@ -237,7 +237,7 @@ than building it.
         }
 
         // skip check for cross-targets
-        if skip_target_sanity && target != &build.build {
+        if skip_target_sanity && target != &build.host_target {
             continue;
         }
 
@@ -308,7 +308,7 @@ than building it.
 
             if build.config.llvm_enabled(*host) {
                 // Externally configured LLVM requires FileCheck to exist
-                let filecheck = build.llvm_filecheck(build.build);
+                let filecheck = build.llvm_filecheck(build.host_target);
                 if !filecheck.starts_with(&build.out)
                     && !filecheck.exists()
                     && build.config.codegen_tests
@@ -333,7 +333,7 @@ than building it.
         }
 
         // skip check for cross-targets
-        if skip_target_sanity && target != &build.build {
+        if skip_target_sanity && target != &build.host_target {
             continue;
         }
 
@@ -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..25e59bfe3a8 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;
@@ -174,7 +175,7 @@ pub struct Build {
     verbosity: usize,
 
     /// Build triple for the pre-compiled snapshot compiler.
-    build: TargetSelection,
+    host_target: TargetSelection,
     /// Which triples to produce a compiler toolchain for.
     hosts: Vec<TargetSelection>,
     /// Which triples to build libraries (core/alloc/std/test/proc_macro) for.
@@ -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")]
@@ -420,7 +420,7 @@ impl Build {
         if bootstrap_out.ends_with("deps") {
             bootstrap_out.pop();
         }
-        if !bootstrap_out.join(exe("rustc", config.build)).exists() && !cfg!(test) {
+        if !bootstrap_out.join(exe("rustc", config.host_target)).exists() && !cfg!(test) {
             // this restriction can be lifted whenever https://github.com/rust-lang/rfcs/pull/3028 is implemented
             panic!(
                 "`rustc` not found in {}, run `cargo build --bins` before `cargo run`",
@@ -436,7 +436,9 @@ impl Build {
             initial_lld,
             initial_relative_libdir,
             initial_rustc: config.initial_rustc.clone(),
-            initial_rustdoc: config.initial_rustc.with_file_name(exe("rustdoc", config.build)),
+            initial_rustdoc: config
+                .initial_rustc
+                .with_file_name(exe("rustdoc", config.host_target)),
             initial_cargo: config.initial_cargo.clone(),
             initial_sysroot: config.initial_sysroot.clone(),
             local_rebuild: config.local_rebuild,
@@ -444,7 +446,7 @@ impl Build {
             doc_tests: config.cmd.doc_tests(),
             verbosity: config.verbose,
 
-            build: config.build,
+            host_target: config.host_target,
             hosts: config.hosts.clone(),
             targets: config.targets.clone(),
 
@@ -469,7 +471,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")]
@@ -522,7 +523,7 @@ impl Build {
         }
 
         // Create symbolic link to use host sysroot from a consistent path (e.g., in the rust-analyzer config file).
-        let build_triple = build.out.join(build.build);
+        let build_triple = build.out.join(build.host_target);
         t!(fs::create_dir_all(&build_triple));
         let host = build.out.join("host");
         if host.is_symlink() {
@@ -629,7 +630,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 +685,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 +695,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 +711,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);
@@ -940,7 +934,7 @@ impl Build {
 
     /// Returns the libdir of the snapshot compiler.
     fn rustc_snapshot_libdir(&self) -> PathBuf {
-        self.rustc_snapshot_sysroot().join(libdir(self.config.build))
+        self.rustc_snapshot_sysroot().join(libdir(self.config.host_target))
     }
 
     /// Returns the sysroot of the snapshot compiler.
@@ -953,133 +947,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 +960,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}");
@@ -1108,7 +975,7 @@ Executed at: {executed_at}"#,
         what: impl Display,
         target: impl Into<Option<TargetSelection>>,
     ) -> Option<gha::Group> {
-        self.msg(Kind::Clippy, self.config.stage, what, self.config.build, target)
+        self.msg(Kind::Clippy, self.config.stage, what, self.config.host_target, target)
     }
 
     #[must_use = "Groups should not be dropped until the Step finishes running"]
@@ -1123,7 +990,7 @@ Executed at: {executed_at}"#,
             Kind::Check,
             custom_stage.unwrap_or(self.config.stage),
             what,
-            self.config.build,
+            self.config.host_target,
             target,
         )
     }
@@ -1216,7 +1083,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)),
         }
@@ -1381,7 +1248,7 @@ Executed at: {executed_at}"#,
             Some(self.cc(target))
         } else if self.config.lld_mode.is_used()
             && self.is_lld_direct_linker(target)
-            && self.build == target
+            && self.host_target == target
         {
             match self.config.lld_mode {
                 LldMode::SelfContained => Some(self.initial_lld.clone()),
@@ -1535,7 +1402,7 @@ Executed at: {executed_at}"#,
 
     /// Path to the python interpreter to use
     fn python(&self) -> &Path {
-        if self.config.build.ends_with("apple-darwin") {
+        if self.config.host_target.ends_with("apple-darwin") {
             // Force /usr/bin/python3 on macOS for LLDB tests because we're loading the
             // LLDB plugin's compiled module which only works with the system python
             // (namely not Homebrew-installed python)
@@ -1575,7 +1442,7 @@ Executed at: {executed_at}"#,
         !self.config.full_bootstrap
             && !self.config.download_rustc()
             && stage >= 2
-            && (self.hosts.contains(&target) || target == self.build)
+            && (self.hosts.contains(&target) || target == self.host_target)
     }
 
     /// Checks whether the `compiler` compiling for `target` should be forced to
@@ -2012,7 +1879,7 @@ to download LLVM rather than building it.
         // In these cases we automatically enable Ninja if we find it in the
         // environment.
         if !self.config.ninja_in_file
-            && self.config.build.is_msvc()
+            && self.config.host_target.is_msvc()
             && cmd_finder.maybe_have("ninja").is_some()
         {
             return true;
@@ -2045,6 +1912,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)]
@@ -2071,7 +1948,7 @@ impl Compiler {
 
     /// Returns `true` if this is a snapshot compiler for `build`'s configuration
     pub fn is_snapshot(&self, build: &Build) -> bool {
-        self.stage == 0 && self.host == build.build
+        self.stage == 0 && self.host == build.host_target
     }
 
     /// Indicates whether the compiler was forced to use a specific stage.
diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs
index 5c9e30706ee..851bb38074e 100644
--- a/src/bootstrap/src/utils/cc_detect.rs
+++ b/src/bootstrap/src/utils/cc_detect.rs
@@ -39,7 +39,7 @@ fn new_cc_build(build: &Build, target: TargetSelection) -> cc::Build {
         // Compress debuginfo
         .flag_if_supported("-gz")
         .target(&target.triple)
-        .host(&build.build.triple);
+        .host(&build.host_target.triple);
     match build.crt_static(target) {
         Some(a) => {
             cfg.static_crt(a);
@@ -70,7 +70,7 @@ pub fn find(build: &Build) {
         | crate::Subcommand::Suggest { .. }
         | crate::Subcommand::Format { .. }
         | crate::Subcommand::Setup { .. } => {
-            build.hosts.iter().cloned().chain(iter::once(build.build)).collect()
+            build.hosts.iter().cloned().chain(iter::once(build.host_target)).collect()
         }
 
         _ => {
@@ -81,7 +81,7 @@ pub fn find(build: &Build) {
                 .iter()
                 .chain(&build.hosts)
                 .cloned()
-                .chain(iter::once(build.build))
+                .chain(iter::once(build.host_target))
                 .collect()
         }
     };
diff --git a/src/bootstrap/src/utils/cc_detect/tests.rs b/src/bootstrap/src/utils/cc_detect/tests.rs
index 225fb7619b5..1f50738959f 100644
--- a/src/bootstrap/src/utils/cc_detect/tests.rs
+++ b/src/bootstrap/src/utils/cc_detect/tests.rs
@@ -155,7 +155,7 @@ fn test_find() {
     build.targets.push(target1.clone());
     build.hosts.push(target2.clone());
     find(&build);
-    for t in build.hosts.iter().chain(build.targets.iter()).chain(iter::once(&build.build)) {
+    for t in build.hosts.iter().chain(build.targets.iter()).chain(iter::once(&build.host_target)) {
         assert!(build.cc.borrow().contains_key(t), "CC not set for target {}", t.triple);
     }
 }
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index e939a8362ad..93e01a58077 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -421,4 +421,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Info,
         summary: "Added new bootstrap flag `--skip-std-check-if-no-download-rustc` that skips std checks when download-rustc is unavailable. Mainly intended for developers to reduce RA overhead.",
     },
+    ChangeInfo {
+        change_id: 142379,
+        severity: ChangeSeverity::Info,
+        summary: "Added new option `tool.TOOL_NAME.features` to specify the features to compile a tool with",
+    },
 ];
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..a5e1e9bcc07
--- /dev/null
+++ b/src/bootstrap/src/utils/execution_context.rs
@@ -0,0 +1,204 @@
+//! 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;
+#[cfg(feature = "tracing")]
+use crate::trace_cmd;
+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/build_helper/src/lib.rs b/src/build_helper/src/lib.rs
index 1f5cf723641..05de8fd2d42 100644
--- a/src/build_helper/src/lib.rs
+++ b/src/build_helper/src/lib.rs
@@ -6,6 +6,7 @@ pub mod fs;
 pub mod git;
 pub mod metrics;
 pub mod stage0_parser;
+pub mod targets;
 pub mod util;
 
 /// The default set of crates for opt-dist to collect LLVM profiles.
diff --git a/src/build_helper/src/targets.rs b/src/build_helper/src/targets.rs
new file mode 100644
index 00000000000..cccc413368b
--- /dev/null
+++ b/src/build_helper/src/targets.rs
@@ -0,0 +1,11 @@
+// FIXME(#142296): this hack is because there is no reliable way (yet) to determine whether a given
+// target supports std. In the long-term, we should try to implement a way to *reliably* determine
+// target (std) metadata.
+//
+// NOTE: this is pulled out to `build_helpers` to share this hack between `bootstrap` and
+// `compiletest`.
+pub fn target_supports_std(target_tuple: &str) -> bool {
+    !(target_tuple.contains("-none")
+        || target_tuple.contains("nvptx")
+        || target_tuple.contains("switch"))
+}
diff --git a/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile
index a1d04bd984c..ce18a181d31 100644
--- a/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check-2/Dockerfile
@@ -36,4 +36,7 @@ ENV SCRIPT \
         RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 1 library && \
         mkdir -p /checkout/obj/staging/doc && \
         cp -r build/x86_64-unknown-linux-gnu/doc /checkout/obj/staging && \
-        RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 1 library/test
+        RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc --stage 1 library/test && \
+        # The BOOTSTRAP_TRACING flag is added to verify whether the 
+        # bootstrap process compiles successfully with this flag enabled.
+        BOOTSTRAP_TRACING=1 python3 ../x.py --help
diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version
index c8721bb3600..86d35b31498 100644
--- a/src/doc/rustc-dev-guide/rust-version
+++ b/src/doc/rustc-dev-guide/rust-version
@@ -1 +1 @@
-c31cccb7b5cc098b1a8c1794ed38d7fdbec0ccb0
+14346303d760027e53214e705109a62c0f00b214
diff --git a/src/doc/rustc-dev-guide/src/git.md b/src/doc/rustc-dev-guide/src/git.md
index 8118ddff10c..8726ddfce20 100644
--- a/src/doc/rustc-dev-guide/src/git.md
+++ b/src/doc/rustc-dev-guide/src/git.md
@@ -142,7 +142,8 @@ The most common cause is that you rebased after a change and ran `git add .` wit
 `x` to update the submodules.  Alternatively, you might have run `cargo fmt` instead of `x fmt`
 and modified files in a submodule, then committed the changes.
 
-To fix it, do the following things:
+To fix it, do the following things (if you changed a submodule other than cargo,
+replace `src/tools/cargo` with the path to that submodule):
 
 1. See which commit has the accidental changes: `git log --stat -n1 src/tools/cargo`
 2. Revert the changes to that commit: `git checkout <my-commit>~ src/tools/cargo`. Type `~`
diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md
index 20dd16c81df..ded30234e70 100644
--- a/src/doc/rustc-dev-guide/src/tests/compiletest.md
+++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md
@@ -115,7 +115,7 @@ default behavior without any commands is to:
 2. Run `rustc -Zunpretty=normal` on the output of the previous step.
 3. The output of the previous two steps should be the same.
 4. Run `rustc -Zno-codegen` on the output to make sure that it can type check
-   (this is similar to running `cargo check`).
+   (similar to `cargo check`).
 
 If any of the commands above fail, then the test fails.
 
diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md
index f73a2811d5a..839076b809d 100644
--- a/src/doc/rustc-dev-guide/src/tests/directives.md
+++ b/src/doc/rustc-dev-guide/src/tests/directives.md
@@ -202,6 +202,7 @@ settings:
   `//@ needs-crate-type: cdylib, proc-macro` will cause the test to be ignored
   on `wasm32-unknown-unknown` target because the target does not support the
   `proc-macro` crate type.
+- `needs-target-std` — ignores if target platform does not have std support.
 
 The following directives will check LLVM support:
 
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/doc/rustc/src/platform-support/loongarch-none.md b/src/doc/rustc/src/platform-support/loongarch-none.md
index fd90b0a2763..7c3a7e6c8bc 100644
--- a/src/doc/rustc/src/platform-support/loongarch-none.md
+++ b/src/doc/rustc/src/platform-support/loongarch-none.md
@@ -11,8 +11,8 @@ Freestanding/bare-metal LoongArch binaries in ELF format: firmware, kernels, etc
 
 ## Target maintainers
 
-- [@heiher](https://github.com/heiher)
-- [@xen0n](https://github.com/xen0n)
+[@heiher](https://github.com/heiher)
+[@xen0n](https://github.com/xen0n)
 
 ## Requirements
 
diff --git a/src/doc/unstable-book/src/compiler-flags/macro-stats.md b/src/doc/unstable-book/src/compiler-flags/macro-stats.md
new file mode 100644
index 00000000000..b2622cff057
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/macro-stats.md
@@ -0,0 +1,24 @@
+# `macro-stats`
+
+This feature is perma-unstable and has no tracking issue.
+
+----
+
+Some macros, especially procedural macros, can generate a surprising amount of
+code, which can slow down compile times. This is hard to detect because the
+generated code is normally invisible to the programmer.
+
+This flag helps identify such cases. When enabled, the compiler measures the
+effect on code size of all used macros and prints a table summarizing that
+effect. For each distinct macro, it counts how many times it is used, and the
+net effect on code size (in terms of lines of code, and bytes of code). The
+code size evaluation uses the compiler's internal pretty-printing, and so will
+be independent of the formatting in the original code.
+
+Note that the net effect of a macro may be negative. E.g. the `cfg!` and
+`#[test]` macros often strip out code.
+
+If a macro is identified as causing a large increase in code size, it is worth
+using `cargo expand` to inspect the post-expansion code, which includes the
+code produced by all macros. It may be possible to optimize the macro to
+produce smaller code, or it may be possible to avoid using it altogether.
diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
index d9566c9f55c..121f9493435 100644
--- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
+++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
@@ -19,6 +19,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 - M68k
 - CSKY
 - SPARC
+- LoongArch32
 
 ## Register classes
 
@@ -53,6 +54,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | CSKY         | `freg`         | `f[0-31]`                          | `f`                  |
 | SPARC        | `reg`          | `r[2-29]`                          | `r`                  |
 | SPARC        | `yreg`         | `y`                                | Only clobbers        |
+| LoongArch32  | `reg`          | `$r1`, `$r[4-20]`, `$r[23,30]`     | `r`                  |
+| LoongArch32  | `freg`         | `$f[0-31]`                         | `f`                  |
 
 > **Notes**:
 > - NVPTX doesn't have a fixed register set, so named registers are not supported.
@@ -91,6 +94,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | CSKY         | `freg`                          | None           | `f32`,                                  |
 | SPARC        | `reg`                           | None           | `i8`, `i16`, `i32`, `i64` (SPARC64 only) |
 | SPARC        | `yreg`                          | N/A            | Only clobbers                           |
+| LoongArch32  | `reg`                           | None           | `i8`, `i16`, `i32`, `f32`               |
+| LoongArch32  | `freg`                          | None           | `f32`, `f64`                            |
 
 ## Register aliases
 
diff --git a/src/etc/completions/x.fish b/src/etc/completions/x.fish
index 10a4e684e33..a030f45830e 100644
--- a/src/etc/completions/x.fish
+++ b/src/etc/completions/x.fish
@@ -26,7 +26,7 @@ end
 
 complete -c x -n "__fish_x_needs_command" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_needs_command" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_needs_command" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x -n "__fish_x_needs_command" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x -n "__fish_x_needs_command" -l host -d 'host targets to build' -r -f
 complete -c x -n "__fish_x_needs_command" -l target -d 'target targets to build' -r -f
 complete -c x -n "__fish_x_needs_command" -l exclude -d 'build paths to exclude' -r -F
@@ -78,7 +78,7 @@ complete -c x -n "__fish_x_needs_command" -a "vendor" -d 'Vendor dependencies'
 complete -c x -n "__fish_x_needs_command" -a "perf" -d 'Perform profiling and benchmarking of the compiler using `rustc-perf`'
 complete -c x -n "__fish_x_using_subcommand build" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand build" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand build" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x -n "__fish_x_using_subcommand build" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x -n "__fish_x_using_subcommand build" -l host -d 'host targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand build" -l target -d 'target targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand build" -l exclude -d 'build paths to exclude' -r -F
@@ -113,7 +113,7 @@ complete -c x -n "__fish_x_using_subcommand build" -l skip-std-check-if-no-downl
 complete -c x -n "__fish_x_using_subcommand build" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x -n "__fish_x_using_subcommand check" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand check" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand check" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x -n "__fish_x_using_subcommand check" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x -n "__fish_x_using_subcommand check" -l host -d 'host targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand check" -l target -d 'target targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand check" -l exclude -d 'build paths to exclude' -r -F
@@ -153,7 +153,7 @@ complete -c x -n "__fish_x_using_subcommand clippy" -s W -d 'clippy lints to war
 complete -c x -n "__fish_x_using_subcommand clippy" -s F -d 'clippy lints to forbid' -r
 complete -c x -n "__fish_x_using_subcommand clippy" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand clippy" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand clippy" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x -n "__fish_x_using_subcommand clippy" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x -n "__fish_x_using_subcommand clippy" -l host -d 'host targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand clippy" -l target -d 'target targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand clippy" -l exclude -d 'build paths to exclude' -r -F
@@ -191,7 +191,7 @@ complete -c x -n "__fish_x_using_subcommand clippy" -l skip-std-check-if-no-down
 complete -c x -n "__fish_x_using_subcommand clippy" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x -n "__fish_x_using_subcommand fix" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand fix" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand fix" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x -n "__fish_x_using_subcommand fix" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x -n "__fish_x_using_subcommand fix" -l host -d 'host targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand fix" -l target -d 'target targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand fix" -l exclude -d 'build paths to exclude' -r -F
@@ -226,7 +226,7 @@ complete -c x -n "__fish_x_using_subcommand fix" -l skip-std-check-if-no-downloa
 complete -c x -n "__fish_x_using_subcommand fix" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x -n "__fish_x_using_subcommand fmt" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand fmt" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand fmt" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x -n "__fish_x_using_subcommand fmt" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x -n "__fish_x_using_subcommand fmt" -l host -d 'host targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand fmt" -l target -d 'target targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand fmt" -l exclude -d 'build paths to exclude' -r -F
@@ -263,7 +263,7 @@ complete -c x -n "__fish_x_using_subcommand fmt" -l skip-std-check-if-no-downloa
 complete -c x -n "__fish_x_using_subcommand fmt" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x -n "__fish_x_using_subcommand doc" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand doc" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand doc" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x -n "__fish_x_using_subcommand doc" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x -n "__fish_x_using_subcommand doc" -l host -d 'host targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand doc" -l target -d 'target targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand doc" -l exclude -d 'build paths to exclude' -r -F
@@ -306,7 +306,7 @@ complete -c x -n "__fish_x_using_subcommand test" -l pass -d 'force {check,build
 complete -c x -n "__fish_x_using_subcommand test" -l run -d 'whether to execute run-* tests' -r
 complete -c x -n "__fish_x_using_subcommand test" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand test" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand test" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x -n "__fish_x_using_subcommand test" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x -n "__fish_x_using_subcommand test" -l host -d 'host targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand test" -l target -d 'target targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand test" -l exclude -d 'build paths to exclude' -r -F
@@ -350,7 +350,7 @@ complete -c x -n "__fish_x_using_subcommand test" -s h -l help -d 'Print help (s
 complete -c x -n "__fish_x_using_subcommand miri" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r
 complete -c x -n "__fish_x_using_subcommand miri" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand miri" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand miri" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x -n "__fish_x_using_subcommand miri" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x -n "__fish_x_using_subcommand miri" -l host -d 'host targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand miri" -l target -d 'target targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand miri" -l exclude -d 'build paths to exclude' -r -F
@@ -389,7 +389,7 @@ complete -c x -n "__fish_x_using_subcommand miri" -s h -l help -d 'Print help (s
 complete -c x -n "__fish_x_using_subcommand bench" -l test-args -r
 complete -c x -n "__fish_x_using_subcommand bench" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand bench" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand bench" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x -n "__fish_x_using_subcommand bench" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x -n "__fish_x_using_subcommand bench" -l host -d 'host targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand bench" -l target -d 'target targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand bench" -l exclude -d 'build paths to exclude' -r -F
@@ -425,7 +425,7 @@ complete -c x -n "__fish_x_using_subcommand bench" -s h -l help -d 'Print help (
 complete -c x -n "__fish_x_using_subcommand clean" -l stage -d 'Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used' -r
 complete -c x -n "__fish_x_using_subcommand clean" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand clean" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand clean" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x -n "__fish_x_using_subcommand clean" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x -n "__fish_x_using_subcommand clean" -l host -d 'host targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand clean" -l target -d 'target targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand clean" -l exclude -d 'build paths to exclude' -r -F
@@ -460,7 +460,7 @@ complete -c x -n "__fish_x_using_subcommand clean" -l skip-std-check-if-no-downl
 complete -c x -n "__fish_x_using_subcommand clean" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x -n "__fish_x_using_subcommand dist" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand dist" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand dist" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x -n "__fish_x_using_subcommand dist" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x -n "__fish_x_using_subcommand dist" -l host -d 'host targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand dist" -l target -d 'target targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand dist" -l exclude -d 'build paths to exclude' -r -F
@@ -495,7 +495,7 @@ complete -c x -n "__fish_x_using_subcommand dist" -l skip-std-check-if-no-downlo
 complete -c x -n "__fish_x_using_subcommand dist" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x -n "__fish_x_using_subcommand install" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand install" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand install" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x -n "__fish_x_using_subcommand install" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x -n "__fish_x_using_subcommand install" -l host -d 'host targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand install" -l target -d 'target targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand install" -l exclude -d 'build paths to exclude' -r -F
@@ -531,7 +531,7 @@ complete -c x -n "__fish_x_using_subcommand install" -s h -l help -d 'Print help
 complete -c x -n "__fish_x_using_subcommand run" -l args -d 'arguments for the tool' -r
 complete -c x -n "__fish_x_using_subcommand run" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand run" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand run" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x -n "__fish_x_using_subcommand run" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x -n "__fish_x_using_subcommand run" -l host -d 'host targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand run" -l target -d 'target targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand run" -l exclude -d 'build paths to exclude' -r -F
@@ -566,7 +566,7 @@ complete -c x -n "__fish_x_using_subcommand run" -l skip-std-check-if-no-downloa
 complete -c x -n "__fish_x_using_subcommand run" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x -n "__fish_x_using_subcommand setup" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand setup" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand setup" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x -n "__fish_x_using_subcommand setup" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x -n "__fish_x_using_subcommand setup" -l host -d 'host targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand setup" -l target -d 'target targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand setup" -l exclude -d 'build paths to exclude' -r -F
@@ -601,7 +601,7 @@ complete -c x -n "__fish_x_using_subcommand setup" -l skip-std-check-if-no-downl
 complete -c x -n "__fish_x_using_subcommand setup" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x -n "__fish_x_using_subcommand suggest" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand suggest" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand suggest" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x -n "__fish_x_using_subcommand suggest" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x -n "__fish_x_using_subcommand suggest" -l host -d 'host targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand suggest" -l target -d 'target targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand suggest" -l exclude -d 'build paths to exclude' -r -F
@@ -638,7 +638,7 @@ complete -c x -n "__fish_x_using_subcommand suggest" -s h -l help -d 'Print help
 complete -c x -n "__fish_x_using_subcommand vendor" -l sync -d 'Additional `Cargo.toml` to sync and vendor' -r -F
 complete -c x -n "__fish_x_using_subcommand vendor" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand vendor" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand vendor" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x -n "__fish_x_using_subcommand vendor" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x -n "__fish_x_using_subcommand vendor" -l host -d 'host targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand vendor" -l target -d 'target targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand vendor" -l exclude -d 'build paths to exclude' -r -F
@@ -674,7 +674,7 @@ complete -c x -n "__fish_x_using_subcommand vendor" -l skip-std-check-if-no-down
 complete -c x -n "__fish_x_using_subcommand vendor" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l host -d 'host targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l target -d 'target targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l exclude -d 'build paths to exclude' -r -F
@@ -718,7 +718,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',Opt\t'',Clippy\t''}"
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l host -d 'host targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l target -d 'target targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l skip -d 'build paths to skip' -r -F
@@ -756,7 +756,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',Opt\t'',Clippy\t''}"
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l host -d 'host targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l target -d 'target targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from samply" -l skip -d 'build paths to skip' -r -F
@@ -794,7 +794,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',Opt\t'',Clippy\t''}"
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l host -d 'host targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l target -d 'target targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l skip -d 'build paths to skip' -r -F
@@ -832,7 +832,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',Opt\t'',Clippy\t''}"
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l host -d 'host targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l target -d 'target targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l skip -d 'build paths to skip' -r -F
@@ -866,7 +866,7 @@ complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_fro
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l config -d 'TOML configuration file for build' -r -F
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l host -d 'host targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l target -d 'target targets to build' -r -f
 complete -c x -n "__fish_x_using_subcommand perf; and __fish_seen_subcommand_from compare" -l exclude -d 'build paths to exclude' -r -F
diff --git a/src/etc/completions/x.ps1 b/src/etc/completions/x.ps1
index 23d8fe0cdd3..a891a9db332 100644
--- a/src/etc/completions/x.ps1
+++ b/src/etc/completions/x.ps1
@@ -23,7 +23,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
         'x' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -82,7 +82,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
         'x;build' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -124,7 +124,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
         'x;check' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -171,7 +171,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
             [CompletionResult]::new('-F', '-F ', [CompletionResultType]::ParameterName, 'clippy lints to forbid')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -216,7 +216,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
         'x;fix' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -258,7 +258,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
         'x;fmt' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -302,7 +302,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
         'x;doc' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -352,7 +352,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
             [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'whether to execute run-* tests')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -403,7 +403,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
             [CompletionResult]::new('--test-args', '--test-args', [CompletionResultType]::ParameterName, 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -449,7 +449,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
             [CompletionResult]::new('--test-args', '--test-args', [CompletionResultType]::ParameterName, 'test-args')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -492,7 +492,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
             [CompletionResult]::new('--stage', '--stage', [CompletionResultType]::ParameterName, 'Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -534,7 +534,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
         'x;dist' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -576,7 +576,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
         'x;install' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -619,7 +619,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
             [CompletionResult]::new('--args', '--args', [CompletionResultType]::ParameterName, 'arguments for the tool')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -661,7 +661,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
         'x;setup' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -703,7 +703,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
         'x;suggest' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -747,7 +747,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
             [CompletionResult]::new('--sync', '--sync', [CompletionResultType]::ParameterName, 'Additional `Cargo.toml` to sync and vendor')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -790,7 +790,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
         'x;perf' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -841,7 +841,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
             [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip')
@@ -886,7 +886,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
             [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip')
@@ -931,7 +931,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
             [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip')
@@ -976,7 +976,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
             [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip')
@@ -1017,7 +1017,7 @@ Register-ArgumentCompleter -Native -CommandName 'x' -ScriptBlock {
         'x;perf;compare' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish
index 1fc5bb12cfb..e6326fcb0bb 100644
--- a/src/etc/completions/x.py.fish
+++ b/src/etc/completions/x.py.fish
@@ -26,7 +26,7 @@ end
 
 complete -c x.py -n "__fish_x.py_needs_command" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_needs_command" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_needs_command" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_x.py_needs_command" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x.py -n "__fish_x.py_needs_command" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_x.py_needs_command" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_x.py_needs_command" -l exclude -d 'build paths to exclude' -r -F
@@ -78,7 +78,7 @@ complete -c x.py -n "__fish_x.py_needs_command" -a "vendor" -d 'Vendor dependenc
 complete -c x.py -n "__fish_x.py_needs_command" -a "perf" -d 'Perform profiling and benchmarking of the compiler using `rustc-perf`'
 complete -c x.py -n "__fish_x.py_using_subcommand build" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand build" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand build" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_x.py_using_subcommand build" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand build" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand build" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand build" -l exclude -d 'build paths to exclude' -r -F
@@ -113,7 +113,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand build" -l skip-std-check-if-no
 complete -c x.py -n "__fish_x.py_using_subcommand build" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_x.py_using_subcommand check" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand check" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand check" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_x.py_using_subcommand check" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand check" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand check" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand check" -l exclude -d 'build paths to exclude' -r -F
@@ -153,7 +153,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand clippy" -s W -d 'clippy lints
 complete -c x.py -n "__fish_x.py_using_subcommand clippy" -s F -d 'clippy lints to forbid' -r
 complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l exclude -d 'build paths to exclude' -r -F
@@ -191,7 +191,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand clippy" -l skip-std-check-if-n
 complete -c x.py -n "__fish_x.py_using_subcommand clippy" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_x.py_using_subcommand fix" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand fix" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand fix" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_x.py_using_subcommand fix" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand fix" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand fix" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand fix" -l exclude -d 'build paths to exclude' -r -F
@@ -226,7 +226,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand fix" -l skip-std-check-if-no-d
 complete -c x.py -n "__fish_x.py_using_subcommand fix" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l exclude -d 'build paths to exclude' -r -F
@@ -263,7 +263,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand fmt" -l skip-std-check-if-no-d
 complete -c x.py -n "__fish_x.py_using_subcommand fmt" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_x.py_using_subcommand doc" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand doc" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand doc" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_x.py_using_subcommand doc" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand doc" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand doc" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand doc" -l exclude -d 'build paths to exclude' -r -F
@@ -306,7 +306,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand test" -l pass -d 'force {check
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l run -d 'whether to execute run-* tests' -r
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand test" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_x.py_using_subcommand test" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand test" -l exclude -d 'build paths to exclude' -r -F
@@ -350,7 +350,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand test" -s h -l help -d 'Print h
 complete -c x.py -n "__fish_x.py_using_subcommand miri" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r
 complete -c x.py -n "__fish_x.py_using_subcommand miri" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand miri" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand miri" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_x.py_using_subcommand miri" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand miri" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand miri" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand miri" -l exclude -d 'build paths to exclude' -r -F
@@ -389,7 +389,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand miri" -s h -l help -d 'Print h
 complete -c x.py -n "__fish_x.py_using_subcommand bench" -l test-args -r
 complete -c x.py -n "__fish_x.py_using_subcommand bench" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand bench" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand bench" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_x.py_using_subcommand bench" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand bench" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand bench" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand bench" -l exclude -d 'build paths to exclude' -r -F
@@ -425,7 +425,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand bench" -s h -l help -d 'Print
 complete -c x.py -n "__fish_x.py_using_subcommand clean" -l stage -d 'Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used' -r
 complete -c x.py -n "__fish_x.py_using_subcommand clean" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand clean" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand clean" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_x.py_using_subcommand clean" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand clean" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand clean" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand clean" -l exclude -d 'build paths to exclude' -r -F
@@ -460,7 +460,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand clean" -l skip-std-check-if-no
 complete -c x.py -n "__fish_x.py_using_subcommand clean" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_x.py_using_subcommand dist" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand dist" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand dist" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_x.py_using_subcommand dist" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand dist" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand dist" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand dist" -l exclude -d 'build paths to exclude' -r -F
@@ -495,7 +495,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand dist" -l skip-std-check-if-no-
 complete -c x.py -n "__fish_x.py_using_subcommand dist" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_x.py_using_subcommand install" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand install" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand install" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_x.py_using_subcommand install" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand install" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand install" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand install" -l exclude -d 'build paths to exclude' -r -F
@@ -531,7 +531,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand install" -s h -l help -d 'Prin
 complete -c x.py -n "__fish_x.py_using_subcommand run" -l args -d 'arguments for the tool' -r
 complete -c x.py -n "__fish_x.py_using_subcommand run" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand run" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand run" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_x.py_using_subcommand run" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand run" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand run" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand run" -l exclude -d 'build paths to exclude' -r -F
@@ -566,7 +566,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand run" -l skip-std-check-if-no-d
 complete -c x.py -n "__fish_x.py_using_subcommand run" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_x.py_using_subcommand setup" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand setup" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand setup" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_x.py_using_subcommand setup" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand setup" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand setup" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand setup" -l exclude -d 'build paths to exclude' -r -F
@@ -601,7 +601,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand setup" -l skip-std-check-if-no
 complete -c x.py -n "__fish_x.py_using_subcommand setup" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand suggest" -l exclude -d 'build paths to exclude' -r -F
@@ -638,7 +638,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand suggest" -s h -l help -d 'Prin
 complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l sync -d 'Additional `Cargo.toml` to sync and vendor' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l exclude -d 'build paths to exclude' -r -F
@@ -674,7 +674,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand vendor" -l skip-std-check-if-n
 complete -c x.py -n "__fish_x.py_using_subcommand vendor" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and not __fish_seen_subcommand_from eprintln samply cachegrind benchmark compare" -l exclude -d 'build paths to exclude' -r -F
@@ -718,7 +718,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',Opt\t'',Clippy\t''}"
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from eprintln" -l skip -d 'build paths to skip' -r -F
@@ -756,7 +756,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',Opt\t'',Clippy\t''}"
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from samply" -l skip -d 'build paths to skip' -r -F
@@ -794,7 +794,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',Opt\t'',Clippy\t''}"
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from cachegrind" -l skip -d 'build paths to skip' -r -F
@@ -832,7 +832,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l profiles -d 'Select the profiles that should be benchmarked' -r -f -a "{Check\t'',Debug\t'',Doc\t'',Opt\t'',Clippy\t''}"
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -l skip -d 'build paths to skip' -r -F
@@ -866,7 +866,7 @@ complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcomma
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from benchmark" -s h -l help -d 'Print help (see more with \'--help\')'
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l config -d 'TOML configuration file for build' -r -F
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l build-dir -d 'Build directory, overrides `build.build-dir` in `bootstrap.toml`' -r -f -a "(__fish_complete_directories)"
-complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l build -d 'build target of the stage0 compiler' -r -f
+complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l build -d 'host target of the stage0 compiler' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l host -d 'host targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l target -d 'target targets to build' -r -f
 complete -c x.py -n "__fish_x.py_using_subcommand perf; and __fish_seen_subcommand_from compare" -l exclude -d 'build paths to exclude' -r -F
diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1
index 5d224ac6df4..ee3373b9e75 100644
--- a/src/etc/completions/x.py.ps1
+++ b/src/etc/completions/x.py.ps1
@@ -23,7 +23,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
         'x.py' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -82,7 +82,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
         'x.py;build' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -124,7 +124,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
         'x.py;check' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -171,7 +171,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('-F', '-F ', [CompletionResultType]::ParameterName, 'clippy lints to forbid')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -216,7 +216,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
         'x.py;fix' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -258,7 +258,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
         'x.py;fmt' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -302,7 +302,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
         'x.py;doc' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -352,7 +352,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--run', '--run', [CompletionResultType]::ParameterName, 'whether to execute run-* tests')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -403,7 +403,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--test-args', '--test-args', [CompletionResultType]::ParameterName, 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -449,7 +449,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--test-args', '--test-args', [CompletionResultType]::ParameterName, 'test-args')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -492,7 +492,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--stage', '--stage', [CompletionResultType]::ParameterName, 'Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -534,7 +534,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
         'x.py;dist' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -576,7 +576,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
         'x.py;install' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -619,7 +619,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--args', '--args', [CompletionResultType]::ParameterName, 'arguments for the tool')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -661,7 +661,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
         'x.py;setup' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -703,7 +703,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
         'x.py;suggest' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -747,7 +747,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--sync', '--sync', [CompletionResultType]::ParameterName, 'Additional `Cargo.toml` to sync and vendor')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -790,7 +790,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
         'x.py;perf' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
@@ -841,7 +841,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip')
@@ -886,7 +886,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip')
@@ -931,7 +931,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip')
@@ -976,7 +976,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
             [CompletionResult]::new('--profiles', '--profiles', [CompletionResultType]::ParameterName, 'Select the profiles that should be benchmarked')
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--skip', '--skip', [CompletionResultType]::ParameterName, 'build paths to skip')
@@ -1017,7 +1017,7 @@ Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock {
         'x.py;perf;compare' {
             [CompletionResult]::new('--config', '--config', [CompletionResultType]::ParameterName, 'TOML configuration file for build')
             [CompletionResult]::new('--build-dir', '--build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `bootstrap.toml`')
-            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler')
+            [CompletionResult]::new('--build', '--build', [CompletionResultType]::ParameterName, 'host target of the stage0 compiler')
             [CompletionResult]::new('--host', '--host', [CompletionResultType]::ParameterName, 'host targets to build')
             [CompletionResult]::new('--target', '--target', [CompletionResultType]::ParameterName, 'target targets to build')
             [CompletionResult]::new('--exclude', '--exclude', [CompletionResultType]::ParameterName, 'build paths to exclude')
diff --git a/src/etc/completions/x.py.zsh b/src/etc/completions/x.py.zsh
index bc55280d038..6dc05708199 100644
--- a/src/etc/completions/x.py.zsh
+++ b/src/etc/completions/x.py.zsh
@@ -17,7 +17,7 @@ _x.py() {
     _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -69,7 +69,7 @@ _x.py() {
 _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -113,7 +113,7 @@ _arguments "${_arguments_options[@]}" : \
 _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -162,7 +162,7 @@ _arguments "${_arguments_options[@]}" : \
 '*-F+[clippy lints to forbid]:LINT:_default' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -209,7 +209,7 @@ _arguments "${_arguments_options[@]}" : \
 _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -253,7 +253,7 @@ _arguments "${_arguments_options[@]}" : \
 _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -299,7 +299,7 @@ _arguments "${_arguments_options[@]}" : \
 _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -351,7 +351,7 @@ _arguments "${_arguments_options[@]}" : \
 '--run=[whether to execute run-* tests]:auto | always | never:_default' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -404,7 +404,7 @@ _arguments "${_arguments_options[@]}" : \
 '*--test-args=[extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)]:ARGS:_default' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -452,7 +452,7 @@ _arguments "${_arguments_options[@]}" : \
 '*--test-args=[]:TEST_ARGS:_default' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -497,7 +497,7 @@ _arguments "${_arguments_options[@]}" : \
 '--stage=[Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used]:N:_default' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -541,7 +541,7 @@ _arguments "${_arguments_options[@]}" : \
 _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -585,7 +585,7 @@ _arguments "${_arguments_options[@]}" : \
 _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -630,7 +630,7 @@ _arguments "${_arguments_options[@]}" : \
 '*--args=[arguments for the tool]:ARGS:_default' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -674,7 +674,7 @@ _arguments "${_arguments_options[@]}" : \
 _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -719,7 +719,7 @@ _arguments "${_arguments_options[@]}" : \
 _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -765,7 +765,7 @@ _arguments "${_arguments_options[@]}" : \
 '*--sync=[Additional \`Cargo.toml\` to sync and vendor]:SYNC:_files' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -810,7 +810,7 @@ _arguments "${_arguments_options[@]}" : \
 _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -867,7 +867,7 @@ _arguments "${_arguments_options[@]}" : \
 '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc Opt Clippy)' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--skip=[build paths to skip]:PATH:_files' \
@@ -914,7 +914,7 @@ _arguments "${_arguments_options[@]}" : \
 '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc Opt Clippy)' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--skip=[build paths to skip]:PATH:_files' \
@@ -961,7 +961,7 @@ _arguments "${_arguments_options[@]}" : \
 '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc Opt Clippy)' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--skip=[build paths to skip]:PATH:_files' \
@@ -1008,7 +1008,7 @@ _arguments "${_arguments_options[@]}" : \
 '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc Opt Clippy)' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--skip=[build paths to skip]:PATH:_files' \
@@ -1052,7 +1052,7 @@ _arguments "${_arguments_options[@]}" : \
 _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
diff --git a/src/etc/completions/x.zsh b/src/etc/completions/x.zsh
index 2e3094fc379..869884bf1dc 100644
--- a/src/etc/completions/x.zsh
+++ b/src/etc/completions/x.zsh
@@ -17,7 +17,7 @@ _x() {
     _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -69,7 +69,7 @@ _x() {
 _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -113,7 +113,7 @@ _arguments "${_arguments_options[@]}" : \
 _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -162,7 +162,7 @@ _arguments "${_arguments_options[@]}" : \
 '*-F+[clippy lints to forbid]:LINT:_default' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -209,7 +209,7 @@ _arguments "${_arguments_options[@]}" : \
 _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -253,7 +253,7 @@ _arguments "${_arguments_options[@]}" : \
 _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -299,7 +299,7 @@ _arguments "${_arguments_options[@]}" : \
 _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -351,7 +351,7 @@ _arguments "${_arguments_options[@]}" : \
 '--run=[whether to execute run-* tests]:auto | always | never:_default' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -404,7 +404,7 @@ _arguments "${_arguments_options[@]}" : \
 '*--test-args=[extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)]:ARGS:_default' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -452,7 +452,7 @@ _arguments "${_arguments_options[@]}" : \
 '*--test-args=[]:TEST_ARGS:_default' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -497,7 +497,7 @@ _arguments "${_arguments_options[@]}" : \
 '--stage=[Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used]:N:_default' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -541,7 +541,7 @@ _arguments "${_arguments_options[@]}" : \
 _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -585,7 +585,7 @@ _arguments "${_arguments_options[@]}" : \
 _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -630,7 +630,7 @@ _arguments "${_arguments_options[@]}" : \
 '*--args=[arguments for the tool]:ARGS:_default' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -674,7 +674,7 @@ _arguments "${_arguments_options[@]}" : \
 _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -719,7 +719,7 @@ _arguments "${_arguments_options[@]}" : \
 _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -765,7 +765,7 @@ _arguments "${_arguments_options[@]}" : \
 '*--sync=[Additional \`Cargo.toml\` to sync and vendor]:SYNC:_files' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -810,7 +810,7 @@ _arguments "${_arguments_options[@]}" : \
 _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
@@ -867,7 +867,7 @@ _arguments "${_arguments_options[@]}" : \
 '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc Opt Clippy)' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--skip=[build paths to skip]:PATH:_files' \
@@ -914,7 +914,7 @@ _arguments "${_arguments_options[@]}" : \
 '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc Opt Clippy)' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--skip=[build paths to skip]:PATH:_files' \
@@ -961,7 +961,7 @@ _arguments "${_arguments_options[@]}" : \
 '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc Opt Clippy)' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--skip=[build paths to skip]:PATH:_files' \
@@ -1008,7 +1008,7 @@ _arguments "${_arguments_options[@]}" : \
 '*--profiles=[Select the profiles that should be benchmarked]:PROFILES:(Check Debug Doc Opt Clippy)' \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--skip=[build paths to skip]:PATH:_files' \
@@ -1052,7 +1052,7 @@ _arguments "${_arguments_options[@]}" : \
 _arguments "${_arguments_options[@]}" : \
 '--config=[TOML configuration file for build]:FILE:_files' \
 '--build-dir=[Build directory, overrides \`build.build-dir\` in \`bootstrap.toml\`]:DIR:_files -/' \
-'--build=[build target of the stage0 compiler]:BUILD:' \
+'--build=[host target of the stage0 compiler]:BUILD:' \
 '--host=[host targets to build]:HOST:' \
 '--target=[target targets to build]:TARGET:' \
 '*--exclude=[build paths to exclude]:PATH:_files' \
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/cfg.rs b/src/librustdoc/clean/cfg.rs
index a3762e4117d..b6ce8551060 100644
--- a/src/librustdoc/clean/cfg.rs
+++ b/src/librustdoc/clean/cfg.rs
@@ -169,33 +169,36 @@ impl Cfg {
         msg
     }
 
-    /// Renders the configuration for long display, as a long HTML description.
-    pub(crate) fn render_long_html(&self) -> String {
+    fn render_long_inner(&self, format: Format) -> String {
         let on = if self.omit_preposition() {
-            ""
+            " "
         } else if self.should_use_with_in_description() {
-            "with "
+            " with "
         } else {
-            "on "
+            " on "
         };
 
-        let mut msg = format!("Available {on}<strong>{}</strong>", Display(self, Format::LongHtml));
+        let mut msg = if matches!(format, Format::LongHtml) {
+            format!("Available{on}<strong>{}</strong>", Display(self, format))
+        } else {
+            format!("Available{on}{}", Display(self, format))
+        };
         if self.should_append_only_to_description() {
             msg.push_str(" only");
         }
+        msg
+    }
+
+    /// Renders the configuration for long display, as a long HTML description.
+    pub(crate) fn render_long_html(&self) -> String {
+        let mut msg = self.render_long_inner(Format::LongHtml);
         msg.push('.');
         msg
     }
 
     /// Renders the configuration for long display, as a long plain text description.
     pub(crate) fn render_long_plain(&self) -> String {
-        let on = if self.should_use_with_in_description() { "with" } else { "on" };
-
-        let mut msg = format!("Available {on} {}", Display(self, Format::LongPlain));
-        if self.should_append_only_to_description() {
-            msg.push_str(" only");
-        }
-        msg
+        self.render_long_inner(Format::LongPlain)
     }
 
     fn should_capitalize_first_letter(&self) -> bool {
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/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index bde1a2e5e66..58e05bd1e85 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -2638,7 +2638,7 @@ mod size_asserts {
     static_assert_size!(GenericParamDef, 40);
     static_assert_size!(Generics, 16);
     static_assert_size!(Item, 8);
-    static_assert_size!(ItemInner, 136);
+    static_assert_size!(ItemInner, 144);
     static_assert_size!(ItemKind, 48);
     static_assert_size!(PathSegment, 32);
     static_assert_size!(Type, 32);
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index 131a12ce228..0ceeea2b9b1 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -18,6 +18,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::{DefId, DefIdSet};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::Session;
+use rustc_session::features::StabilityExt;
 use rustc_span::def_id::LOCAL_CRATE;
 use rustdoc_json_types as types;
 // It's important to use the FxHashMap from rustdoc_json_types here, instead of
@@ -148,7 +149,7 @@ fn target(sess: &rustc_session::Session) -> types::Target {
             .copied()
             .filter(|(_, stability, _)| {
                 // Describe only target features which the user can toggle
-                stability.toggle_allowed().is_ok()
+                stability.is_toggle_permitted(sess).is_ok()
             })
             .map(|(name, stability, implied_features)| {
                 types::TargetFeature {
@@ -164,7 +165,7 @@ fn target(sess: &rustc_session::Session) -> types::Target {
                             // Imply only target features which the user can toggle
                             feature_stability
                                 .get(name)
-                                .map(|stability| stability.toggle_allowed().is_ok())
+                                .map(|stability| stability.is_toggle_permitted(sess).is_ok())
                                 .unwrap_or(false)
                         })
                         .map(String::from)
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 64a12460708cf146e16cc61f28aba5dc2463bbb
+Subproject fc1518ef02b77327d70d4026b95ea719dd9b8c5
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 3a98217f625..0cfe89ad378 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -5685,6 +5685,7 @@ Released 2018-09-13
 [`cmp_nan`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_nan
 [`cmp_null`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_null
 [`cmp_owned`]: https://rust-lang.github.io/rust-clippy/master/index.html#cmp_owned
+[`coerce_container_to_any`]: https://rust-lang.github.io/rust-clippy/master/index.html#coerce_container_to_any
 [`cognitive_complexity`]: https://rust-lang.github.io/rust-clippy/master/index.html#cognitive_complexity
 [`collapsible_else_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_else_if
 [`collapsible_if`]: https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if
@@ -5736,6 +5737,7 @@ Released 2018-09-13
 [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
 [`doc_nested_refdefs`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_nested_refdefs
 [`doc_overindented_list_items`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_overindented_list_items
+[`doc_suspicious_footnotes`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_suspicious_footnotes
 [`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
 [`double_ended_iterator_last`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_ended_iterator_last
 [`double_must_use`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_must_use
@@ -5862,6 +5864,7 @@ Released 2018-09-13
 [`ineffective_open_options`]: https://rust-lang.github.io/rust-clippy/master/index.html#ineffective_open_options
 [`inefficient_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inefficient_to_string
 [`infallible_destructuring_match`]: https://rust-lang.github.io/rust-clippy/master/index.html#infallible_destructuring_match
+[`infallible_try_from`]: https://rust-lang.github.io/rust-clippy/master/index.html#infallible_try_from
 [`infinite_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#infinite_iter
 [`infinite_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#infinite_loop
 [`inherent_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#inherent_to_string
@@ -5888,6 +5891,7 @@ Released 2018-09-13
 [`inverted_saturating_sub`]: https://rust-lang.github.io/rust-clippy/master/index.html#inverted_saturating_sub
 [`invisible_characters`]: https://rust-lang.github.io/rust-clippy/master/index.html#invisible_characters
 [`io_other_error`]: https://rust-lang.github.io/rust-clippy/master/index.html#io_other_error
+[`ip_constant`]: https://rust-lang.github.io/rust-clippy/master/index.html#ip_constant
 [`is_digit_ascii_radix`]: https://rust-lang.github.io/rust-clippy/master/index.html#is_digit_ascii_radix
 [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements
 [`items_after_test_module`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_test_module
@@ -6163,6 +6167,7 @@ Released 2018-09-13
 [`pathbuf_init_then_push`]: https://rust-lang.github.io/rust-clippy/master/index.html#pathbuf_init_then_push
 [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch
 [`permissions_set_readonly_false`]: https://rust-lang.github.io/rust-clippy/master/index.html#permissions_set_readonly_false
+[`pointer_format`]: https://rust-lang.github.io/rust-clippy/master/index.html#pointer_format
 [`pointers_in_nomem_asm_block`]: https://rust-lang.github.io/rust-clippy/master/index.html#pointers_in_nomem_asm_block
 [`positional_named_format_parameters`]: https://rust-lang.github.io/rust-clippy/master/index.html#positional_named_format_parameters
 [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index 320462a2c96..08592f2521f 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -73,8 +73,8 @@ pub fn generate_lint_files(
             (
                 "clippy_lints/src/lib.rs",
                 &mut update_text_region_fn(
-                    "// begin lints modules, do not remove this comment, it’s used in `update_lints`\n",
-                    "// end lints modules, do not remove this comment, it’s used in `update_lints`",
+                    "// begin lints modules, do not remove this comment, it's used in `update_lints`\n",
+                    "// end lints modules, do not remove this comment, it's used in `update_lints`",
                     |dst| {
                         for lint_mod in lints.iter().map(|l| &l.module).sorted().dedup() {
                             writeln!(dst, "mod {lint_mod};").unwrap();
diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
index 59a0c7c8868..b9ae9afe851 100644
--- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
+++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
@@ -204,7 +204,7 @@ impl ArbitrarySourceItemOrdering {
                 self.assoc_types_order
             ),
             Some(before_item.span),
-            format!("should be placed before `{}`", before_item.ident.as_str(),),
+            format!("should be placed before `{}`", before_item.ident.name),
         );
     }
 
@@ -216,7 +216,7 @@ impl ArbitrarySourceItemOrdering {
             ident.span,
             "incorrect ordering of items (must be alphabetically ordered)",
             Some(before_ident.span),
-            format!("should be placed before `{}`", before_ident.as_str(),),
+            format!("should be placed before `{}`", before_ident.name),
         );
     }
 
@@ -228,7 +228,7 @@ impl ArbitrarySourceItemOrdering {
         };
 
         let (before_span, note) = if let Some(ident) = before_item.kind.ident() {
-            (ident.span, format!("should be placed before `{}`", ident.as_str(),))
+            (ident.span, format!("should be placed before `{}`", ident.name))
         } else {
             (
                 before_item.span,
@@ -255,7 +255,7 @@ impl ArbitrarySourceItemOrdering {
                 self.assoc_types_order
             ),
             Some(before_item.span),
-            format!("should be placed before `{}`", before_item.ident.as_str(),),
+            format!("should be placed before `{}`", before_item.ident.name),
         );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs b/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs
index 0edb50be8c7..d67a194b020 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/deprecated_cfg_attr.rs
@@ -61,7 +61,7 @@ pub(super) fn check_clippy(cx: &EarlyContext<'_>, attr: &Attribute) {
 
 fn check_deprecated_cfg_recursively(cx: &EarlyContext<'_>, attr: &rustc_ast::MetaItem) {
     if let Some(ident) = attr.ident() {
-        if ["any", "all", "not"].contains(&ident.name.as_str()) {
+        if matches!(ident.name, sym::any | sym::all | sym::not) {
             let Some(list) = attr.meta_item_list() else { return };
             for item in list.iter().filter_map(|item| item.meta_item()) {
                 check_deprecated_cfg_recursively(cx, item);
diff --git a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs
index a851daaede7..c2406bcfb64 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs
@@ -1,9 +1,10 @@
 use super::DUPLICATED_ATTRIBUTES;
 use clippy_utils::diagnostics::span_lint_and_then;
+use itertools::Itertools;
 use rustc_ast::{Attribute, MetaItem};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_lint::EarlyContext;
-use rustc_span::{Span, sym};
+use rustc_span::{Span, Symbol, sym};
 use std::collections::hash_map::Entry;
 
 fn emit_if_duplicated(
@@ -29,7 +30,7 @@ fn check_duplicated_attr(
     cx: &EarlyContext<'_>,
     attr: &MetaItem,
     attr_paths: &mut FxHashMap<String, Span>,
-    parent: &mut Vec<String>,
+    parent: &mut Vec<Symbol>,
 ) {
     if attr.span.from_expansion() {
         return;
@@ -43,7 +44,7 @@ fn check_duplicated_attr(
         return;
     }
     if let Some(direct_parent) = parent.last()
-        && direct_parent == sym::cfg_trace.as_str()
+        && *direct_parent == sym::cfg_trace
         && [sym::all, sym::not, sym::any].contains(&name)
     {
         // FIXME: We don't correctly check `cfg`s for now, so if it's more complex than just a one
@@ -51,9 +52,14 @@ fn check_duplicated_attr(
         return;
     }
     if let Some(value) = attr.value_str() {
-        emit_if_duplicated(cx, attr, attr_paths, format!("{}:{name}={value}", parent.join(":")));
+        emit_if_duplicated(
+            cx,
+            attr,
+            attr_paths,
+            format!("{}:{name}={value}", parent.iter().join(":")),
+        );
     } else if let Some(sub_attrs) = attr.meta_item_list() {
-        parent.push(name.as_str().to_string());
+        parent.push(name);
         for sub_attr in sub_attrs {
             if let Some(meta) = sub_attr.meta_item() {
                 check_duplicated_attr(cx, meta, attr_paths, parent);
@@ -61,7 +67,7 @@ fn check_duplicated_attr(
         }
         parent.pop();
     } else {
-        emit_if_duplicated(cx, attr, attr_paths, format!("{}:{name}", parent.join(":")));
+        emit_if_duplicated(cx, attr, attr_paths, format!("{}:{name}", parent.iter().join(":")));
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index 7c6fd91ca67..bf43234ff50 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -1,10 +1,10 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
-use clippy_utils::eq_expr_value;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
+use clippy_utils::{eq_expr_value, sym};
 use rustc_ast::ast::LitKind;
 use rustc_attr_data_structures::RustcVersion;
 use rustc_errors::Applicability;
@@ -13,7 +13,7 @@ use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp};
 use rustc_lint::{LateContext, LateLintPass, Level};
 use rustc_session::impl_lint_pass;
 use rustc_span::def_id::LocalDefId;
-use rustc_span::{Span, SyntaxContext, sym};
+use rustc_span::{Span, Symbol, SyntaxContext};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -73,10 +73,10 @@ declare_clippy_lint! {
 }
 
 // For each pairs, both orders are considered.
-const METHODS_WITH_NEGATION: [(Option<RustcVersion>, &str, &str); 3] = [
-    (None, "is_some", "is_none"),
-    (None, "is_err", "is_ok"),
-    (Some(msrvs::IS_NONE_OR), "is_some_and", "is_none_or"),
+const METHODS_WITH_NEGATION: [(Option<RustcVersion>, Symbol, Symbol); 3] = [
+    (None, sym::is_some, sym::is_none),
+    (None, sym::is_err, sym::is_ok),
+    (Some(msrvs::IS_NONE_OR), sym::is_some_and, sym::is_none_or),
 ];
 
 pub struct NonminimalBool {
@@ -440,9 +440,7 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: Msrv, expr: &Expr<'_>) -> Optio
                 .iter()
                 .copied()
                 .flat_map(|(msrv, a, b)| vec![(msrv, a, b), (msrv, b, a)])
-                .find(|&(msrv, a, _)| {
-                    a == path.ident.name.as_str() && msrv.is_none_or(|msrv| curr_msrv.meets(cx, msrv))
-                })
+                .find(|&(msrv, a, _)| a == path.ident.name && msrv.is_none_or(|msrv| curr_msrv.meets(cx, msrv)))
                 .and_then(|(_, _, neg_method)| {
                     let negated_args = args
                         .iter()
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
index 0f066fae118..c1d6cec1b62 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
@@ -76,19 +76,20 @@ fn should_lint(cx: &LateContext<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: M
         return false;
     }
 
-    match (cast_from.is_integral(), cast_to.is_integral()) {
-        (true, true) => {
+    match (
+        utils::int_ty_to_nbits(cx.tcx, cast_from),
+        utils::int_ty_to_nbits(cx.tcx, cast_to),
+    ) {
+        (Some(from_nbits), Some(to_nbits)) => {
             let cast_signed_to_unsigned = cast_from.is_signed() && !cast_to.is_signed();
-            let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
-            let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
             !is_isize_or_usize(cast_from)
                 && !is_isize_or_usize(cast_to)
                 && from_nbits < to_nbits
                 && !cast_signed_to_unsigned
         },
 
-        (true, false) => {
-            let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
+        (Some(from_nbits), None) => {
+            // FIXME: handle `f16` and `f128`
             let to_nbits = if let ty::Float(FloatTy::F32) = cast_to.kind() {
                 32
             } else {
@@ -96,9 +97,7 @@ fn should_lint(cx: &LateContext<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>, msrv: M
             };
             !is_isize_or_usize(cast_from) && from_nbits < to_nbits
         },
-        (false, true) if matches!(cast_from.kind(), ty::Bool) && msrv.meets(cx, msrvs::FROM_BOOL) => true,
-        (_, _) => {
-            matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64))
-        },
+        (None, Some(_)) if cast_from.is_bool() && msrv.meets(cx, msrvs::FROM_BOOL) => true,
+        _ => matches!(cast_from.kind(), ty::Float(FloatTy::F32)) && matches!(cast_to.kind(), ty::Float(FloatTy::F64)),
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
index 4120e5c8cb7..a2ecb5fb44a 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
@@ -91,15 +91,14 @@ pub(super) fn check(
     cast_to: Ty<'_>,
     cast_to_span: Span,
 ) {
-    let msg = match (cast_from.kind(), cast_to.is_integral()) {
-        (ty::Int(_) | ty::Uint(_), true) => {
+    let msg = match (cast_from.kind(), utils::int_ty_to_nbits(cx.tcx, cast_to)) {
+        (ty::Int(_) | ty::Uint(_), Some(to_nbits)) => {
             let from_nbits = apply_reductions(
                 cx,
-                utils::int_ty_to_nbits(cast_from, cx.tcx),
+                utils::int_ty_to_nbits(cx.tcx, cast_from).unwrap(),
                 cast_expr,
                 cast_from.is_signed(),
             );
-            let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
 
             let (should_lint, suffix) = match (is_isize_or_usize(cast_from), is_isize_or_usize(cast_to)) {
                 (true, true) | (false, false) => (to_nbits < from_nbits, ""),
@@ -121,7 +120,7 @@ pub(super) fn check(
             format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}",)
         },
 
-        (ty::Adt(def, _), true) if def.is_enum() => {
+        (ty::Adt(def, _), Some(to_nbits)) if def.is_enum() => {
             let (from_nbits, variant) = if let ExprKind::Path(p) = &cast_expr.kind
                 && let Res::Def(DefKind::Ctor(..), id) = cx.qpath_res(p, cast_expr.hir_id)
             {
@@ -132,7 +131,6 @@ pub(super) fn check(
             } else {
                 (utils::enum_ty_to_nbits(*def, cx.tcx), None)
             };
-            let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
 
             let cast_from_ptr_size = def.repr().int.is_none_or(|ty| matches!(ty, IntegerType::Pointer(_),));
             let suffix = match (cast_from_ptr_size, is_isize_or_usize(cast_to)) {
@@ -157,11 +155,11 @@ pub(super) fn check(
             format!("casting `{cast_from}` to `{cast_to}` may truncate the value{suffix}")
         },
 
-        (ty::Float(_), true) => {
+        (ty::Float(_), Some(_)) => {
             format!("casting `{cast_from}` to `{cast_to}` may truncate the value")
         },
 
-        (ty::Float(FloatTy::F64), false) if matches!(cast_to.kind(), &ty::Float(FloatTy::F32)) => {
+        (ty::Float(FloatTy::F64), None) if matches!(cast_to.kind(), &ty::Float(FloatTy::F32)) => {
             "casting `f64` to `f32` may truncate the value".to_string()
         },
 
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs
index 504d0a267e4..e26c03ccda9 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_wrap.rs
@@ -17,9 +17,12 @@ enum EmitState {
 }
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
-    if !(cast_from.is_integral() && cast_to.is_integral()) {
+    let (Some(from_nbits), Some(to_nbits)) = (
+        utils::int_ty_to_nbits(cx.tcx, cast_from),
+        utils::int_ty_to_nbits(cx.tcx, cast_to),
+    ) else {
         return;
-    }
+    };
 
     // emit a lint if a cast is:
     // 1. unsigned to signed
@@ -35,9 +38,6 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca
         return;
     }
 
-    let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
-    let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
-
     let should_lint = match (cast_from.is_ptr_sized_integral(), cast_to.is_ptr_sized_integral()) {
         (true, true) => {
             // casts between two ptr sized integers are trivially always the same size
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs
index 1eb115ce6bd..712e38db499 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_precision_loss.rs
@@ -7,15 +7,14 @@ use rustc_middle::ty::{self, FloatTy, Ty};
 use super::{CAST_PRECISION_LOSS, utils};
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
-    if !cast_from.is_integral() || cast_to.is_integral() {
+    let Some(from_nbits) = utils::int_ty_to_nbits(cx.tcx, cast_from) else {
         return;
-    }
+    };
 
-    let from_nbits = utils::int_ty_to_nbits(cast_from, cx.tcx);
-    let to_nbits = if cast_to.kind() == &ty::Float(FloatTy::F32) {
-        32
-    } else {
-        64
+    // FIXME: handle `f16` and `f128`
+    let to_nbits = match cast_to.kind() {
+        ty::Float(f @ (FloatTy::F32 | FloatTy::F64)) => f.bit_width(),
+        _ => return,
     };
 
     if !(is_isize_or_usize(cast_from) || from_nbits >= to_nbits) {
@@ -29,9 +28,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_from: Ty<'_>, ca
     let from_nbits_str = if arch_dependent {
         "64".to_owned()
     } else if is_isize_or_usize(cast_from) {
+        // FIXME: handle 16 bits `usize` type
         "32 or 64".to_owned()
     } else {
-        utils::int_ty_to_nbits(cast_from, cx.tcx).to_string()
+        from_nbits.to_string()
     };
 
     span_lint(
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
index 01020f3eee2..e4dafde0f9d 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
@@ -61,7 +61,7 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
     };
     match parent.kind {
         ExprKind::MethodCall(name, self_arg, ..) if self_arg.hir_id == e.hir_id => {
-            if matches!(name.ident.as_str(), "read_unaligned" | "write_unaligned")
+            if matches!(name.ident.name, sym::read_unaligned | sym::write_unaligned)
                 && let Some(def_id) = cx.typeck_results().type_dependent_def_id(parent.hir_id)
                 && let Some(def_id) = cx.tcx.impl_of_method(def_id)
                 && cx.tcx.type_of(def_id).instantiate_identity().is_raw_ptr()
diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs
index ac1a355c8d9..105477093b5 100644
--- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast.rs
@@ -3,24 +3,22 @@ use clippy_utils::source::snippet_with_applicability;
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
-use rustc_middle::ty::{self, Ty, UintTy};
+use rustc_middle::ty::{self, Ty};
 
 use super::{FN_TO_NUMERIC_CAST, utils};
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
     // We only want to check casts to `ty::Uint` or `ty::Int`
-    match cast_to.kind() {
-        ty::Uint(_) | ty::Int(..) => { /* continue on */ },
-        _ => return,
-    }
+    let Some(to_nbits) = utils::int_ty_to_nbits(cx.tcx, cast_to) else {
+        return;
+    };
 
     match cast_from.kind() {
         ty::FnDef(..) | ty::FnPtr(..) => {
             let mut applicability = Applicability::MaybeIncorrect;
-            let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability);
-            let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
 
-            if (to_nbits >= cx.tcx.data_layout.pointer_size.bits()) && (*cast_to.kind() != ty::Uint(UintTy::Usize)) {
+            if to_nbits >= cx.tcx.data_layout.pointer_size.bits() && !cast_to.is_usize() {
+                let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability);
                 span_lint_and_sugg(
                     cx,
                     FN_TO_NUMERIC_CAST,
diff --git a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs
index 18e7798452e..700b7d0d426 100644
--- a/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/fn_to_numeric_cast_with_truncation.rs
@@ -9,16 +9,14 @@ use super::{FN_TO_NUMERIC_CAST_WITH_TRUNCATION, utils};
 
 pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_from: Ty<'_>, cast_to: Ty<'_>) {
     // We only want to check casts to `ty::Uint` or `ty::Int`
-    match cast_to.kind() {
-        ty::Uint(_) | ty::Int(..) => { /* continue on */ },
-        _ => return,
-    }
+    let Some(to_nbits) = utils::int_ty_to_nbits(cx.tcx, cast_to) else {
+        return;
+    };
     match cast_from.kind() {
         ty::FnDef(..) | ty::FnPtr(..) => {
             let mut applicability = Applicability::MaybeIncorrect;
             let from_snippet = snippet_with_applicability(cx, cast_expr.span, "x", &mut applicability);
 
-            let to_nbits = utils::int_ty_to_nbits(cast_to, cx.tcx);
             if to_nbits < cx.tcx.data_layout.pointer_size.bits() {
                 span_lint_and_sugg(
                     cx,
diff --git a/src/tools/clippy/clippy_lints/src/casts/utils.rs b/src/tools/clippy/clippy_lints/src/casts/utils.rs
index 5ccba92a0af..318a1646477 100644
--- a/src/tools/clippy/clippy_lints/src/casts/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/utils.rs
@@ -1,27 +1,14 @@
 use clippy_utils::ty::{EnumValue, read_explicit_enum_value};
 use rustc_middle::ty::{self, AdtDef, IntTy, Ty, TyCtxt, UintTy, VariantDiscr};
 
-/// Returns the size in bits of an integral type.
-/// Will return 0 if the type is not an int or uint variant
-pub(super) fn int_ty_to_nbits(typ: Ty<'_>, tcx: TyCtxt<'_>) -> u64 {
-    match typ.kind() {
-        ty::Int(i) => match i {
-            IntTy::Isize => tcx.data_layout.pointer_size.bits(),
-            IntTy::I8 => 8,
-            IntTy::I16 => 16,
-            IntTy::I32 => 32,
-            IntTy::I64 => 64,
-            IntTy::I128 => 128,
-        },
-        ty::Uint(i) => match i {
-            UintTy::Usize => tcx.data_layout.pointer_size.bits(),
-            UintTy::U8 => 8,
-            UintTy::U16 => 16,
-            UintTy::U32 => 32,
-            UintTy::U64 => 64,
-            UintTy::U128 => 128,
-        },
-        _ => 0,
+/// Returns the size in bits of an integral type, or `None` if `ty` is not an
+/// integral type.
+pub(super) fn int_ty_to_nbits(tcx: TyCtxt<'_>, ty: Ty<'_>) -> Option<u64> {
+    match ty.kind() {
+        ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Some(tcx.data_layout.pointer_size.bits()),
+        ty::Int(i) => i.bit_width(),
+        ty::Uint(i) => i.bit_width(),
+        _ => None,
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
index 8ada608049c..9b3822f9d8f 100644
--- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
@@ -2,11 +2,12 @@ use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal};
+use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{BinOpKind, Expr, ExprKind, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::impl_lint_pass;
+use rustc_span::Symbol;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -98,7 +99,7 @@ impl LateLintPass<'_> for CheckedConversions {
 struct Conversion<'a> {
     cvt: ConversionType,
     expr_to_cast: &'a Expr<'a>,
-    to_type: Option<&'a str>,
+    to_type: Option<Symbol>,
 }
 
 /// The kind of conversion that is checked
@@ -150,7 +151,7 @@ impl<'a> Conversion<'a> {
     }
 
     /// Try to construct a new conversion if the conversion type is valid
-    fn try_new(expr_to_cast: &'a Expr<'_>, from_type: &str, to_type: &'a str) -> Option<Conversion<'a>> {
+    fn try_new(expr_to_cast: &'a Expr<'_>, from_type: Symbol, to_type: Symbol) -> Option<Conversion<'a>> {
         ConversionType::try_new(from_type, to_type).map(|cvt| Conversion {
             cvt,
             expr_to_cast,
@@ -171,7 +172,7 @@ impl<'a> Conversion<'a> {
 impl ConversionType {
     /// Creates a conversion type if the type is allowed & conversion is valid
     #[must_use]
-    fn try_new(from: &str, to: &str) -> Option<Self> {
+    fn try_new(from: Symbol, to: Symbol) -> Option<Self> {
         if UINTS.contains(&from) {
             Some(Self::FromUnsigned)
         } else if SINTS.contains(&from) {
@@ -190,7 +191,7 @@ impl ConversionType {
 
 /// Check for `expr <= (to_type::MAX as from_type)`
 fn check_upper_bound<'tcx>(lt: &'tcx Expr<'tcx>, gt: &'tcx Expr<'tcx>) -> Option<Conversion<'tcx>> {
-    if let Some((from, to)) = get_types_from_cast(gt, INTS, "max_value", "MAX") {
+    if let Some((from, to)) = get_types_from_cast(gt, INTS, sym::max_value, sym::MAX) {
         Conversion::try_new(lt, from, to)
     } else {
         None
@@ -209,7 +210,7 @@ fn check_lower_bound_zero<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> O
 
 /// Check for `expr >= (to_type::MIN as from_type)`
 fn check_lower_bound_min<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> Option<Conversion<'a>> {
-    if let Some((from, to)) = get_types_from_cast(check, SINTS, "min_value", "MIN") {
+    if let Some((from, to)) = get_types_from_cast(check, SINTS, sym::min_value, sym::MIN) {
         Conversion::try_new(candidate, from, to)
     } else {
         None
@@ -217,15 +218,15 @@ fn check_lower_bound_min<'a>(candidate: &'a Expr<'_>, check: &'a Expr<'_>) -> Op
 }
 
 /// Tries to extract the from- and to-type from a cast expression
-fn get_types_from_cast<'a>(
-    expr: &'a Expr<'_>,
-    types: &'a [&str],
-    func: &'a str,
-    assoc_const: &'a str,
-) -> Option<(&'a str, &'a str)> {
+fn get_types_from_cast(
+    expr: &Expr<'_>,
+    types: &[Symbol],
+    func: Symbol,
+    assoc_const: Symbol,
+) -> Option<(Symbol, Symbol)> {
     // `to_type::max_value() as from_type`
     // or `to_type::MAX as from_type`
-    let call_from_cast: Option<(&Expr<'_>, &str)> = if let ExprKind::Cast(limit, from_type) = &expr.kind
+    let call_from_cast: Option<(&Expr<'_>, Symbol)> = if let ExprKind::Cast(limit, from_type) = &expr.kind
         // to_type::max_value(), from_type
         && let TyKind::Path(from_type_path) = &from_type.kind
         && let Some(from_sym) = int_ty_to_sym(from_type_path)
@@ -236,12 +237,12 @@ fn get_types_from_cast<'a>(
     };
 
     // `from_type::from(to_type::max_value())`
-    let limit_from: Option<(&Expr<'_>, &str)> = call_from_cast.or_else(|| {
+    let limit_from: Option<(&Expr<'_>, Symbol)> = call_from_cast.or_else(|| {
         if let ExprKind::Call(from_func, [limit]) = &expr.kind
             // `from_type::from, to_type::max_value()`
             // `from_type::from`
             && let ExprKind::Path(path) = &from_func.kind
-            && let Some(from_sym) = get_implementing_type(path, INTS, "from")
+            && let Some(from_sym) = get_implementing_type(path, INTS, sym::from)
         {
             Some((limit, from_sym))
         } else {
@@ -273,32 +274,41 @@ fn get_types_from_cast<'a>(
 }
 
 /// Gets the type which implements the called function
-fn get_implementing_type<'a>(path: &QPath<'_>, candidates: &'a [&str], function: &str) -> Option<&'a str> {
+fn get_implementing_type(path: &QPath<'_>, candidates: &[Symbol], function: Symbol) -> Option<Symbol> {
     if let QPath::TypeRelative(ty, path) = &path
-        && path.ident.name.as_str() == function
+        && path.ident.name == function
         && let TyKind::Path(QPath::Resolved(None, tp)) = &ty.kind
         && let [int] = tp.segments
     {
-        let name = int.ident.name.as_str();
-        candidates.iter().find(|c| &name == *c).copied()
+        candidates.iter().find(|c| int.ident.name == **c).copied()
     } else {
         None
     }
 }
 
 /// Gets the type as a string, if it is a supported integer
-fn int_ty_to_sym<'tcx>(path: &QPath<'_>) -> Option<&'tcx str> {
+fn int_ty_to_sym(path: &QPath<'_>) -> Option<Symbol> {
     if let QPath::Resolved(_, path) = *path
         && let [ty] = path.segments
     {
-        let name = ty.ident.name.as_str();
-        INTS.iter().find(|c| &name == *c).copied()
+        INTS.iter().find(|c| ty.ident.name == **c).copied()
     } else {
         None
     }
 }
 
 // Constants
-const UINTS: &[&str] = &["u8", "u16", "u32", "u64", "usize"];
-const SINTS: &[&str] = &["i8", "i16", "i32", "i64", "isize"];
-const INTS: &[&str] = &["u8", "u16", "u32", "u64", "usize", "i8", "i16", "i32", "i64", "isize"];
+const UINTS: &[Symbol] = &[sym::u8, sym::u16, sym::u32, sym::u64, sym::usize];
+const SINTS: &[Symbol] = &[sym::i8, sym::i16, sym::i32, sym::i64, sym::isize];
+const INTS: &[Symbol] = &[
+    sym::u8,
+    sym::u16,
+    sym::u32,
+    sym::u64,
+    sym::usize,
+    sym::i8,
+    sym::i16,
+    sym::i32,
+    sym::i64,
+    sym::isize,
+];
diff --git a/src/tools/clippy/clippy_lints/src/cloned_ref_to_slice_refs.rs b/src/tools/clippy/clippy_lints/src/cloned_ref_to_slice_refs.rs
index 6b239a1541b..e33a8e0fb74 100644
--- a/src/tools/clippy/clippy_lints/src/cloned_ref_to_slice_refs.rs
+++ b/src/tools/clippy/clippy_lints/src/cloned_ref_to_slice_refs.rs
@@ -17,7 +17,7 @@ declare_clippy_lint! {
     ///
     /// ### Why is this bad
     ///
-    /// A reference does not need to be owned in order to used as a slice.
+    /// A reference does not need to be owned in order to be used as a slice.
     ///
     /// ### Known problems
     ///
diff --git a/src/tools/clippy/clippy_lints/src/coerce_container_to_any.rs b/src/tools/clippy/clippy_lints/src/coerce_container_to_any.rs
new file mode 100644
index 00000000000..2b659253763
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/coerce_container_to_any.rs
@@ -0,0 +1,108 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet;
+use clippy_utils::sym;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::{self, ExistentialPredicate, Ty, TyCtxt};
+use rustc_session::declare_lint_pass;
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Protects against unintended coercion of references to container types to `&dyn Any` when the
+    /// container type dereferences to a `dyn Any` which could be directly referenced instead.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// The intention is usually to get a reference to the `dyn Any` the value dereferences to,
+    /// rather than coercing a reference to the container itself to `&dyn Any`.
+    ///
+    /// ### Example
+    ///
+    /// Because `Box<dyn Any>` itself implements `Any`, `&Box<dyn Any>`
+    /// can be coerced to an `&dyn Any` which refers to *the `Box` itself*, rather than the
+    /// inner `dyn Any`.
+    /// ```no_run
+    /// # use std::any::Any;
+    /// let x: Box<dyn Any> = Box::new(0u32);
+    /// let dyn_any_of_box: &dyn Any = &x;
+    ///
+    /// // Fails as we have a &dyn Any to the Box, not the u32
+    /// assert_eq!(dyn_any_of_box.downcast_ref::<u32>(), None);
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// # use std::any::Any;
+    /// let x: Box<dyn Any> = Box::new(0u32);
+    /// let dyn_any_of_u32: &dyn Any = &*x;
+    ///
+    /// // Succeeds since we have a &dyn Any to the inner u32!
+    /// assert_eq!(dyn_any_of_u32.downcast_ref::<u32>(), Some(&0u32));
+    /// ```
+    #[clippy::version = "1.88.0"]
+    pub COERCE_CONTAINER_TO_ANY,
+    nursery,
+    "coercing to `&dyn Any` when dereferencing could produce a `dyn Any` without coercion is usually not intended"
+}
+declare_lint_pass!(CoerceContainerToAny => [COERCE_CONTAINER_TO_ANY]);
+
+impl<'tcx> LateLintPass<'tcx> for CoerceContainerToAny {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
+        // If this expression has an effective type of `&dyn Any` ...
+        {
+            let coerced_ty = cx.typeck_results().expr_ty_adjusted(e);
+
+            let ty::Ref(_, coerced_ref_ty, _) = *coerced_ty.kind() else {
+                return;
+            };
+            if !is_dyn_any(cx.tcx, coerced_ref_ty) {
+                return;
+            }
+        }
+
+        let expr_ty = cx.typeck_results().expr_ty(e);
+        let ty::Ref(_, expr_ref_ty, _) = *expr_ty.kind() else {
+            return;
+        };
+        // ... but only due to coercion ...
+        if is_dyn_any(cx.tcx, expr_ref_ty) {
+            return;
+        }
+        // ... and it also *derefs* to `dyn Any` ...
+        let Some((depth, target)) = clippy_utils::ty::deref_chain(cx, expr_ref_ty).enumerate().last() else {
+            return;
+        };
+        if !is_dyn_any(cx.tcx, target) {
+            return;
+        }
+
+        // ... that's probably not intended.
+        let (span, deref_count) = match e.kind {
+            // If `e` was already an `&` expression, skip `*&` in the suggestion
+            ExprKind::AddrOf(_, _, referent) => (referent.span, depth),
+            _ => (e.span, depth + 1),
+        };
+        span_lint_and_sugg(
+            cx,
+            COERCE_CONTAINER_TO_ANY,
+            e.span,
+            format!("coercing `{expr_ty}` to `&dyn Any`"),
+            "consider dereferencing",
+            format!("&{}{}", str::repeat("*", deref_count), snippet(cx, span, "x")),
+            Applicability::MaybeIncorrect,
+        );
+    }
+}
+
+fn is_dyn_any(tcx: TyCtxt<'_>, ty: Ty<'_>) -> bool {
+    let ty::Dynamic(traits, ..) = ty.kind() else {
+        return false;
+    };
+    traits.iter().any(|binder| {
+        let ExistentialPredicate::Trait(t) = binder.skip_binder() else {
+            return false;
+        };
+        tcx.is_diagnostic_item(sym::Any, t.def_id)
+    })
+}
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index 2467fc95fd0..5ef726638a5 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -425,7 +425,9 @@ fn scan_block_for_eq<'tcx>(
             modifies_any_local(cx, stmt, &cond_locals)
                 || !eq_stmts(stmt, blocks, |b| b.stmts.get(i), &mut eq, &mut moved_locals)
         })
-        .map_or(block.stmts.len(), |(i, _)| i);
+        .map_or(block.stmts.len(), |(i, stmt)| {
+            adjust_by_closest_callsite(i, stmt, block.stmts[..i].iter().enumerate().rev())
+        });
 
     if local_needs_ordered_drop {
         return BlockEq {
@@ -467,7 +469,9 @@ fn scan_block_for_eq<'tcx>(
                     .is_none_or(|s| hash != hash_stmt(cx, s))
             })
         })
-        .map_or(block.stmts.len() - start_end_eq, |(i, _)| i);
+        .map_or(block.stmts.len() - start_end_eq, |(i, stmt)| {
+            adjust_by_closest_callsite(i, stmt, (0..i).rev().zip(block.stmts[(block.stmts.len() - i)..].iter()))
+        });
 
     let moved_locals_at_start = moved_locals.len();
     let mut i = end_search_start;
@@ -522,6 +526,49 @@ fn scan_block_for_eq<'tcx>(
     }
 }
 
+/// Adjusts the index for which the statements begin to differ to the closest macro callsite. This
+/// avoids giving suggestions that requires splitting a macro call in half, when only a part of the
+/// macro expansion is equal.
+///
+/// For example, for the following macro:
+/// ```rust,ignore
+/// macro_rules! foo {
+///    ($x:expr) => {
+///        let y = 42;
+///        $x;
+///    };
+/// }
+/// ```
+/// If the macro is called like this:
+/// ```rust,ignore
+/// if false {
+///    let z = 42;
+///    foo!(println!("Hello"));
+/// } else {
+///    let z = 42;
+///    foo!(println!("World"));
+/// }
+/// ```
+/// Although the expanded `let y = 42;` is equal, the macro call should not be included in the
+/// suggestion.
+fn adjust_by_closest_callsite<'tcx>(
+    i: usize,
+    stmt: &'tcx Stmt<'tcx>,
+    mut iter: impl Iterator<Item = (usize, &'tcx Stmt<'tcx>)>,
+) -> usize {
+    let Some((_, first)) = iter.next() else {
+        return 0;
+    };
+
+    // If it is already at the boundary of a macro call, then just return.
+    if first.span.source_callsite() != stmt.span.source_callsite() {
+        return i;
+    }
+
+    iter.find(|(_, stmt)| stmt.span.source_callsite() != first.span.source_callsite())
+        .map_or(0, |(i, _)| i + 1)
+}
+
 fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbol)], if_expr: &Expr<'_>) -> bool {
     get_enclosing_block(cx, if_expr.hir_id).is_some_and(|block| {
         let ignore_span = block.span.shrink_to_lo().to(if_expr.span);
diff --git a/src/tools/clippy/clippy_lints/src/create_dir.rs b/src/tools/clippy/clippy_lints/src/create_dir.rs
index b43906903a0..695b25aeb0b 100644
--- a/src/tools/clippy/clippy_lints/src/create_dir.rs
+++ b/src/tools/clippy/clippy_lints/src/create_dir.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::source::snippet_with_applicability;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
+use rustc_hir::{Expr, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
@@ -34,10 +33,12 @@ declare_lint_pass!(CreateDir => [CREATE_DIR]);
 
 impl LateLintPass<'_> for CreateDir {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
-        if let ExprKind::Call(func, [arg]) = expr.kind
+        if let ExprKind::Call(func, [_]) = expr.kind
             && let ExprKind::Path(ref path) = func.kind
             && let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id()
             && cx.tcx.is_diagnostic_item(sym::fs_create_dir, def_id)
+            && let QPath::Resolved(_, path) = path
+            && let Some(last) = path.segments.last()
         {
             span_lint_and_then(
                 cx,
@@ -45,15 +46,15 @@ impl LateLintPass<'_> for CreateDir {
                 expr.span,
                 "calling `std::fs::create_dir` where there may be a better way",
                 |diag| {
-                    let mut app = Applicability::MaybeIncorrect;
-                    diag.span_suggestion_verbose(
-                        expr.span,
+                    let mut suggestions = vec![(last.ident.span.shrink_to_hi(), "_all".to_owned())];
+                    if path.segments.len() == 1 {
+                        suggestions.push((path.span.shrink_to_lo(), "std::fs::".to_owned()));
+                    }
+
+                    diag.multipart_suggestion_verbose(
                         "consider calling `std::fs::create_dir_all` instead",
-                        format!(
-                            "create_dir_all({})",
-                            snippet_with_applicability(cx, arg.span, "..", &mut app)
-                        ),
-                        app,
+                        suggestions,
+                        Applicability::MaybeIncorrect,
                     );
                 },
             );
diff --git a/src/tools/clippy/clippy_lints/src/ctfe.rs b/src/tools/clippy/clippy_lints/src/ctfe.rs
deleted file mode 100644
index 7bae04a10f1..00000000000
--- a/src/tools/clippy/clippy_lints/src/ctfe.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, FnDecl};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::declare_lint_pass;
-use rustc_span::Span;
-
-declare_lint_pass! {
-    /// Ensures that Constant-time Function Evaluation is being done (specifically, MIR lint passes).
-    /// As Clippy deactivates codegen, this lint ensures that CTFE (used in hard errors) is still ran.
-    ClippyCtfe => []
-}
-
-impl<'tcx> LateLintPass<'tcx> for ClippyCtfe {
-    fn check_fn(
-        &mut self,
-        cx: &LateContext<'_>,
-        _: FnKind<'tcx>,
-        _: &'tcx FnDecl<'tcx>,
-        _: &'tcx Body<'tcx>,
-        _: Span,
-        defid: LocalDefId,
-    ) {
-        cx.tcx.ensure_ok().mir_drops_elaborated_and_const_checked(defid); // Lint
-    }
-}
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 5fcb851dfeb..1e3907d9ede 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -77,6 +77,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::cfg_not_test::CFG_NOT_TEST_INFO,
     crate::checked_conversions::CHECKED_CONVERSIONS_INFO,
     crate::cloned_ref_to_slice_refs::CLONED_REF_TO_SLICE_REFS_INFO,
+    crate::coerce_container_to_any::COERCE_CONTAINER_TO_ANY_INFO,
     crate::cognitive_complexity::COGNITIVE_COMPLEXITY_INFO,
     crate::collapsible_if::COLLAPSIBLE_ELSE_IF_INFO,
     crate::collapsible_if::COLLAPSIBLE_IF_INFO,
@@ -119,6 +120,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::doc::DOC_MARKDOWN_INFO,
     crate::doc::DOC_NESTED_REFDEFS_INFO,
     crate::doc::DOC_OVERINDENTED_LIST_ITEMS_INFO,
+    crate::doc::DOC_SUSPICIOUS_FOOTNOTES_INFO,
     crate::doc::EMPTY_DOCS_INFO,
     crate::doc::MISSING_ERRORS_DOC_INFO,
     crate::doc::MISSING_PANICS_DOC_INFO,
@@ -166,6 +168,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::floating_point_arithmetic::SUBOPTIMAL_FLOPS_INFO,
     crate::format::USELESS_FORMAT_INFO,
     crate::format_args::FORMAT_IN_FORMAT_ARGS_INFO,
+    crate::format_args::POINTER_FORMAT_INFO,
     crate::format_args::TO_STRING_IN_FORMAT_ARGS_INFO,
     crate::format_args::UNINLINED_FORMAT_ARGS_INFO,
     crate::format_args::UNNECESSARY_DEBUG_FORMATTING_INFO,
@@ -211,6 +214,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::indexing_slicing::INDEXING_SLICING_INFO,
     crate::indexing_slicing::OUT_OF_BOUNDS_INDEXING_INFO,
     crate::ineffective_open_options::INEFFECTIVE_OPEN_OPTIONS_INFO,
+    crate::infallible_try_from::INFALLIBLE_TRY_FROM_INFO,
     crate::infinite_iter::INFINITE_ITER_INFO,
     crate::infinite_iter::MAYBE_INFINITE_ITER_INFO,
     crate::inherent_impl::MULTIPLE_INHERENT_IMPL_INFO,
@@ -379,6 +383,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::methods::INSPECT_FOR_EACH_INFO,
     crate::methods::INTO_ITER_ON_REF_INFO,
     crate::methods::IO_OTHER_ERROR_INFO,
+    crate::methods::IP_CONSTANT_INFO,
     crate::methods::IS_DIGIT_ASCII_RADIX_INFO,
     crate::methods::ITERATOR_STEP_BY_ZERO_INFO,
     crate::methods::ITER_CLONED_COLLECT_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index 886c325b355..a48e4d2fbd5 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -1,10 +1,9 @@
 use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{has_drop, is_copy};
-use clippy_utils::{contains_name, get_parent_expr, in_automatically_derived, is_from_proc_macro};
+use clippy_utils::{contains_name, get_parent_expr, in_automatically_derived, is_expr_default, is_from_proc_macro};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
-use rustc_hir::def::Res;
 use rustc_hir::{Block, Expr, ExprKind, PatKind, QPath, Stmt, StmtKind, StructTailExpr};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
@@ -129,7 +128,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
                 // only take bindings to identifiers
                 && let PatKind::Binding(_, binding_id, ident, _) = local.pat.kind
                 // only when assigning `... = Default::default()`
-                && is_expr_default(expr, cx)
+                && is_expr_default(cx, expr)
                 && let binding_type = cx.typeck_results().node_type(binding_id)
                 && let ty::Adt(adt, args) = *binding_type.kind()
                 && adt.is_struct()
@@ -251,19 +250,6 @@ impl<'tcx> LateLintPass<'tcx> for Default {
     }
 }
 
-/// Checks if the given expression is the `default` method belonging to the `Default` trait.
-fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool {
-    if let ExprKind::Call(fn_expr, []) = &expr.kind
-        && let ExprKind::Path(qpath) = &fn_expr.kind
-        && let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id)
-    {
-        // right hand side of assignment is `Default::default`
-        cx.tcx.is_diagnostic_item(sym::default_fn, def_id)
-    } else {
-        false
-    }
-}
-
 /// Returns the reassigned field and the assigning expression (right-hand side of assign).
 fn field_reassigned_by_stmt<'tcx>(this: &Stmt<'tcx>, binding_name: Symbol) -> Option<(Ident, &'tcx Expr<'tcx>)> {
     if let StmtKind::Semi(later_expr) = this.kind
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_names.rs b/src/tools/clippy/clippy_lints/src/disallowed_names.rs
index f55b0cf1c50..566aa12b08f 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_names.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_names.rs
@@ -1,6 +1,6 @@
 use clippy_config::Conf;
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::is_in_test;
+use clippy_utils::{is_from_proc_macro, is_in_test};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::{Pat, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -43,8 +43,10 @@ impl_lint_pass!(DisallowedNames => [DISALLOWED_NAMES]);
 impl<'tcx> LateLintPass<'tcx> for DisallowedNames {
     fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
         if let PatKind::Binding(.., ident, _) = pat.kind
+            && !ident.span.from_expansion()
             && self.disallow.contains(&ident.name)
             && !is_in_test(cx.tcx, pat.hir_id)
+            && !is_from_proc_macro(cx, &ident)
         {
             span_lint(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_types.rs b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
index 821bb25d2ce..7875cdd77e8 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_types.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
@@ -105,10 +105,10 @@ impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]);
 
 impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
-        if let ItemKind::Use(path, UseKind::Single(_)) = &item.kind {
-            if let Some(res) = path.res.type_ns {
-                self.check_res_emit(cx, &res, item.span);
-            }
+        if let ItemKind::Use(path, UseKind::Single(_)) = &item.kind
+            && let Some(res) = path.res.type_ns
+        {
+            self.check_res_emit(cx, &res, item.span);
         }
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs b/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs
new file mode 100644
index 00000000000..289b6b915d4
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/doc/doc_suspicious_footnotes.rs
@@ -0,0 +1,113 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_ast::token::CommentKind;
+use rustc_errors::Applicability;
+use rustc_hir::{AttrStyle, Attribute};
+use rustc_lint::{LateContext, LintContext};
+use rustc_resolve::rustdoc::DocFragmentKind;
+
+use std::ops::Range;
+
+use super::{DOC_SUSPICIOUS_FOOTNOTES, Fragments};
+
+pub fn check(cx: &LateContext<'_>, doc: &str, range: Range<usize>, fragments: &Fragments<'_>, attrs: &[Attribute]) {
+    for i in doc[range.clone()]
+        .bytes()
+        .enumerate()
+        .filter_map(|(i, c)| if c == b'[' { Some(i) } else { None })
+    {
+        let start = i + range.start;
+        if doc.as_bytes().get(start + 1) == Some(&b'^')
+            && let Some(end) = all_numbers_upto_brace(doc, start + 2)
+            && doc.as_bytes().get(end) != Some(&b':')
+            && doc.as_bytes().get(start - 1) != Some(&b'\\')
+            && let Some(this_fragment) = {
+                // the `doc` string contains all fragments concatenated together
+                // figure out which one this suspicious footnote comes from
+                let mut starting_position = 0;
+                let mut found_fragment = fragments.fragments.last();
+                for fragment in fragments.fragments {
+                    if start >= starting_position && start < starting_position + fragment.doc.as_str().len() {
+                        found_fragment = Some(fragment);
+                        break;
+                    }
+                    starting_position += fragment.doc.as_str().len();
+                }
+                found_fragment
+            }
+        {
+            let span = fragments.span(cx, start..end).unwrap_or(this_fragment.span);
+            span_lint_and_then(
+                cx,
+                DOC_SUSPICIOUS_FOOTNOTES,
+                span,
+                "looks like a footnote ref, but has no matching footnote",
+                |diag| {
+                    if this_fragment.kind == DocFragmentKind::SugaredDoc {
+                        let (doc_attr, (_, doc_attr_comment_kind)) = attrs
+                            .iter()
+                            .filter(|attr| attr.span().overlaps(this_fragment.span))
+                            .rev()
+                            .find_map(|attr| Some((attr, attr.doc_str_and_comment_kind()?)))
+                            .unwrap();
+                        let (to_add, terminator) = match (doc_attr_comment_kind, doc_attr.style()) {
+                            (CommentKind::Line, AttrStyle::Outer) => ("\n///\n/// ", ""),
+                            (CommentKind::Line, AttrStyle::Inner) => ("\n//!\n//! ", ""),
+                            (CommentKind::Block, AttrStyle::Outer) => ("\n/** ", " */"),
+                            (CommentKind::Block, AttrStyle::Inner) => ("\n/*! ", " */"),
+                        };
+                        diag.span_suggestion_verbose(
+                            doc_attr.span().shrink_to_hi(),
+                            "add footnote definition",
+                            format!(
+                                "{to_add}{label}: <!-- description -->{terminator}",
+                                label = &doc[start..end]
+                            ),
+                            Applicability::HasPlaceholders,
+                        );
+                    } else {
+                        let is_file_include = cx
+                            .sess()
+                            .source_map()
+                            .span_to_snippet(this_fragment.span)
+                            .as_ref()
+                            .map(|vdoc| vdoc.trim())
+                            == Ok(doc);
+                        if is_file_include {
+                            // if this is a file include, then there's no quote marks
+                            diag.span_suggestion_verbose(
+                                this_fragment.span.shrink_to_hi(),
+                                "add footnote definition",
+                                format!("\n\n{label}: <!-- description -->", label = &doc[start..end],),
+                                Applicability::HasPlaceholders,
+                            );
+                        } else {
+                            // otherwise, we wrap in a string
+                            diag.span_suggestion_verbose(
+                                this_fragment.span,
+                                "add footnote definition",
+                                format!(
+                                    "r#\"{doc}\n\n{label}: <!-- description -->\"#",
+                                    doc = this_fragment.doc,
+                                    label = &doc[start..end],
+                                ),
+                                Applicability::HasPlaceholders,
+                            );
+                        }
+                    }
+                },
+            );
+        }
+    }
+}
+
+fn all_numbers_upto_brace(text: &str, i: usize) -> Option<usize> {
+    for (j, c) in text.as_bytes()[i..].iter().copied().enumerate().take(64) {
+        if c == b']' && j != 0 {
+            return Some(i + j + 1);
+        }
+        if !c.is_ascii_digit() || j >= 64 {
+            break;
+        }
+    }
+    None
+}
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index c46dd09d60c..e0fc2fd9347 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -25,6 +25,7 @@ use std::ops::Range;
 use url::Url;
 
 mod doc_comment_double_space_linebreaks;
+mod doc_suspicious_footnotes;
 mod include_in_doc_without_cfg;
 mod lazy_continuation;
 mod link_with_quotes;
@@ -607,6 +608,37 @@ declare_clippy_lint! {
     "double-space used for doc comment linebreak instead of `\\`"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Detects syntax that looks like a footnote reference.
+    ///
+    /// Rustdoc footnotes are compatible with GitHub-Flavored Markdown (GFM).
+    /// GFM does not parse a footnote reference unless its definition also
+    /// exists. This lint checks for footnote references with missing
+    /// definitions, unless it thinks you're writing a regex.
+    ///
+    /// ### Why is this bad?
+    /// This probably means that a footnote was meant to exist,
+    /// but was not written.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// /// This is not a footnote[^1], because no definition exists.
+    /// fn my_fn() {}
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// /// This is a footnote[^1].
+    /// ///
+    /// /// [^1]: defined here
+    /// fn my_fn() {}
+    /// ```
+    #[clippy::version = "1.88.0"]
+    pub DOC_SUSPICIOUS_FOOTNOTES,
+    suspicious,
+    "looks like a link or footnote ref, but with no definition"
+}
+
 pub struct Documentation {
     valid_idents: FxHashSet<String>,
     check_private_items: bool,
@@ -638,7 +670,8 @@ impl_lint_pass!(Documentation => [
     DOC_OVERINDENTED_LIST_ITEMS,
     TOO_LONG_FIRST_DOC_PARAGRAPH,
     DOC_INCLUDE_WITHOUT_CFG,
-    DOC_COMMENT_DOUBLE_SPACE_LINEBREAKS
+    DOC_COMMENT_DOUBLE_SPACE_LINEBREAKS,
+    DOC_SUSPICIOUS_FOOTNOTES,
 ]);
 
 impl EarlyLintPass for Documentation {
@@ -825,6 +858,7 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
             doc: &doc,
             fragments: &fragments,
         },
+        attrs,
     ))
 }
 
@@ -905,6 +939,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
     events: Events,
     doc: &str,
     fragments: Fragments<'_>,
+    attrs: &[Attribute],
 ) -> DocHeaders {
     // true if a safety header was found
     let mut headers = DocHeaders::default();
@@ -1148,7 +1183,8 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
                         // Don't check the text associated with external URLs
                         continue;
                     }
-                    text_to_check.push((text, range, code_level));
+                    text_to_check.push((text, range.clone(), code_level));
+                    doc_suspicious_footnotes::check(cx, doc, range, &fragments, attrs);
                 }
             }
             FootnoteReference(_) => {}
diff --git a/src/tools/clippy/clippy_lints/src/endian_bytes.rs b/src/tools/clippy/clippy_lints/src/endian_bytes.rs
index a7670ffce88..75db923b1c3 100644
--- a/src/tools/clippy/clippy_lints/src/endian_bytes.rs
+++ b/src/tools/clippy/clippy_lints/src/endian_bytes.rs
@@ -1,6 +1,6 @@
 use crate::Lint;
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_lint_allowed;
+use clippy_utils::{is_lint_allowed, sym};
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty::Ty;
@@ -65,9 +65,9 @@ declare_clippy_lint! {
 
 declare_lint_pass!(EndianBytes => [HOST_ENDIAN_BYTES, LITTLE_ENDIAN_BYTES, BIG_ENDIAN_BYTES]);
 
-const HOST_NAMES: [&str; 2] = ["from_ne_bytes", "to_ne_bytes"];
-const LITTLE_NAMES: [&str; 2] = ["from_le_bytes", "to_le_bytes"];
-const BIG_NAMES: [&str; 2] = ["from_be_bytes", "to_be_bytes"];
+const HOST_NAMES: [Symbol; 2] = [sym::from_ne_bytes, sym::to_ne_bytes];
+const LITTLE_NAMES: [Symbol; 2] = [sym::from_le_bytes, sym::to_le_bytes];
+const BIG_NAMES: [Symbol; 2] = [sym::from_be_bytes, sym::to_be_bytes];
 
 #[derive(Clone, Debug)]
 enum LintKind {
@@ -95,7 +95,7 @@ impl LintKind {
         }
     }
 
-    fn as_name(&self, prefix: Prefix) -> &str {
+    fn as_name(&self, prefix: Prefix) -> Symbol {
         let index = usize::from(prefix == Prefix::To);
 
         match self {
@@ -133,7 +133,7 @@ fn maybe_lint_endian_bytes(cx: &LateContext<'_>, expr: &Expr<'_>, prefix: Prefix
     let le = LintKind::Little.as_name(prefix);
     let be = LintKind::Big.as_name(prefix);
 
-    let (lint, other_lints) = match name.as_str() {
+    let (lint, other_lints) = match name {
         name if name == ne => ((&LintKind::Host), [(&LintKind::Little), (&LintKind::Big)]),
         name if name == le => ((&LintKind::Little), [(&LintKind::Host), (&LintKind::Big)]),
         name if name == be => ((&LintKind::Big), [(&LintKind::Host), (&LintKind::Little)]),
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index a26e736c7ae..0c39aae9ca9 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -1,6 +1,8 @@
+use std::collections::hash_map::Entry;
+
 use arrayvec::ArrayVec;
 use clippy_config::Conf;
-use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
+use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::macros::{
     FormatArgsStorage, FormatParamUsage, MacroCall, find_format_arg_expr, format_arg_removal_span,
     format_placeholder_format_span, is_assert_macro, is_format_macro, is_panic, matching_root_macro_call,
@@ -9,7 +11,7 @@ use clippy_utils::macros::{
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::source::{SpanRangeExt, snippet};
 use clippy_utils::ty::{implements_trait, is_type_lang_item};
-use clippy_utils::{is_diag_trait_item, is_from_proc_macro, is_in_test};
+use clippy_utils::{is_diag_trait_item, is_from_proc_macro, is_in_test, trait_ref_of_method};
 use itertools::Itertools;
 use rustc_ast::{
     FormatArgPosition, FormatArgPositionKind, FormatArgsPiece, FormatArgumentKind, FormatCount, FormatOptions,
@@ -22,10 +24,12 @@ use rustc_errors::SuggestionStyle::{CompletelyHidden, ShowCode};
 use rustc_hir::{Expr, ExprKind, LangItem};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment};
-use rustc_middle::ty::{List, Ty, TyCtxt};
+use rustc_middle::ty::{self, GenericArg, List, TraitRef, Ty, TyCtxt, Upcast};
 use rustc_session::impl_lint_pass;
 use rustc_span::edition::Edition::Edition2021;
 use rustc_span::{Span, Symbol, sym};
+use rustc_trait_selection::infer::TyCtxtInferExt;
+use rustc_trait_selection::traits::{Obligation, ObligationCause, Selection, SelectionContext};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -194,12 +198,41 @@ declare_clippy_lint! {
     "use of a format specifier that has no effect"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Detects [pointer format] as well as `Debug` formatting of raw pointers or function pointers
+    /// or any types that have a derived `Debug` impl that recursively contains them.
+    ///
+    /// ### Why restrict this?
+    /// The addresses are only useful in very specific contexts, and certain projects may want to keep addresses of
+    /// certain data structures or functions from prying hacker eyes as an additional line of security.
+    ///
+    /// ### Known problems
+    /// The lint currently only looks through derived `Debug` implementations. Checking whether a manual
+    /// implementation prints an address is left as an exercise to the next lint implementer.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let foo = &0_u32;
+    /// fn bar() {}
+    /// println!("{:p}", foo);
+    /// let _ = format!("{:?}", &(bar as fn()));
+    /// ```
+    ///
+    /// [pointer format]: https://doc.rust-lang.org/std/fmt/index.html#formatting-traits
+    #[clippy::version = "1.88.0"]
+    pub POINTER_FORMAT,
+    restriction,
+    "formatting a pointer"
+}
+
 impl_lint_pass!(FormatArgs<'_> => [
     FORMAT_IN_FORMAT_ARGS,
     TO_STRING_IN_FORMAT_ARGS,
     UNINLINED_FORMAT_ARGS,
     UNNECESSARY_DEBUG_FORMATTING,
     UNUSED_FORMAT_SPECS,
+    POINTER_FORMAT,
 ]);
 
 #[allow(clippy::struct_field_names)]
@@ -208,6 +241,8 @@ pub struct FormatArgs<'tcx> {
     msrv: Msrv,
     ignore_mixed: bool,
     ty_msrv_map: FxHashMap<Ty<'tcx>, Option<RustcVersion>>,
+    has_derived_debug: FxHashMap<Ty<'tcx>, bool>,
+    has_pointer_format: FxHashMap<Ty<'tcx>, bool>,
 }
 
 impl<'tcx> FormatArgs<'tcx> {
@@ -218,6 +253,8 @@ impl<'tcx> FormatArgs<'tcx> {
             msrv: conf.msrv,
             ignore_mixed: conf.allow_mixed_uninlined_format_args,
             ty_msrv_map,
+            has_derived_debug: FxHashMap::default(),
+            has_pointer_format: FxHashMap::default(),
         }
     }
 }
@@ -228,7 +265,7 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs<'tcx> {
             && is_format_macro(cx, macro_call.def_id)
             && let Some(format_args) = self.format_args.get(cx, expr, macro_call.expn)
         {
-            let linter = FormatArgsExpr {
+            let mut linter = FormatArgsExpr {
                 cx,
                 expr,
                 macro_call: &macro_call,
@@ -236,6 +273,8 @@ impl<'tcx> LateLintPass<'tcx> for FormatArgs<'tcx> {
                 ignore_mixed: self.ignore_mixed,
                 msrv: &self.msrv,
                 ty_msrv_map: &self.ty_msrv_map,
+                has_derived_debug: &mut self.has_derived_debug,
+                has_pointer_format: &mut self.has_pointer_format,
             };
 
             linter.check_templates();
@@ -255,10 +294,12 @@ struct FormatArgsExpr<'a, 'tcx> {
     ignore_mixed: bool,
     msrv: &'a Msrv,
     ty_msrv_map: &'a FxHashMap<Ty<'tcx>, Option<RustcVersion>>,
+    has_derived_debug: &'a mut FxHashMap<Ty<'tcx>, bool>,
+    has_pointer_format: &'a mut FxHashMap<Ty<'tcx>, bool>,
 }
 
 impl<'tcx> FormatArgsExpr<'_, 'tcx> {
-    fn check_templates(&self) {
+    fn check_templates(&mut self) {
         for piece in &self.format_args.template {
             if let FormatArgsPiece::Placeholder(placeholder) = piece
                 && let Ok(index) = placeholder.argument.index
@@ -279,6 +320,17 @@ impl<'tcx> FormatArgsExpr<'_, 'tcx> {
                 if placeholder.format_trait == FormatTrait::Debug {
                     let name = self.cx.tcx.item_name(self.macro_call.def_id);
                     self.check_unnecessary_debug_formatting(name, arg_expr);
+                    if let Some(span) = placeholder.span
+                        && self.has_pointer_debug(self.cx.typeck_results().expr_ty(arg_expr), 0)
+                    {
+                        span_lint(self.cx, POINTER_FORMAT, span, "pointer formatting detected");
+                    }
+                }
+
+                if placeholder.format_trait == FormatTrait::Pointer
+                    && let Some(span) = placeholder.span
+                {
+                    span_lint(self.cx, POINTER_FORMAT, span, "pointer formatting detected");
                 }
             }
         }
@@ -490,6 +542,16 @@ impl<'tcx> FormatArgsExpr<'_, 'tcx> {
             && let ty = cx.typeck_results().expr_ty(value)
             && self.can_display_format(ty)
         {
+            // If the parent function is a method of `Debug`, we don't want to lint
+            // because it is likely that the user wants to use `Debug` formatting.
+            let parent_fn = cx.tcx.hir_get_parent_item(value.hir_id);
+            if let Some(trait_ref) = trait_ref_of_method(cx, parent_fn)
+                && let Some(trait_def_id) = trait_ref.trait_def_id()
+                && cx.tcx.is_diagnostic_item(sym::Debug, trait_def_id)
+            {
+                return;
+            }
+
             let snippet = snippet(cx.sess(), value.span, "..");
             span_lint_and_then(
                 cx,
@@ -559,6 +621,58 @@ impl<'tcx> FormatArgsExpr<'_, 'tcx> {
 
         false
     }
+
+    fn has_pointer_debug(&mut self, ty: Ty<'tcx>, depth: usize) -> bool {
+        let cx = self.cx;
+        let tcx = cx.tcx;
+        if !tcx.recursion_limit().value_within_limit(depth) {
+            return false;
+        }
+        let depth = depth + 1;
+        let typing_env = cx.typing_env();
+        let ty = tcx.normalize_erasing_regions(typing_env, ty);
+        match ty.kind() {
+            ty::RawPtr(..) | ty::FnPtr(..) | ty::FnDef(..) => true,
+            ty::Ref(_, t, _) | ty::Slice(t) | ty::Array(t, _) => self.has_pointer_debug(*t, depth),
+            ty::Tuple(ts) => ts.iter().any(|t| self.has_pointer_debug(t, depth)),
+            ty::Adt(adt, args) => {
+                match self.has_pointer_format.entry(ty) {
+                    Entry::Occupied(o) => return *o.get(),
+                    Entry::Vacant(v) => v.insert(false),
+                };
+                let derived_debug = if let Some(&known) = self.has_derived_debug.get(&ty) {
+                    known
+                } else {
+                    let Some(trait_id) = tcx.get_diagnostic_item(sym::Debug) else {
+                        return false;
+                    };
+                    let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);
+                    let trait_ref = TraitRef::new(tcx, trait_id, [GenericArg::from(ty)]);
+                    let obligation = Obligation {
+                        cause: ObligationCause::dummy(),
+                        param_env,
+                        recursion_depth: 0,
+                        predicate: trait_ref.upcast(tcx),
+                    };
+                    let selection = SelectionContext::new(&infcx).select(&obligation);
+                    let derived = if let Ok(Some(Selection::UserDefined(data))) = selection {
+                        tcx.has_attr(data.impl_def_id, sym::automatically_derived)
+                    } else {
+                        false
+                    };
+                    self.has_derived_debug.insert(ty, derived);
+                    derived
+                };
+                let pointer_debug = derived_debug
+                    && adt.all_fields().any(|f| {
+                        self.has_pointer_debug(tcx.normalize_erasing_regions(typing_env, f.ty(tcx, args)), depth)
+                    });
+                self.has_pointer_format.insert(ty, pointer_debug);
+                pointer_debug
+            },
+            _ => false,
+        }
+    }
 }
 
 fn make_ty_msrv_map(tcx: TyCtxt<'_>) -> FxHashMap<Ty<'_>, Option<RustcVersion>> {
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs
index d0d02a382d1..6051dc9479b 100644
--- a/src/tools/clippy/clippy_lints/src/functions/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs
@@ -303,7 +303,7 @@ declare_clippy_lint! {
     /// to the name of the method, when there is a field's whose name matches that of the method.
     ///
     /// ### Why is this bad?
-    /// It is most likely that such a  method is a bug caused by a typo or by copy-pasting.
+    /// It is most likely that such a method is a bug caused by a typo or by copy-pasting.
     ///
     /// ### Example
 
diff --git a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
index 6444e99ae9c..a99118f90f8 100644
--- a/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
+++ b/src/tools/clippy/clippy_lints/src/if_let_mutex.rs
@@ -1,14 +1,13 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::for_each_expr_without_closures;
-use clippy_utils::{eq_expr_value, higher};
+use clippy_utils::{eq_expr_value, higher, sym};
 use core::ops::ControlFlow;
 use rustc_errors::Diag;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::edition::Edition::Edition2024;
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -94,7 +93,7 @@ fn mutex_lock_call<'tcx>(
     op_mutex: Option<&'tcx Expr<'_>>,
 ) -> ControlFlow<&'tcx Expr<'tcx>> {
     if let ExprKind::MethodCall(path, self_arg, [], _) = &expr.kind
-        && path.ident.as_str() == "lock"
+        && path.ident.name == sym::lock
         && let ty = cx.typeck_results().expr_ty(self_arg).peel_refs()
         && is_type_diagnostic_item(cx, ty, sym::Mutex)
         && op_mutex.is_none_or(|op| eq_expr_value(cx, self_arg, op))
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
index 0823ef53ef9..c743501da25 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::msrvs::{self, Msrv};
 use clippy_utils::sugg::{Sugg, make_binop};
 use clippy_utils::{
-    SpanlessEq, eq_expr_value, higher, is_in_const_context, is_integer_literal, peel_blocks, peel_blocks_with_stmt,
+    SpanlessEq, eq_expr_value, higher, is_in_const_context, is_integer_literal, peel_blocks, peel_blocks_with_stmt, sym,
 };
 use rustc_ast::ast::LitKind;
 use rustc_data_structures::packed::Pu128;
@@ -11,7 +11,7 @@ use rustc_errors::Applicability;
 use rustc_hir::{AssignOpKind, BinOp, BinOpKind, Expr, ExprKind, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -325,7 +325,7 @@ fn check_with_condition<'tcx>(
         }
 
         // Get the variable name
-        let var_name = ares_path.segments[0].ident.name.as_str();
+        let var_name = ares_path.segments[0].ident.name;
         match cond_num_val.kind {
             ExprKind::Lit(cond_lit) => {
                 // Check if the constant is zero
@@ -337,7 +337,7 @@ fn check_with_condition<'tcx>(
                 }
             },
             ExprKind::Path(QPath::TypeRelative(_, name)) => {
-                if name.ident.as_str() == "MIN"
+                if name.ident.name == sym::MIN
                     && let Some(const_id) = cx.typeck_results().type_dependent_def_id(cond_num_val.hir_id)
                     && let Some(impl_id) = cx.tcx.impl_of_method(const_id)
                     && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl
@@ -348,7 +348,7 @@ fn check_with_condition<'tcx>(
             },
             ExprKind::Call(func, []) => {
                 if let ExprKind::Path(QPath::TypeRelative(_, name)) = func.kind
-                    && name.ident.as_str() == "min_value"
+                    && name.ident.name == sym::min_value
                     && let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id)
                     && let Some(impl_id) = cx.tcx.impl_of_method(func_id)
                     && let None = cx.tcx.impl_trait_ref(impl_id) // An inherent impl
@@ -383,7 +383,7 @@ fn subtracts_one<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a Exp
     }
 }
 
-fn print_lint_and_sugg(cx: &LateContext<'_>, var_name: &str, expr: &Expr<'_>) {
+fn print_lint_and_sugg(cx: &LateContext<'_>, var_name: Symbol, expr: &Expr<'_>) {
     span_lint_and_sugg(
         cx,
         IMPLICIT_SATURATING_SUB,
diff --git a/src/tools/clippy/clippy_lints/src/infallible_try_from.rs b/src/tools/clippy/clippy_lints/src/infallible_try_from.rs
new file mode 100644
index 00000000000..b54c289fa7e
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/infallible_try_from.rs
@@ -0,0 +1,76 @@
+use clippy_utils::diagnostics::span_lint;
+use clippy_utils::sym;
+use rustc_errors::MultiSpan;
+use rustc_hir::{AssocItemKind, Item, ItemKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
+
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// Finds manual impls of `TryFrom` with infallible error types.
+    ///
+    /// ### Why is this bad?
+    ///
+    /// Infalliable conversions should be implemented via `From` with the blanket conversion.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// use std::convert::Infallible;
+    /// struct MyStruct(i16);
+    /// impl TryFrom<i16> for MyStruct {
+    ///     type Error = Infallible;
+    ///     fn try_from(other: i16) -> Result<Self, Infallible> {
+    ///         Ok(Self(other.into()))
+    ///     }
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// struct MyStruct(i16);
+    /// impl From<i16> for MyStruct {
+    ///     fn from(other: i16) -> Self {
+    ///         Self(other)
+    ///     }
+    /// }
+    /// ```
+    #[clippy::version = "1.88.0"]
+    pub INFALLIBLE_TRY_FROM,
+    suspicious,
+    "TryFrom with infallible Error type"
+}
+declare_lint_pass!(InfallibleTryFrom => [INFALLIBLE_TRY_FROM]);
+
+impl<'tcx> LateLintPass<'tcx> for InfallibleTryFrom {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
+        let ItemKind::Impl(imp) = item.kind else { return };
+        let Some(r#trait) = imp.of_trait else { return };
+        let Some(trait_def_id) = r#trait.trait_def_id() else {
+            return;
+        };
+        if !cx.tcx.is_diagnostic_item(sym::TryFrom, trait_def_id) {
+            return;
+        }
+        for ii in imp.items {
+            if ii.kind == AssocItemKind::Type {
+                let ii = cx.tcx.hir_impl_item(ii.id);
+                if ii.ident.name != sym::Error {
+                    continue;
+                }
+                let ii_ty = ii.expect_type();
+                let ii_ty_span = ii_ty.span;
+                let ii_ty = clippy_utils::ty::ty_from_hir_ty(cx, ii_ty);
+                if !ii_ty.is_inhabited_from(cx.tcx, ii.owner_id.to_def_id(), cx.typing_env()) {
+                    let mut span = MultiSpan::from_span(cx.tcx.def_span(item.owner_id.to_def_id()));
+                    span.push_span_label(ii_ty_span, "infallible error type");
+                    span_lint(
+                        cx,
+                        INFALLIBLE_TRY_FROM,
+                        span,
+                        "infallible TryFrom impl; consider implementing From, instead",
+                    );
+                }
+            }
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 92eb3d7a7c5..be9142b17fe 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -55,6 +55,7 @@ extern crate rustc_session;
 extern crate rustc_span;
 extern crate rustc_target;
 extern crate rustc_trait_selection;
+extern crate smallvec;
 extern crate thin_vec;
 
 #[macro_use]
@@ -65,11 +66,10 @@ extern crate clippy_utils;
 
 mod utils;
 
-pub mod ctfe; // Very important lint, do not remove (rust#125116)
 pub mod declared_lints;
 pub mod deprecated_lints;
 
-// begin lints modules, do not remove this comment, it’s used in `update_lints`
+// begin lints modules, do not remove this comment, it's used in `update_lints`
 mod absolute_paths;
 mod almost_complete_range;
 mod approx_const;
@@ -95,6 +95,7 @@ mod casts;
 mod cfg_not_test;
 mod checked_conversions;
 mod cloned_ref_to_slice_refs;
+mod coerce_container_to_any;
 mod cognitive_complexity;
 mod collapsible_if;
 mod collection_is_never_read;
@@ -169,6 +170,7 @@ mod inconsistent_struct_constructor;
 mod index_refutable_slice;
 mod indexing_slicing;
 mod ineffective_open_options;
+mod infallible_try_from;
 mod infinite_iter;
 mod inherent_impl;
 mod inherent_to_string;
@@ -404,7 +406,7 @@ mod zero_div_zero;
 mod zero_repeat_side_effects;
 mod zero_sized_map_values;
 mod zombie_processes;
-// end lints modules, do not remove this comment, it’s used in `update_lints`
+// end lints modules, do not remove this comment, it's used in `update_lints`
 
 use clippy_config::{Conf, get_configuration_metadata, sanitize_explanation};
 use clippy_utils::macros::FormatArgsStorage;
@@ -583,8 +585,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     let attrs = attr_storage.clone();
     store.register_early_pass(move || Box::new(AttrCollector::new(attrs.clone())));
 
-    store.register_late_pass(|_| Box::new(ctfe::ClippyCtfe));
-
     store.register_late_pass(move |_| Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(conf)));
     store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir));
     store.register_late_pass(|_| Box::new(utils::author::Author));
@@ -946,5 +946,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(|_| Box::new(single_option_map::SingleOptionMap));
     store.register_late_pass(move |_| Box::new(redundant_test_prefix::RedundantTestPrefix));
     store.register_late_pass(|_| Box::new(cloned_ref_to_slice_refs::ClonedRefToSliceRefs::new(conf)));
+    store.register_late_pass(|_| Box::new(infallible_try_from::InfallibleTryFrom));
+    store.register_late_pass(|_| Box::new(coerce_container_to_any::CoerceContainerToAny));
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
index 81f14b7b2b0..ddb8bb536c0 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
@@ -2,8 +2,9 @@ use super::MANUAL_FLATTEN;
 use super::utils::make_iterator_snippet;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::source::{HasSession, indent_of, reindent_multiline, snippet_with_applicability};
 use clippy_utils::visitors::is_local_used;
-use clippy_utils::{higher, is_refutable, path_to_local_id, peel_blocks_with_stmt};
+use clippy_utils::{higher, is_refutable, path_to_local_id, peel_blocks_with_stmt, span_contains_comment};
 use rustc_errors::Applicability;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::{Expr, Pat, PatKind};
@@ -39,13 +40,20 @@ pub(super) fn check<'tcx>(
         && msrv.meets(cx, msrvs::ITER_FLATTEN)
         && !is_refutable(cx, inner_pat)
     {
+        if arg.span.from_expansion() || if_then.span.from_expansion() {
+            return;
+        }
         let if_let_type = if some_ctor { "Some" } else { "Ok" };
         // Prepare the error message
         let msg =
             format!("unnecessary `if let` since only the `{if_let_type}` variant of the iterator element is used");
 
         // Prepare the help message
-        let mut applicability = Applicability::MaybeIncorrect;
+        let mut applicability = if span_contains_comment(cx.sess().source_map(), body.span) {
+            Applicability::MaybeIncorrect
+        } else {
+            Applicability::MachineApplicable
+        };
         let arg_snippet = make_iterator_snippet(cx, arg, &mut applicability);
         let copied = match cx.typeck_results().expr_ty(let_expr).kind() {
             ty::Ref(_, inner, _) => match inner.kind() {
@@ -55,20 +63,26 @@ pub(super) fn check<'tcx>(
             _ => "",
         };
 
-        let sugg = format!("{arg_snippet}{copied}.flatten()");
+        let help_msg = "try `.flatten()` and remove the `if let` statement in the for loop";
 
-        // If suggestion is not a one-liner, it won't be shown inline within the error message. In that
-        // case, it will be shown in the extra `help` message at the end, which is why the first
-        // `help_msg` needs to refer to the correct relative position of the suggestion.
-        let help_msg = if sugg.contains('\n') {
-            "remove the `if let` statement in the for loop and then..."
-        } else {
-            "...and remove the `if let` statement in the for loop"
-        };
+        let pat_snippet =
+            snippet_with_applicability(cx, inner_pat.span.source_callsite(), "_", &mut applicability).to_string();
+        let body_snippet =
+            snippet_with_applicability(cx, if_then.span.source_callsite(), "[body]", &mut applicability).to_string();
+        let suggestions = vec![
+            // flatten the iterator
+            (arg.span, format!("{arg_snippet}{copied}.flatten()")),
+            (pat.span, pat_snippet),
+            // remove the `if let` statement
+            (
+                body.span,
+                reindent_multiline(&body_snippet, true, indent_of(cx, body.span)),
+            ),
+        ];
 
         span_lint_and_then(cx, MANUAL_FLATTEN, span, msg, |diag| {
-            diag.span_suggestion(arg.span, "try", sugg, applicability);
             diag.span_help(inner_expr.span, help_msg);
+            diag.multipart_suggestion("try", suggestions, applicability);
         });
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
index 02afe9f0997..42fe386d2c3 100644
--- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
@@ -8,7 +8,7 @@ use clippy_utils::ty::implements_trait;
 use clippy_utils::visitors::is_const_evaluatable;
 use clippy_utils::{
     MaybePath, eq_expr_value, is_diag_trait_item, is_in_const_context, is_trait_method, path_res, path_to_local_id,
-    peel_blocks, peel_blocks_with_stmt,
+    peel_blocks, peel_blocks_with_stmt, sym,
 };
 use itertools::Itertools;
 use rustc_errors::{Applicability, Diag};
@@ -18,7 +18,6 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty;
 use rustc_session::impl_lint_pass;
 use rustc_span::Span;
-use rustc_span::symbol::sym;
 use std::cmp::Ordering;
 use std::ops::Deref;
 
@@ -299,9 +298,9 @@ fn is_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> O
         && (cx.typeck_results().expr_ty_adjusted(input).is_floating_point() || is_trait_method(cx, receiver, sym::Ord))
     {
         let is_float = cx.typeck_results().expr_ty_adjusted(input).is_floating_point();
-        let (min, max) = match (seg_first.ident.as_str(), seg_second.ident.as_str()) {
-            ("min", "max") => (arg_second, arg_first),
-            ("max", "min") => (arg_first, arg_second),
+        let (min, max) = match (seg_first.ident.name, seg_second.ident.name) {
+            (sym::min, sym::max) => (arg_second, arg_first),
+            (sym::max, sym::min) => (arg_first, arg_second),
             _ => return None,
         };
         Some(ClampSuggestion {
diff --git a/src/tools/clippy/clippy_lints/src/manual_string_new.rs b/src/tools/clippy/clippy_lints/src/manual_string_new.rs
index 73ee1c3c78a..9b590e092d0 100644
--- a/src/tools/clippy/clippy_lints/src/manual_string_new.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_string_new.rs
@@ -1,11 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::sym;
 use rustc_ast::LitKind;
 use rustc_errors::Applicability::MachineApplicable;
 use rustc_hir::{Expr, ExprKind, PathSegment, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::declare_lint_pass;
-use rustc_span::{Span, sym};
+use rustc_span::Span;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -89,9 +90,10 @@ fn warn_then_suggest(cx: &LateContext<'_>, span: Span) {
 
 /// Tries to parse an expression as a method call, emitting the warning if necessary.
 fn parse_method_call(cx: &LateContext<'_>, span: Span, path_segment: &PathSegment<'_>, receiver: &Expr<'_>) {
-    let ident = path_segment.ident.as_str();
     let method_arg_kind = &receiver.kind;
-    if ["to_string", "to_owned", "into"].contains(&ident) && is_expr_kind_empty_str(method_arg_kind) {
+    if matches!(path_segment.ident.name, sym::to_string | sym::to_owned | sym::into)
+        && is_expr_kind_empty_str(method_arg_kind)
+    {
         warn_then_suggest(cx, span);
     } else if let ExprKind::Call(func, [arg]) = method_arg_kind {
         // If our first argument is a function call itself, it could be an `unwrap`-like function.
diff --git a/src/tools/clippy/clippy_lints/src/match_result_ok.rs b/src/tools/clippy/clippy_lints/src/match_result_ok.rs
index 2a5fc8b6609..e0cb5d14d3c 100644
--- a/src/tools/clippy/clippy_lints/src/match_result_ok.rs
+++ b/src/tools/clippy/clippy_lints/src/match_result_ok.rs
@@ -1,12 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{higher, is_res_lang_ctor};
+use clippy_utils::{higher, is_res_lang_ctor, sym};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, LangItem, PatKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -57,7 +56,7 @@ impl<'tcx> LateLintPass<'tcx> for MatchResultOk {
 
         if let ExprKind::MethodCall(ok_path, recv, [], ..) = let_expr.kind //check is expr.ok() has type Result<T,E>.ok(, _)
             && let PatKind::TupleStruct(ref pat_path, [ok_pat], _)  = let_pat.kind //get operation
-            && ok_path.ident.as_str() == "ok"
+            && ok_path.ident.name == sym::ok
             && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result)
             && is_res_lang_ctor(cx, cx.qpath_res(pat_path, let_pat.hir_id), LangItem::OptionSome)
             && let ctxt = expr.span.ctxt()
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
index adda3586990..6a76c6cedd0 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::macros::HirNode;
 use clippy_utils::source::{indent_of, snippet, snippet_block_with_context, snippet_with_context};
-use clippy_utils::{get_parent_expr, is_refutable, peel_blocks};
+use clippy_utils::{is_refutable, peel_blocks};
 use rustc_errors::Applicability;
 use rustc_hir::{Arm, Expr, ExprKind, Node, PatKind, StmtKind};
 use rustc_lint::LateContext;
@@ -9,6 +9,7 @@ use rustc_span::Span;
 
 use super::MATCH_SINGLE_BINDING;
 
+#[derive(Debug)]
 enum AssignmentExpr {
     Assign { span: Span, match_span: Span },
     Local { span: Span, pat_span: Span },
@@ -160,6 +161,17 @@ fn opt_parent_assign_span<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<Ass
     None
 }
 
+fn expr_parent_requires_curlies<'a>(cx: &LateContext<'a>, match_expr: &Expr<'a>) -> bool {
+    let parent = cx.tcx.parent_hir_node(match_expr.hir_id);
+    matches!(
+        parent,
+        Node::Expr(Expr {
+            kind: ExprKind::Closure { .. },
+            ..
+        }) | Node::AnonConst(..)
+    )
+}
+
 fn sugg_with_curlies<'a>(
     cx: &LateContext<'a>,
     (ex, match_expr): (&Expr<'a>, &Expr<'a>),
@@ -172,9 +184,7 @@ fn sugg_with_curlies<'a>(
     let mut indent = " ".repeat(indent_of(cx, ex.span).unwrap_or(0));
 
     let (mut cbrace_start, mut cbrace_end) = (String::new(), String::new());
-    if let Some(parent_expr) = get_parent_expr(cx, match_expr)
-        && let ExprKind::Closure { .. } = parent_expr.kind
-    {
+    if expr_parent_requires_curlies(cx, match_expr) {
         cbrace_end = format!("\n{indent}}}");
         // Fix body indent due to the closure
         indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
index 65b93a095b9..8b4c1700051 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
@@ -1,6 +1,7 @@
 use std::ops::ControlFlow;
 
 use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::sym;
 use clippy_utils::ty::is_type_lang_item;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
@@ -42,7 +43,7 @@ impl<'tcx> Visitor<'tcx> for MatchExprVisitor<'_, 'tcx> {
     type Result = ControlFlow<CaseMethod>;
     fn visit_expr(&mut self, ex: &'tcx Expr<'_>) -> Self::Result {
         if let ExprKind::MethodCall(segment, receiver, [], _) = ex.kind {
-            let result = self.case_altered(segment.ident.as_str(), receiver);
+            let result = self.case_altered(segment.ident.name, receiver);
             if result.is_break() {
                 return result;
             }
@@ -53,7 +54,7 @@ impl<'tcx> Visitor<'tcx> for MatchExprVisitor<'_, 'tcx> {
 }
 
 impl MatchExprVisitor<'_, '_> {
-    fn case_altered(&mut self, segment_ident: &str, receiver: &Expr<'_>) -> ControlFlow<CaseMethod> {
+    fn case_altered(&mut self, segment_ident: Symbol, receiver: &Expr<'_>) -> ControlFlow<CaseMethod> {
         if let Some(case_method) = get_case_method(segment_ident) {
             let ty = self.cx.typeck_results().expr_ty(receiver).peel_refs();
 
@@ -66,12 +67,12 @@ impl MatchExprVisitor<'_, '_> {
     }
 }
 
-fn get_case_method(segment_ident_str: &str) -> Option<CaseMethod> {
-    match segment_ident_str {
-        "to_lowercase" => Some(CaseMethod::LowerCase),
-        "to_ascii_lowercase" => Some(CaseMethod::AsciiLowerCase),
-        "to_uppercase" => Some(CaseMethod::UpperCase),
-        "to_ascii_uppercase" => Some(CaseMethod::AsciiUppercase),
+fn get_case_method(segment_ident: Symbol) -> Option<CaseMethod> {
+    match segment_ident {
+        sym::to_lowercase => Some(CaseMethod::LowerCase),
+        sym::to_ascii_lowercase => Some(CaseMethod::AsciiLowerCase),
+        sym::to_uppercase => Some(CaseMethod::UpperCase),
+        sym::to_ascii_uppercase => Some(CaseMethod::AsciiUppercase),
         _ => None,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/ip_constant.rs b/src/tools/clippy/clippy_lints/src/methods/ip_constant.rs
new file mode 100644
index 00000000000..83803fba6a1
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/ip_constant.rs
@@ -0,0 +1,52 @@
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, QPath, Ty, TyKind};
+use rustc_lint::LateContext;
+use rustc_span::sym;
+use smallvec::SmallVec;
+
+use super::IP_CONSTANT;
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, func: &Expr<'_>, args: &[Expr<'_>]) {
+    if let ExprKind::Path(QPath::TypeRelative(
+        Ty {
+            kind: TyKind::Path(QPath::Resolved(_, func_path)),
+            ..
+        },
+        p,
+    )) = func.kind
+        && p.ident.name == sym::new
+        && let Some(func_def_id) = func_path.res.opt_def_id()
+        && matches!(
+            cx.tcx.get_diagnostic_name(func_def_id),
+            Some(sym::Ipv4Addr | sym::Ipv6Addr)
+        )
+        && let Some(args) = args
+            .iter()
+            .map(|arg| {
+                if let Some(Constant::Int(constant @ (0 | 1 | 127 | 255))) = ConstEvalCtxt::new(cx).eval(arg) {
+                    u8::try_from(constant).ok()
+                } else {
+                    None
+                }
+            })
+            .collect::<Option<SmallVec<[u8; 8]>>>()
+    {
+        let constant_name = match args.as_slice() {
+            [0, 0, 0, 0] | [0, 0, 0, 0, 0, 0, 0, 0] => "UNSPECIFIED",
+            [127, 0, 0, 1] | [0, 0, 0, 0, 0, 0, 0, 1] => "LOCALHOST",
+            [255, 255, 255, 255] => "BROADCAST",
+            _ => return,
+        };
+
+        span_lint_and_then(cx, IP_CONSTANT, expr.span, "hand-coded well-known IP address", |diag| {
+            diag.span_suggestion_verbose(
+                expr.span.with_lo(p.ident.span.lo()),
+                "use",
+                constant_name,
+                Applicability::MachineApplicable,
+            );
+        });
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
index c88462129af..cbb1b450e60 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
@@ -46,7 +46,7 @@ pub(super) fn check<'tcx>(
 
         if let ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body_expr.kind
             && let [local_ident] = path.segments
-            && local_ident.ident.as_str() == bound_ident.as_str()
+            && local_ident.ident.name == bound_ident.name
         {
             span_lint_and_sugg(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
index e2df8ce1513..c785b23bc9c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
@@ -72,9 +72,9 @@ fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<MinMax> {
     if let hir::ExprKind::Call(func, []) = &expr.kind
         && let hir::ExprKind::Path(hir::QPath::TypeRelative(_, segment)) = &func.kind
     {
-        match segment.ident.as_str() {
-            "max_value" => return Some(MinMax::Max),
-            "min_value" => return Some(MinMax::Min),
+        match segment.ident.name {
+            sym::max_value => return Some(MinMax::Max),
+            sym::min_value => return Some(MinMax::Min),
             _ => {},
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index bc159206985..347960e0003 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -37,6 +37,7 @@ mod inefficient_to_string;
 mod inspect_for_each;
 mod into_iter_on_ref;
 mod io_other_error;
+mod ip_constant;
 mod is_digit_ascii_radix;
 mod is_empty;
 mod iter_cloned_collect;
@@ -4528,6 +4529,42 @@ declare_clippy_lint! {
     "detect swap with a temporary value"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    /// Checks for IP addresses that could be replaced with predefined constants such as
+    /// `Ipv4Addr::new(127, 0, 0, 1)` instead of using the appropriate constants.
+    ///
+    /// ### Why is this bad?
+    /// Using specific IP addresses like `127.0.0.1` or `::1` is less clear and less maintainable than using the
+    /// predefined constants `Ipv4Addr::LOCALHOST` or `Ipv6Addr::LOCALHOST`. These constants improve code
+    /// readability, make the intent explicit, and are less error-prone.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// use std::net::{Ipv4Addr, Ipv6Addr};
+    ///
+    /// // IPv4 loopback
+    /// let addr_v4 = Ipv4Addr::new(127, 0, 0, 1);
+    ///
+    /// // IPv6 loopback
+    /// let addr_v6 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// use std::net::{Ipv4Addr, Ipv6Addr};
+    ///
+    /// // IPv4 loopback
+    /// let addr_v4 = Ipv4Addr::LOCALHOST;
+    ///
+    /// // IPv6 loopback
+    /// let addr_v6 = Ipv6Addr::LOCALHOST;
+    /// ```
+    #[clippy::version = "1.89.0"]
+    pub IP_CONSTANT,
+    pedantic,
+    "hardcoded localhost IP address"
+}
+
 #[expect(clippy::struct_excessive_bools)]
 pub struct Methods {
     avoid_breaking_exported_api: bool,
@@ -4706,6 +4743,7 @@ impl_lint_pass!(Methods => [
     MANUAL_CONTAINS,
     IO_OTHER_ERROR,
     SWAP_WITH_TEMPORARY,
+    IP_CONSTANT,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -4738,6 +4776,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
                 useless_nonzero_new_unchecked::check(cx, expr, func, args, self.msrv);
                 io_other_error::check(cx, expr, func, args, self.msrv);
                 swap_with_temporary::check(cx, expr, func, args);
+                ip_constant::check(cx, expr, func, args);
             },
             ExprKind::MethodCall(method_call, receiver, args, _) => {
                 let method_span = method_call.ident.span;
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index 2b75d6a8248..0075bf166cc 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -44,11 +44,10 @@ pub(super) fn check<'tcx>(
 
             if let ExprKind::MethodCall(name, _, args @ ([] | [_]), _) = parent.kind {
                 let mut app = Applicability::MachineApplicable;
-                let name = name.ident.as_str();
                 let collect_ty = cx.typeck_results().expr_ty(collect_expr);
 
-                let sugg: String = match name {
-                    "len" => {
+                let sugg: String = match name.ident.name {
+                    sym::len => {
                         if let Some(adt) = collect_ty.ty_adt_def()
                             && matches!(
                                 cx.tcx.get_diagnostic_name(adt.did()),
@@ -60,13 +59,13 @@ pub(super) fn check<'tcx>(
                             return;
                         }
                     },
-                    "is_empty"
+                    sym::is_empty
                         if is_is_empty_sig(cx, parent.hir_id)
                             && iterates_same_ty(cx, cx.typeck_results().expr_ty(iter_expr), collect_ty) =>
                     {
                         "next().is_none()".into()
                     },
-                    "contains" => {
+                    sym::contains => {
                         if is_contains_sig(cx, parent.hir_id, iter_expr)
                             && let Some(arg) = args.first()
                         {
diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
index bce314e64f0..fd368024177 100644
--- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
@@ -1,14 +1,14 @@
 use rustc_data_structures::fx::FxHashMap;
 
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
-use clippy_utils::paths;
 use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{paths, sym};
 use rustc_ast::ast::LitKind;
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::Ty;
+use rustc_span::Span;
 use rustc_span::source_map::Spanned;
-use rustc_span::{Span, sym};
 
 use super::{NONSENSICAL_OPEN_OPTIONS, SUSPICIOUS_OPEN_OPTIONS};
 
@@ -87,23 +87,23 @@ fn get_open_options(
                 _ => Argument::Unknown,
             };
 
-            match path.ident.as_str() {
-                "create" => {
+            match path.ident.name {
+                sym::create => {
                     options.push((OpenOption::Create, argument_option, span));
                 },
-                "create_new" => {
+                sym::create_new => {
                     options.push((OpenOption::CreateNew, argument_option, span));
                 },
-                "append" => {
+                sym::append => {
                     options.push((OpenOption::Append, argument_option, span));
                 },
-                "truncate" => {
+                sym::truncate => {
                     options.push((OpenOption::Truncate, argument_option, span));
                 },
-                "read" => {
+                sym::read => {
                     options.push((OpenOption::Read, argument_option, span));
                 },
-                "write" => {
+                sym::write => {
                     options.push((OpenOption::Write, argument_option, span));
                 },
                 _ => {
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
index 6935ae1f391..6f78d6c6128 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -285,9 +285,9 @@ fn parse_iter_usage<'tcx>(
             let did = cx.typeck_results().type_dependent_def_id(e.hir_id)?;
             let iter_id = cx.tcx.get_diagnostic_item(sym::Iterator)?;
 
-            match (name.ident.as_str(), args) {
-                ("next", []) if cx.tcx.trait_of_item(did) == Some(iter_id) => (IterUsageKind::Nth(0), e.span),
-                ("next_tuple", []) => {
+            match (name.ident.name, args) {
+                (sym::next, []) if cx.tcx.trait_of_item(did) == Some(iter_id) => (IterUsageKind::Nth(0), e.span),
+                (sym::next_tuple, []) => {
                     return if paths::ITERTOOLS_NEXT_TUPLE.matches(cx, did)
                         && let ty::Adt(adt_def, subs) = cx.typeck_results().expr_ty(e).kind()
                         && cx.tcx.is_diagnostic_item(sym::Option, adt_def.did())
@@ -303,7 +303,7 @@ fn parse_iter_usage<'tcx>(
                         None
                     };
                 },
-                ("nth" | "skip", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => {
+                (sym::nth | sym::skip, [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => {
                     if let Some(Constant::Int(idx)) = ConstEvalCtxt::new(cx).eval(idx_expr) {
                         let span = if name.ident.as_str() == "nth" {
                             e.span
diff --git a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs
index 4b32ba83b32..741f38f9756 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs
@@ -47,7 +47,7 @@ impl EarlyLintPass for MultipleBoundLocations {
 
             for param in &generics.params {
                 if !param.bounds.is_empty() {
-                    generic_params_with_bounds.insert(param.ident.name.as_str(), param.ident.span);
+                    generic_params_with_bounds.insert(param.ident.as_str(), param.ident.span);
                 }
             }
             for clause in &generics.where_clause.predicates {
@@ -64,7 +64,7 @@ impl EarlyLintPass for MultipleBoundLocations {
                     },
                     WherePredicateKind::RegionPredicate(pred) => {
                         if !pred.bounds.is_empty()
-                            && let Some(bound_span) = generic_params_with_bounds.get(&pred.lifetime.ident.name.as_str())
+                            && let Some(bound_span) = generic_params_with_bounds.get(&pred.lifetime.ident.as_str())
                         {
                             emit_lint(cx, *bound_span, pred.lifetime.ident.span);
                         }
diff --git a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
index 93865197ec9..04b09276966 100644
--- a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
@@ -293,7 +293,14 @@ fn self_cmp_call<'tcx>(
         ExprKind::Call(path, [_, _]) => path_res(cx, path)
             .opt_def_id()
             .is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::ord_cmp_method, def_id)),
-        ExprKind::MethodCall(_, _, [_other], ..) => {
+        ExprKind::MethodCall(_, recv, [_], ..) => {
+            let ExprKind::Path(path) = recv.kind else {
+                return false;
+            };
+            if last_path_segment(&path).ident.name != kw::SelfLower {
+                return false;
+            }
+
             // We can set this to true here no matter what as if it's a `MethodCall` and goes to the
             // `else` branch, it must be a method named `cmp` that isn't `Ord::cmp`
             *needs_fully_qualified = true;
diff --git a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
index 35caac855cf..4ce6827cac9 100644
--- a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
@@ -1,14 +1,14 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::path_to_local_id;
 use clippy_utils::source::{SpanRangeExt, snippet};
 use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{path_to_local_id, sym};
 use rustc_ast::{LitKind, StrStyle};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, LetStmt, PatKind, QPath, Stmt, StmtKind, TyKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::impl_lint_pass;
-use rustc_span::{Span, Symbol, sym};
+use rustc_span::{Span, Symbol};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -177,7 +177,7 @@ impl<'tcx> LateLintPass<'tcx> for PathbufThenPush<'tcx> {
             && let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind
             && let ExprKind::MethodCall(name, self_arg, [arg_expr], _) = expr.kind
             && path_to_local_id(self_arg, searcher.local_id)
-            && name.ident.as_str() == "push"
+            && name.ident.name == sym::push
         {
             searcher.err_span = searcher.err_span.to(stmt.span);
             searcher.arg = Some(*arg_expr);
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 9149406642d..94cdcf00054 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then, span_lin
 use clippy_utils::source::SpanRangeExt;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::visitors::contains_unsafe_block;
-use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, std_or_core};
+use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, std_or_core, sym};
 use hir::LifetimeKind;
 use rustc_abi::ExternAbi;
 use rustc_errors::{Applicability, MultiSpan};
@@ -18,8 +18,8 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, Binder, ClauseKind, ExistentialPredicate, List, PredicateKind, Ty};
 use rustc_session::declare_lint_pass;
+use rustc_span::Span;
 use rustc_span::symbol::Symbol;
-use rustc_span::{Span, sym};
 use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use std::{fmt, iter};
@@ -268,6 +268,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
                 (false, false, true) if let Some(sugg) = Sugg::hir_opt(cx, l) => sugg.maybe_paren(),
                 _ => return check_ptr_eq(cx, expr, op.node, l, r),
             };
+            let invert = if op.node == BinOpKind::Eq { "" } else { "!" };
 
             span_lint_and_sugg(
                 cx,
@@ -275,7 +276,7 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
                 expr.span,
                 "comparing with null is better expressed by the `.is_null()` method",
                 "try",
-                format!("{non_null_path_snippet}.is_null()"),
+                format!("{invert}{non_null_path_snippet}.is_null()",),
                 Applicability::MachineApplicable,
             );
         }
@@ -299,7 +300,7 @@ struct PtrArg<'tcx> {
     emission_id: HirId,
     span: Span,
     ty_name: Symbol,
-    method_renames: &'static [(&'static str, &'static str)],
+    method_renames: &'static [(Symbol, &'static str)],
     ref_prefix: RefPrefix,
     deref_ty: DerefTy<'tcx>,
 }
@@ -385,6 +386,7 @@ impl<'tcx> DerefTy<'tcx> {
     }
 }
 
+#[expect(clippy::too_many_lines)]
 fn check_fn_args<'cx, 'tcx: 'cx>(
     cx: &'cx LateContext<'tcx>,
     fn_sig: ty::FnSig<'tcx>,
@@ -409,7 +411,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
                 let emission_id = params.get(i).map_or(hir_ty.hir_id, |param| param.hir_id);
                 let (method_renames, deref_ty) = match cx.tcx.get_diagnostic_name(adt.did()) {
                     Some(sym::Vec) => (
-                        [("clone", ".to_owned()")].as_slice(),
+                        [(sym::clone, ".to_owned()")].as_slice(),
                         DerefTy::Slice(
                             name.args.and_then(|args| args.args.first()).and_then(|arg| {
                                 if let GenericArg::Type(ty) = arg {
@@ -421,10 +423,14 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
                             args.type_at(0),
                         ),
                     ),
-                    _ if Some(adt.did()) == cx.tcx.lang_items().string() => {
-                        ([("clone", ".to_owned()"), ("as_str", "")].as_slice(), DerefTy::Str)
-                    },
-                    Some(sym::PathBuf) => ([("clone", ".to_path_buf()"), ("as_path", "")].as_slice(), DerefTy::Path),
+                    _ if Some(adt.did()) == cx.tcx.lang_items().string() => (
+                        [(sym::clone, ".to_owned()"), (sym::as_str, "")].as_slice(),
+                        DerefTy::Str,
+                    ),
+                    Some(sym::PathBuf) => (
+                        [(sym::clone, ".to_path_buf()"), (sym::as_path, "")].as_slice(),
+                        DerefTy::Path,
+                    ),
                     Some(sym::Cow) if mutability == Mutability::Not => {
                         if let Some((lifetime, ty)) = name.args.and_then(|args| {
                             if let [GenericArg::Lifetime(lifetime), ty] = args.args {
@@ -595,7 +601,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &Body<'tcx>, args: &[
                     if let ExprKind::MethodCall(name, receiver, ..) = use_expr.kind
                         && receiver.hir_id == child_id
                     {
-                        let name = name.ident.as_str();
+                        let name = name.ident.name;
 
                         // Check if the method can be renamed.
                         if let Some((_, replacement)) = args.method_renames.iter().find(|&&(x, _)| x == name) {
diff --git a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
index 49b522994fb..6b1dc864fb7 100644
--- a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then};
-use clippy_utils::get_enclosing_block;
 use clippy_utils::higher::{VecInitKind, get_vec_init_kind};
 use clippy_utils::source::snippet;
+use clippy_utils::{get_enclosing_block, sym};
 
 use hir::{Expr, ExprKind, HirId, LetStmt, PatKind, PathSegment, QPath, StmtKind};
 use rustc_errors::Applicability;
@@ -87,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec {
                                 diag.span_suggestion(
                                     expr.span,
                                     "try",
-                                    format!("{}.resize({len}, 0); {}", ident.as_str(), snippet(cx, expr.span, "..")),
+                                    format!("{}.resize({len}, 0); {}", ident, snippet(cx, expr.span, "..")),
                                     applicability,
                                 );
                             },
@@ -106,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec {
                                         "try",
                                         format!(
                                             "{}.resize({}, 0); {}",
-                                            ident.as_str(),
+                                            ident,
                                             snippet(cx, e.span, ".."),
                                             snippet(cx, expr.span, "..")
                                         ),
@@ -142,8 +142,8 @@ impl<'tcx> Visitor<'tcx> for ReadVecVisitor<'tcx> {
         if let ExprKind::MethodCall(path, receiver, args, _) = e.kind {
             let PathSegment { ident, .. } = *path;
 
-            match ident.as_str() {
-                "read" | "read_exact" => {
+            match ident.name {
+                sym::read | sym::read_exact => {
                     let [arg] = args else { return };
                     if let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind
                         && let ExprKind::Path(QPath::Resolved(None, inner_path)) = inner.kind
@@ -155,7 +155,7 @@ impl<'tcx> Visitor<'tcx> for ReadVecVisitor<'tcx> {
                         return;
                     }
                 },
-                "resize" => {
+                sym::resize => {
                     // If the Vec is resized, then it's a valid read
                     if let ExprKind::Path(QPath::Resolved(_, inner_path)) = receiver.kind
                         && let Res::Local(res_id) = inner_path.res
diff --git a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs
index 152d7450f5f..51adbbcd58b 100644
--- a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::higher::{VecInitKind, get_vec_init_kind};
 use clippy_utils::source::snippet;
-use clippy_utils::{is_from_proc_macro, path_to_local_id};
+use clippy_utils::{is_from_proc_macro, path_to_local_id, sym};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{BindingMode, Block, Expr, ExprKind, HirId, LetStmt, PatKind, QPath, Stmt, StmtKind};
@@ -126,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization {
             if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind
                 && let ExprKind::MethodCall(name, self_arg, [space_hint], _) = expr.kind
                 && path_to_local_id(self_arg, searcher.local_id)
-                && name.ident.as_str() == "reserve"
+                && name.ident.name == sym::reserve
                 && !is_from_proc_macro(cx, expr)
             {
                 self.searcher = Some(VecReserveSearcher {
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
index d85f4a8fa01..f6c128d4c52 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
@@ -143,7 +143,7 @@ impl LateLintPass<'_> for SemicolonBlock {
             StmtKind::Expr(Expr {
                 kind: ExprKind::Block(block, _),
                 ..
-            }) if !block.span.from_expansion() => {
+            }) if !block.span.from_expansion() && stmt.span.contains(block.span) => {
                 let Block {
                     expr: None,
                     stmts: [.., stmt],
diff --git a/src/tools/clippy/clippy_lints/src/serde_api.rs b/src/tools/clippy/clippy_lints/src/serde_api.rs
index a64b9b22378..b36a5d6d502 100644
--- a/src/tools/clippy/clippy_lints/src/serde_api.rs
+++ b/src/tools/clippy/clippy_lints/src/serde_api.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint;
-use clippy_utils::paths;
+use clippy_utils::{paths, sym};
 use rustc_hir::{Impl, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
@@ -36,9 +36,9 @@ impl<'tcx> LateLintPass<'tcx> for SerdeApi {
                 let mut seen_str = None;
                 let mut seen_string = None;
                 for item in *items {
-                    match item.ident.as_str() {
-                        "visit_str" => seen_str = Some(item.span),
-                        "visit_string" => seen_string = Some(item.span),
+                    match item.ident.name {
+                        sym::visit_str => seen_str = Some(item.span),
+                        sym::visit_string => seen_string = Some(item.span),
                         _ => {},
                     }
                 }
diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
index 3d39386ecf9..442b3250d86 100644
--- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
+++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
@@ -1,13 +1,13 @@
 use clippy_config::Conf;
-use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::is_from_proc_macro;
 use clippy_utils::msrvs::Msrv;
 use rustc_attr_data_structures::{StabilityLevel, StableSince};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{HirId, Path, PathSegment};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_hir::{Block, Body, HirId, Path, PathSegment};
+use rustc_lint::{LateContext, LateLintPass, Lint, LintContext};
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::kw;
 use rustc_span::{Span, sym};
@@ -88,24 +88,35 @@ declare_clippy_lint! {
 }
 
 pub struct StdReexports {
-    // Paths which can be either a module or a macro (e.g. `std::env`) will cause this check to happen
-    // twice. First for the mod, second for the macro. This is used to avoid the lint reporting for the macro
-    // when the path could be also be used to access the module.
-    prev_span: Span,
+    lint_point: (Span, Option<LintPoint>),
     msrv: Msrv,
 }
 
 impl StdReexports {
     pub fn new(conf: &'static Conf) -> Self {
         Self {
-            prev_span: Span::default(),
+            lint_point: Default::default(),
             msrv: conf.msrv,
         }
     }
+
+    fn lint_if_finish(&mut self, cx: &LateContext<'_>, (span, item): (Span, Option<LintPoint>)) {
+        if span.source_equal(self.lint_point.0) {
+            return;
+        }
+
+        if !self.lint_point.0.is_dummy() {
+            emit_lints(cx, &self.lint_point);
+        }
+
+        self.lint_point = (span, item);
+    }
 }
 
 impl_lint_pass!(StdReexports => [STD_INSTEAD_OF_CORE, STD_INSTEAD_OF_ALLOC, ALLOC_INSTEAD_OF_CORE]);
 
+type LintPoint = (&'static Lint, &'static str, &'static str);
+
 impl<'tcx> LateLintPass<'tcx> for StdReexports {
     fn check_path(&mut self, cx: &LateContext<'tcx>, path: &Path<'tcx>, _: HirId) {
         if let Res::Def(_, def_id) = path.res
@@ -119,7 +130,7 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
                     sym::core => (STD_INSTEAD_OF_CORE, "std", "core"),
                     sym::alloc => (STD_INSTEAD_OF_ALLOC, "std", "alloc"),
                     _ => {
-                        self.prev_span = first_segment.ident.span;
+                        self.lint_if_finish(cx, (first_segment.ident.span, None));
                         return;
                     },
                 },
@@ -127,32 +138,44 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
                     if cx.tcx.crate_name(def_id.krate) == sym::core {
                         (ALLOC_INSTEAD_OF_CORE, "alloc", "core")
                     } else {
-                        self.prev_span = first_segment.ident.span;
+                        self.lint_if_finish(cx, (first_segment.ident.span, None));
                         return;
                     }
                 },
                 _ => return,
             };
-            if first_segment.ident.span != self.prev_span {
-                #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
-                span_lint_and_then(
-                    cx,
-                    lint,
-                    first_segment.ident.span,
-                    format!("used import from `{used_mod}` instead of `{replace_with}`"),
-                    |diag| {
-                        diag.span_suggestion(
-                            first_segment.ident.span,
-                            format!("consider importing the item from `{replace_with}`"),
-                            replace_with.to_string(),
-                            Applicability::MachineApplicable,
-                        );
-                    },
-                );
-                self.prev_span = first_segment.ident.span;
-            }
+
+            self.lint_if_finish(cx, (first_segment.ident.span, Some((lint, used_mod, replace_with))));
         }
     }
+
+    fn check_block_post(&mut self, cx: &LateContext<'tcx>, _: &Block<'tcx>) {
+        self.lint_if_finish(cx, Default::default());
+    }
+
+    fn check_body_post(&mut self, cx: &LateContext<'tcx>, _: &Body<'tcx>) {
+        self.lint_if_finish(cx, Default::default());
+    }
+
+    fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
+        self.lint_if_finish(cx, Default::default());
+    }
+}
+
+fn emit_lints(cx: &LateContext<'_>, (span, item): &(Span, Option<LintPoint>)) {
+    let Some((lint, used_mod, replace_with)) = item else {
+        return;
+    };
+
+    span_lint_and_sugg(
+        cx,
+        lint,
+        *span,
+        format!("used import from `{used_mod}` instead of `{replace_with}`"),
+        format!("consider importing the item from `{replace_with}`"),
+        (*replace_with).to_string(),
+        Applicability::MachineApplicable,
+    );
 }
 
 /// Returns the first named segment of a [`Path`].
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 73a9fe71e00..1cda6f596f4 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -560,7 +560,7 @@ impl<'tcx> LateLintPass<'tcx> for TrimSplitWhitespace {
             && let Some(split_ws_def_id) = tyckres.type_dependent_def_id(expr.hir_id)
             && cx.tcx.is_diagnostic_item(sym::str_split_whitespace, split_ws_def_id)
             && let ExprKind::MethodCall(path, _trim_recv, [], trim_span) = split_recv.kind
-            && let trim_fn_name @ ("trim" | "trim_start" | "trim_end") = path.ident.name.as_str()
+            && let trim_fn_name @ (sym::trim | sym::trim_start | sym::trim_end) = path.ident.name
             && let Some(trim_def_id) = tyckres.type_dependent_def_id(split_recv.hir_id)
             && is_one_of_trim_diagnostic_items(cx, trim_def_id)
         {
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index e3ecd6508bf..5ecbb56925e 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -3,7 +3,7 @@ use clippy_utils::source::{snippet_indent, snippet_with_context};
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::is_type_diagnostic_item;
 
-use clippy_utils::{can_mut_borrow_both, eq_expr_value, is_in_const_context, std_or_core};
+use clippy_utils::{can_mut_borrow_both, eq_expr_value, is_in_const_context, path_to_local, std_or_core};
 use itertools::Itertools;
 
 use rustc_data_structures::fx::FxIndexSet;
@@ -350,12 +350,21 @@ impl<'tcx> IndexBinding<'_, 'tcx> {
                 format!("{lhs_snippet}{rhs_snippet}")
             },
             ExprKind::Path(QPath::Resolved(_, path)) => {
-                let init = self.cx.expr_or_init(expr);
-
                 let Some(first_segment) = path.segments.first() else {
                     return String::new();
                 };
-                if !self.suggest_span.contains(init.span) || !self.is_used_other_than_swapping(first_segment.ident) {
+
+                let init = self.cx.expr_or_init(expr);
+
+                // We skip suggesting a variable binding in any of these cases:
+                // - Variable initialization is outside the suggestion span
+                // - Variable declaration is outside the suggestion span
+                // - Variable is not used as an index or elsewhere later
+                if !self.suggest_span.contains(init.span)
+                    || path_to_local(expr)
+                        .is_some_and(|hir_id| !self.suggest_span.contains(self.cx.tcx.hir_span(hir_id)))
+                    || !self.is_used_other_than_swapping(first_segment.ident)
+                {
                     return String::new();
                 }
 
diff --git a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs
index 96286fcf73d..08f36a2ed5d 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/missing_transmute_annotations.rs
@@ -74,7 +74,7 @@ pub(super) fn check<'tcx>(
         last.ident.span.with_hi(path.span.hi()),
         "transmute used without annotations",
         "consider adding missing annotations",
-        format!("{}::<{from_ty}, {to_ty}>", last.ident.as_str()),
+        format!("{}::<{from_ty}, {to_ty}>", last.ident),
         Applicability::MaybeIncorrect,
     );
     true
diff --git a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
index 004ad03e708..4b23367645e 100644
--- a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
@@ -33,7 +33,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
                 let ltopt = if lt.is_anonymous() {
                     String::new()
                 } else {
-                    format!("{} ", lt.ident.as_str())
+                    format!("{} ", lt.ident)
                 };
 
                 if mut_ty.mutbl == Mutability::Mut {
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
index 019ae16ca85..ae6d8a1c1aa 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
@@ -1,9 +1,14 @@
+use std::iter;
+
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::is_from_proc_macro;
-use clippy_utils::source::{SourceText, SpanRangeExt, indent_of, reindent_multiline};
+use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline};
+use clippy_utils::sugg::Sugg;
+use clippy_utils::ty::expr_type_is_certain;
+use clippy_utils::{is_expr_default, is_from_proc_macro};
 use rustc_errors::Applicability;
 use rustc_hir::{Block, Expr, ExprKind, MatchSource, Node, StmtKind};
 use rustc_lint::LateContext;
+use rustc_span::SyntaxContext;
 
 use super::{UNIT_ARG, utils};
 
@@ -59,7 +64,7 @@ fn is_questionmark_desugar_marked_call(expr: &Expr<'_>) -> bool {
     }
 }
 
-fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Expr<'_>]) {
+fn lint_unit_args<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, args_to_recover: &[&'tcx Expr<'tcx>]) {
     let mut applicability = Applicability::MachineApplicable;
     let (singular, plural) = if args_to_recover.len() > 1 {
         ("", "s")
@@ -100,34 +105,41 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp
 
             let arg_snippets: Vec<_> = args_to_recover
                 .iter()
-                .filter_map(|arg| arg.span.get_source_text(cx))
+                // If the argument is from an expansion and is a `Default::default()`, we skip it
+                .filter(|arg| !arg.span.from_expansion() || !is_expr_default_nested(cx, arg))
+                .filter_map(|arg| get_expr_snippet(cx, arg))
                 .collect();
-            let arg_snippets_without_empty_blocks: Vec<_> = args_to_recover
+
+            // If the argument is an empty block or `Default::default()`, we can replace it with `()`.
+            let arg_snippets_without_redundant_exprs: Vec<_> = args_to_recover
                 .iter()
-                .filter(|arg| !is_empty_block(arg))
-                .filter_map(|arg| arg.span.get_source_text(cx))
+                .filter(|arg| !is_expr_default_nested(cx, arg) && (arg.span.from_expansion() || !is_empty_block(arg)))
+                .filter_map(|arg| get_expr_snippet_with_type_certainty(cx, arg))
                 .collect();
 
             if let Some(call_snippet) = expr.span.get_source_text(cx) {
-                let sugg = fmt_stmts_and_call(
-                    cx,
-                    expr,
-                    &call_snippet,
-                    &arg_snippets,
-                    &arg_snippets_without_empty_blocks,
-                );
-
-                if arg_snippets_without_empty_blocks.is_empty() {
+                if arg_snippets_without_redundant_exprs.is_empty()
+                    && let suggestions = args_to_recover
+                        .iter()
+                        .filter(|arg| !arg.span.from_expansion() || !is_expr_default_nested(cx, arg))
+                        .map(|arg| (arg.span.parent_callsite().unwrap_or(arg.span), "()".to_string()))
+                        .collect::<Vec<_>>()
+                    && !suggestions.is_empty()
+                {
                     db.multipart_suggestion(
                         format!("use {singular}unit literal{plural} instead"),
-                        args_to_recover
-                            .iter()
-                            .map(|arg| (arg.span, "()".to_string()))
-                            .collect::<Vec<_>>(),
+                        suggestions,
                         applicability,
                     );
                 } else {
-                    let plural = arg_snippets_without_empty_blocks.len() > 1;
+                    let plural = arg_snippets_without_redundant_exprs.len() > 1;
+                    let sugg = fmt_stmts_and_call(
+                        cx,
+                        expr,
+                        &call_snippet,
+                        arg_snippets,
+                        arg_snippets_without_redundant_exprs,
+                    );
                     let empty_or_s = if plural { "s" } else { "" };
                     let it_or_them = if plural { "them" } else { "it" };
                     db.span_suggestion(
@@ -144,6 +156,55 @@ fn lint_unit_args(cx: &LateContext<'_>, expr: &Expr<'_>, args_to_recover: &[&Exp
     );
 }
 
+fn is_expr_default_nested<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
+    is_expr_default(cx, expr)
+        || matches!(expr.kind, ExprKind::Block(block, _)
+        if block.expr.is_some() && is_expr_default_nested(cx, block.expr.unwrap()))
+}
+
+enum MaybeTypeUncertain<'tcx> {
+    Certain(Sugg<'tcx>),
+    Uncertain(Sugg<'tcx>),
+}
+
+impl From<MaybeTypeUncertain<'_>> for String {
+    fn from(value: MaybeTypeUncertain<'_>) -> Self {
+        match value {
+            MaybeTypeUncertain::Certain(sugg) => sugg.to_string(),
+            MaybeTypeUncertain::Uncertain(sugg) => format!("let _: () = {sugg}"),
+        }
+    }
+}
+
+fn get_expr_snippet<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<Sugg<'tcx>> {
+    let mut app = Applicability::MachineApplicable;
+    let snip = Sugg::hir_with_context(cx, expr, SyntaxContext::root(), "..", &mut app);
+    if app != Applicability::MachineApplicable {
+        return None;
+    }
+
+    Some(snip)
+}
+
+fn get_expr_snippet_with_type_certainty<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &'tcx Expr<'tcx>,
+) -> Option<MaybeTypeUncertain<'tcx>> {
+    get_expr_snippet(cx, expr).map(|snip| {
+        // If the type of the expression is certain, we can use it directly.
+        // Otherwise, we wrap it in a `let _: () = ...` to ensure the type is correct.
+        if !expr_type_is_certain(cx, expr) && !is_block_with_no_expr(expr) {
+            MaybeTypeUncertain::Uncertain(snip)
+        } else {
+            MaybeTypeUncertain::Certain(snip)
+        }
+    })
+}
+
+fn is_block_with_no_expr(expr: &Expr<'_>) -> bool {
+    matches!(expr.kind, ExprKind::Block(Block { expr: None, .. }, _))
+}
+
 fn is_empty_block(expr: &Expr<'_>) -> bool {
     matches!(
         expr.kind,
@@ -162,23 +223,20 @@ fn fmt_stmts_and_call(
     cx: &LateContext<'_>,
     call_expr: &Expr<'_>,
     call_snippet: &str,
-    args_snippets: &[SourceText],
-    non_empty_block_args_snippets: &[SourceText],
+    args_snippets: Vec<Sugg<'_>>,
+    non_empty_block_args_snippets: Vec<MaybeTypeUncertain<'_>>,
 ) -> String {
     let call_expr_indent = indent_of(cx, call_expr.span).unwrap_or(0);
-    let call_snippet_with_replacements = args_snippets
-        .iter()
-        .fold(call_snippet.to_owned(), |acc, arg| acc.replacen(arg.as_ref(), "()", 1));
+    let call_snippet_with_replacements = args_snippets.into_iter().fold(call_snippet.to_owned(), |acc, arg| {
+        acc.replacen(&arg.to_string(), "()", 1)
+    });
 
-    let mut stmts_and_call = non_empty_block_args_snippets
-        .iter()
-        .map(|it| it.as_ref().to_owned())
-        .collect::<Vec<_>>();
-    stmts_and_call.push(call_snippet_with_replacements);
-    stmts_and_call = stmts_and_call
+    let stmts_and_call = non_empty_block_args_snippets
         .into_iter()
+        .map(Into::into)
+        .chain(iter::once(call_snippet_with_replacements))
         .map(|v| reindent_multiline(&v, true, Some(call_expr_indent)))
-        .collect();
+        .collect::<Vec<_>>();
 
     let mut stmts_and_call_snippet = stmts_and_call.join(&format!("{}{}", ";\n", " ".repeat(call_expr_indent)));
     // expr is not in a block statement or result expression position, wrap in a block
diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
index 5e1cb9e54f5..12cc1093899 100644
--- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -1,11 +1,11 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
 use clippy_utils::macros::{is_panic, root_macro_call_first_node};
-use clippy_utils::{is_res_lang_ctor, paths, peel_blocks};
+use clippy_utils::{is_res_lang_ctor, paths, peel_blocks, sym};
 use hir::{ExprKind, HirId, PatKind};
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::{Span, sym};
+use rustc_span::Span;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -232,8 +232,16 @@ fn is_unreachable_or_panic(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
 fn unpack_call_chain<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
     while let ExprKind::MethodCall(path, receiver, ..) = expr.kind {
         if matches!(
-            path.ident.as_str(),
-            "unwrap" | "expect" | "unwrap_or" | "unwrap_or_else" | "ok" | "is_ok" | "is_err" | "or_else" | "or"
+            path.ident.name,
+            sym::unwrap
+                | sym::expect
+                | sym::unwrap_or
+                | sym::unwrap_or_else
+                | sym::ok
+                | sym::is_ok
+                | sym::is_err
+                | sym::or_else
+                | sym::or
         ) {
             expr = receiver;
         } else {
diff --git a/src/tools/clippy/clippy_lints/src/unused_result_ok.rs b/src/tools/clippy/clippy_lints/src/unused_result_ok.rs
index 958f19d1833..f5ed10fb760 100644
--- a/src/tools/clippy/clippy_lints/src/unused_result_ok.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_result_ok.rs
@@ -1,11 +1,11 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
+use clippy_utils::sym;
 use clippy_utils::ty::is_type_diagnostic_item;
 use rustc_errors::Applicability;
 use rustc_hir::{ExprKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -36,7 +36,7 @@ impl LateLintPass<'_> for UnusedResultOk {
     fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) {
         if let StmtKind::Semi(expr) = stmt.kind
             && let ExprKind::MethodCall(ok_path, recv, [], ..) = expr.kind //check is expr.ok() has type Result<T,E>.ok(, _)
-            && ok_path.ident.as_str() == "ok"
+            && ok_path.ident.name == sym::ok
             && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result)
             && !stmt.span.in_external_macro(cx.sess().source_map())
         {
diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs
index 9859ddfdf7b..3811f0fe6b5 100644
--- a/src/tools/clippy/clippy_lints/src/unused_unit.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs
@@ -100,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedUnit {
         let segments = &poly.trait_ref.path.segments;
 
         if segments.len() == 1
-            && ["Fn", "FnMut", "FnOnce"].contains(&segments[0].ident.name.as_str())
+            && matches!(segments[0].ident.name, sym::Fn | sym::FnMut | sym::FnOnce)
             && let Some(args) = segments[0].args
             && args.parenthesized == GenericArgsParentheses::ParenSugar
             && let constraints = &args.constraints
@@ -109,6 +109,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedUnit {
             && let AssocItemConstraintKind::Equality { term: Term::Ty(hir_ty) } = constraints[0].kind
             && args.span_ext.hi() != poly.span.hi()
             && !hir_ty.span.from_expansion()
+            && args.span_ext.hi() != hir_ty.span.hi()
             && is_unit_ty(hir_ty)
         {
             lint_unneeded_unit_return(cx, hir_ty.span, poly.span);
diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
index 3c23662e9d1..8d873536295 100644
--- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::higher::{VecInitKind, get_vec_init_kind};
 use clippy_utils::source::snippet;
 use clippy_utils::visitors::for_each_local_use_after_expr;
-use clippy_utils::{get_parent_expr, path_to_local_id};
+use clippy_utils::{get_parent_expr, path_to_local_id, sym};
 use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
@@ -202,7 +202,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush {
             if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind
                 && let ExprKind::MethodCall(name, self_arg, [_], _) = expr.kind
                 && path_to_local_id(self_arg, searcher.local_id)
-                && name.ident.as_str() == "push"
+                && name.ident.name == sym::push
             {
                 self.searcher = Some(VecPushSearcher {
                     err_span: searcher.err_span.to(stmt.span),
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index 467811c586b..d9dda6eadb2 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -9,8 +9,8 @@ use rustc_hir::{Item, ItemKind, PathSegment, UseKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
+use rustc_span::BytePos;
 use rustc_span::symbol::kw;
-use rustc_span::{BytePos, sym};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -193,9 +193,7 @@ impl WildcardImports {
 // Allow "...prelude::..::*" imports.
 // Many crates have a prelude, and it is imported as a glob by design.
 fn is_prelude_import(segments: &[PathSegment<'_>]) -> bool {
-    segments
-        .iter()
-        .any(|ps| ps.ident.as_str().contains(sym::prelude.as_str()))
+    segments.iter().any(|ps| ps.ident.as_str().contains("prelude"))
 }
 
 // Allow "super::*" imports in tests.
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index a8758b65c91..d9a007635ca 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -5,8 +5,8 @@ use clippy_utils::source::{SpanRangeExt, expand_past_previous_comma};
 use clippy_utils::{is_in_test, sym};
 use rustc_ast::token::LitKind;
 use rustc_ast::{
-    FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder,
-    FormatTrait,
+    FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatCount, FormatOptions,
+    FormatPlaceholder, FormatTrait,
 };
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, Impl, Item, ItemKind};
@@ -556,12 +556,7 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
     // Decrement the index of the remaining by the number of replaced positional arguments
     if !suggestion.is_empty() {
         for piece in &format_args.template {
-            if let Some((span, index)) = positional_arg_piece_span(piece)
-                && suggestion.iter().all(|(s, _)| *s != span)
-            {
-                let decrement = replaced_position.iter().filter(|i| **i < index).count();
-                suggestion.push((span, format!("{{{}}}", index.saturating_sub(decrement))));
-            }
+            relocalize_format_args_indexes(piece, &mut suggestion, &replaced_position);
         }
     }
 
@@ -574,7 +569,7 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
     }
 }
 
-/// Extract Span and its index from the given `piece`, iff it's positional argument.
+/// Extract Span and its index from the given `piece`, if it's positional argument.
 fn positional_arg_piece_span(piece: &FormatArgsPiece) -> Option<(Span, usize)> {
     match piece {
         FormatArgsPiece::Placeholder(FormatPlaceholder {
@@ -591,6 +586,57 @@ fn positional_arg_piece_span(piece: &FormatArgsPiece) -> Option<(Span, usize)> {
     }
 }
 
+/// Relocalizes the indexes of positional arguments in the format string
+fn relocalize_format_args_indexes(
+    piece: &FormatArgsPiece,
+    suggestion: &mut Vec<(Span, String)>,
+    replaced_position: &[usize],
+) {
+    if let FormatArgsPiece::Placeholder(FormatPlaceholder {
+        argument:
+            FormatArgPosition {
+                index: Ok(index),
+                // Only consider positional arguments
+                kind: FormatArgPositionKind::Number,
+                span: Some(span),
+            },
+        format_options,
+        ..
+    }) = piece
+    {
+        if suggestion.iter().any(|(s, _)| s.overlaps(*span)) {
+            // If the span is already in the suggestion, we don't need to process it again
+            return;
+        }
+
+        // lambda to get the decremented index based on the replaced positions
+        let decremented_index = |index: usize| -> usize {
+            let decrement = replaced_position.iter().filter(|&&i| i < index).count();
+            index - decrement
+        };
+
+        suggestion.push((*span, decremented_index(*index).to_string()));
+
+        // If there are format options, we need to handle them as well
+        if *format_options != FormatOptions::default() {
+            // lambda to process width and precision format counts and add them to the suggestion
+            let mut process_format_count = |count: &Option<FormatCount>, formatter: &dyn Fn(usize) -> String| {
+                if let Some(FormatCount::Argument(FormatArgPosition {
+                    index: Ok(format_arg_index),
+                    kind: FormatArgPositionKind::Number,
+                    span: Some(format_arg_span),
+                })) = count
+                {
+                    suggestion.push((*format_arg_span, formatter(decremented_index(*format_arg_index))));
+                }
+            };
+
+            process_format_count(&format_options.width, &|index: usize| format!("{index}$"));
+            process_format_count(&format_options.precision, &|index: usize| format!(".{index}$"));
+        }
+    }
+}
+
 /// Removes the raw marker, `#`s and quotes from a str, and returns if the literal is raw
 ///
 /// `r#"a"#` -> (`a`, true)
diff --git a/src/tools/clippy/clippy_lints/src/zombie_processes.rs b/src/tools/clippy/clippy_lints/src/zombie_processes.rs
index 09f1084fe70..6ab94a52210 100644
--- a/src/tools/clippy/clippy_lints/src/zombie_processes.rs
+++ b/src/tools/clippy/clippy_lints/src/zombie_processes.rs
@@ -5,7 +5,7 @@ use rustc_ast::Mutability;
 use rustc_ast::visit::visit_opt;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::LocalDefId;
-use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_local};
+use rustc_hir::intravisit::{Visitor, walk_block, walk_expr};
 use rustc_hir::{Expr, ExprKind, HirId, LetStmt, Node, PatKind, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
@@ -69,8 +69,9 @@ impl<'tcx> LateLintPass<'tcx> for ZombieProcesses {
                     let mut vis = WaitFinder {
                         cx,
                         local_id,
+                        create_id: expr.hir_id,
                         body_id: cx.tcx.hir_enclosing_body_owner(expr.hir_id),
-                        state: VisitorState::WalkUpToLocal,
+                        state: VisitorState::WalkUpToCreate,
                         early_return: None,
                         missing_wait_branch: None,
                     };
@@ -131,6 +132,7 @@ struct MaybeWait(Span);
 struct WaitFinder<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
     local_id: HirId,
+    create_id: HirId,
     body_id: LocalDefId,
     state: VisitorState,
     early_return: Option<Span>,
@@ -141,8 +143,8 @@ struct WaitFinder<'a, 'tcx> {
 
 #[derive(PartialEq)]
 enum VisitorState {
-    WalkUpToLocal,
-    LocalFound,
+    WalkUpToCreate,
+    CreateFound,
 }
 
 #[derive(Copy, Clone)]
@@ -155,19 +157,13 @@ impl<'tcx> Visitor<'tcx> for WaitFinder<'_, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
     type Result = ControlFlow<MaybeWait>;
 
-    fn visit_local(&mut self, l: &'tcx LetStmt<'tcx>) -> Self::Result {
-        if self.state == VisitorState::WalkUpToLocal
-            && let PatKind::Binding(_, pat_id, ..) = l.pat.kind
-            && self.local_id == pat_id
-        {
-            self.state = VisitorState::LocalFound;
+    fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> Self::Result {
+        if ex.hir_id == self.create_id {
+            self.state = VisitorState::CreateFound;
+            return Continue(());
         }
 
-        walk_local(self, l)
-    }
-
-    fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) -> Self::Result {
-        if self.state != VisitorState::LocalFound {
+        if self.state != VisitorState::CreateFound {
             return walk_expr(self, ex);
         }
 
diff --git a/src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs b/src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs
index 311f76fee6b..7eeec84720f 100644
--- a/src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs
@@ -45,7 +45,7 @@ impl AlmostStandardFormulation {
 impl<'tcx> LateLintPass<'tcx> for AlmostStandardFormulation {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         let mut check_next = false;
-        if let ItemKind::Static(_, ty, Mutability::Not, _) = item.kind {
+        if let ItemKind::Static(Mutability::Not, _, ty, _) = item.kind {
             let lines = cx
                 .tcx
                 .hir_attrs(item.hir_id())
diff --git a/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs
index 0edeef3ab85..45a866030b2 100644
--- a/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs
@@ -105,7 +105,7 @@ impl_lint_pass!(LintWithoutLintPass => [
 
 impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
-        if let hir::ItemKind::Static(ident, ty, Mutability::Not, body_id) = item.kind {
+        if let hir::ItemKind::Static(Mutability::Not, ident, ty, body_id) = item.kind {
             if is_lint_ref_type(cx, ty) {
                 check_invalid_clippy_version_attribute(cx, item);
 
diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md
index efbacbd72db..1aa16e3943c 100644
--- a/src/tools/clippy/clippy_utils/README.md
+++ b/src/tools/clippy/clippy_utils/README.md
@@ -8,7 +8,7 @@ This crate is only guaranteed to build with this `nightly` toolchain:
 
 <!-- begin autogenerated nightly -->
 ```
-nightly-2025-05-31
+nightly-2025-06-12
 ```
 <!-- end autogenerated nightly -->
 
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index f6ef638e618..c7a2375c8df 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1793,10 +1793,9 @@ pub fn in_automatically_derived(tcx: TyCtxt<'_>, id: HirId) -> bool {
 
 /// Checks if the given `DefId` matches the `libc` item.
 pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: Symbol) -> bool {
-    let path = cx.get_def_path(did);
     // libc is meant to be used as a flat list of names, but they're all actually defined in different
     // modules based on the target platform. Ignore everything but crate name and the item name.
-    path.first().is_some_and(|s| *s == sym::libc) && path.last().copied() == Some(name)
+    cx.tcx.crate_name(did.krate) == sym::libc && cx.tcx.def_path_str(did).ends_with(name.as_str())
 }
 
 /// Returns the list of condition expressions and the list of blocks in a
@@ -3473,3 +3472,15 @@ pub fn desugar_await<'tcx>(expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
         None
     }
 }
+
+/// Checks if the given expression is a call to `Default::default()`.
+pub fn is_expr_default<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool {
+    if let ExprKind::Call(fn_expr, []) = &expr.kind
+        && let ExprKind::Path(qpath) = &fn_expr.kind
+        && let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id)
+    {
+        cx.tcx.is_diagnostic_item(sym::default_fn, def_id)
+    } else {
+        false
+    }
+}
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 8e16f943e9f..e629012b187 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -18,7 +18,7 @@ use rustc_middle::mir::{
 };
 use rustc_middle::traits::{BuiltinImplSource, ImplSource, ObligationCause};
 use rustc_middle::ty::adjustment::PointerCoercion;
-use rustc_middle::ty::{self, GenericArgKind, TraitRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, GenericArgKind, Instance, TraitRef, Ty, TyCtxt};
 use rustc_span::Span;
 use rustc_span::symbol::sym;
 use rustc_trait_selection::traits::{ObligationCtxt, SelectionContext};
@@ -349,7 +349,15 @@ fn check_terminator<'tcx>(
         }
         | TerminatorKind::TailCall { func, args, fn_span: _ } => {
             let fn_ty = func.ty(body, cx.tcx);
-            if let ty::FnDef(fn_def_id, _) = *fn_ty.kind() {
+            if let ty::FnDef(fn_def_id, fn_substs) = fn_ty.kind() {
+                // FIXME: when analyzing a function with generic parameters, we may not have enough information to
+                // resolve to an instance. However, we could check if a host effect predicate can guarantee that
+                // this can be made a `const` call.
+                let fn_def_id = match Instance::try_resolve(cx.tcx, cx.typing_env(), *fn_def_id, fn_substs) {
+                    Ok(Some(fn_inst)) => fn_inst.def_id(),
+                    Ok(None) => return Err((span, format!("cannot resolve instance for {func:?}").into())),
+                    Err(_) => return Err((span, format!("error during instance resolution of {func:?}").into())),
+                };
                 if !is_stable_const_fn(cx, fn_def_id, msrv) {
                     return Err((
                         span,
diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs
index f417530be36..3b58dba5628 100644
--- a/src/tools/clippy/clippy_utils/src/sym.rs
+++ b/src/tools/clippy/clippy_utils/src/sym.rs
@@ -76,7 +76,6 @@ generate! {
     Visitor,
     Weak,
     abs,
-    align_of,
     ambiguous_glob_reexports,
     append,
     arg,
@@ -84,6 +83,7 @@ generate! {
     as_deref,
     as_deref_mut,
     as_mut,
+    as_path,
     assert_failed,
     author,
     borrow,
@@ -121,6 +121,8 @@ generate! {
     copy_to,
     copy_to_nonoverlapping,
     count_ones,
+    create,
+    create_new,
     cycle,
     cyclomatic_complexity,
     de,
@@ -132,7 +134,6 @@ generate! {
     enum_glob_use,
     enumerate,
     err,
-    error,
     exp,
     expect_err,
     expn_data,
@@ -150,8 +151,11 @@ generate! {
     floor_char_boundary,
     fold,
     for_each,
+    from_be_bytes,
     from_bytes_with_nul,
     from_bytes_with_nul_unchecked,
+    from_le_bytes,
+    from_ne_bytes,
     from_ptr,
     from_raw,
     from_ref,
@@ -184,8 +188,10 @@ generate! {
     is_err,
     is_file,
     is_none,
+    is_none_or,
     is_ok,
     is_some,
+    is_some_and,
     isqrt,
     itertools,
     join,
@@ -252,9 +258,12 @@ generate! {
     powi,
     product,
     push,
+    read,
+    read_exact,
     read_line,
     read_to_end,
     read_to_string,
+    read_unaligned,
     redundant_pub_crate,
     regex,
     rem_euclid,
@@ -323,16 +332,22 @@ generate! {
     then_some,
     to_ascii_lowercase,
     to_ascii_uppercase,
+    to_be_bytes,
     to_digit,
+    to_le_bytes,
     to_lowercase,
+    to_ne_bytes,
     to_os_string,
     to_owned,
     to_path_buf,
     to_uppercase,
     tokio,
     trim,
+    trim_end,
     trim_end_matches,
+    trim_start,
     trim_start_matches,
+    truncate,
     unreachable_pub,
     unsafe_removed_from_name,
     unused,
@@ -347,12 +362,15 @@ generate! {
     unwrap_unchecked,
     unzip,
     utils,
+    visit_str,
+    visit_string,
     wake,
     warnings,
     wildcard_imports,
     with_capacity,
     wrapping_offset,
     write,
+    write_unaligned,
     writeln,
     zip,
 }
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs
index 61e70b3fa0b..1f0a0f2b02a 100644
--- a/src/tools/clippy/clippy_utils/src/ty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -1137,21 +1137,38 @@ impl<'tcx> InteriorMut<'tcx> {
 
     /// Check if given type has interior mutability such as [`std::cell::Cell`] or
     /// [`std::cell::RefCell`] etc. and if it does, returns a chain of types that causes
-    /// this type to be interior mutable
+    /// this type to be interior mutable.  False negatives may be expected for infinitely recursive
+    /// types, and `None` will be returned there.
     pub fn interior_mut_ty_chain(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx ty::List<Ty<'tcx>>> {
+        self.interior_mut_ty_chain_inner(cx, ty, 0)
+    }
+
+    fn interior_mut_ty_chain_inner(
+        &mut self,
+        cx: &LateContext<'tcx>,
+        ty: Ty<'tcx>,
+        depth: usize,
+    ) -> Option<&'tcx ty::List<Ty<'tcx>>> {
+        if !cx.tcx.recursion_limit().value_within_limit(depth) {
+            return None;
+        }
+
         match self.tys.entry(ty) {
             Entry::Occupied(o) => return *o.get(),
             // Temporarily insert a `None` to break cycles
             Entry::Vacant(v) => v.insert(None),
         };
+        let depth = depth + 1;
 
         let chain = match *ty.kind() {
-            ty::RawPtr(inner_ty, _) if !self.ignore_pointers => self.interior_mut_ty_chain(cx, inner_ty),
-            ty::Ref(_, inner_ty, _) | ty::Slice(inner_ty) => self.interior_mut_ty_chain(cx, inner_ty),
+            ty::RawPtr(inner_ty, _) if !self.ignore_pointers => self.interior_mut_ty_chain_inner(cx, inner_ty, depth),
+            ty::Ref(_, inner_ty, _) | ty::Slice(inner_ty) => self.interior_mut_ty_chain_inner(cx, inner_ty, depth),
             ty::Array(inner_ty, size) if size.try_to_target_usize(cx.tcx) != Some(0) => {
-                self.interior_mut_ty_chain(cx, inner_ty)
+                self.interior_mut_ty_chain_inner(cx, inner_ty, depth)
             },
-            ty::Tuple(fields) => fields.iter().find_map(|ty| self.interior_mut_ty_chain(cx, ty)),
+            ty::Tuple(fields) => fields
+                .iter()
+                .find_map(|ty| self.interior_mut_ty_chain_inner(cx, ty, depth)),
             ty::Adt(def, _) if def.is_unsafe_cell() => Some(ty::List::empty()),
             ty::Adt(def, args) => {
                 let is_std_collection = matches!(
@@ -1171,16 +1188,17 @@ impl<'tcx> InteriorMut<'tcx> {
 
                 if is_std_collection || def.is_box() {
                     // Include the types from std collections that are behind pointers internally
-                    args.types().find_map(|ty| self.interior_mut_ty_chain(cx, ty))
+                    args.types()
+                        .find_map(|ty| self.interior_mut_ty_chain_inner(cx, ty, depth))
                 } else if self.ignored_def_ids.contains(&def.did()) || def.is_phantom_data() {
                     None
                 } else {
                     def.all_fields()
-                        .find_map(|f| self.interior_mut_ty_chain(cx, f.ty(cx.tcx, args)))
+                        .find_map(|f| self.interior_mut_ty_chain_inner(cx, f.ty(cx.tcx, args), depth))
                 }
             },
             ty::Alias(ty::Projection, _) => match cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty) {
-                Ok(normalized_ty) if ty != normalized_ty => self.interior_mut_ty_chain(cx, normalized_ty),
+                Ok(normalized_ty) if ty != normalized_ty => self.interior_mut_ty_chain_inner(cx, normalized_ty, depth),
                 _ => None,
             },
             _ => None,
@@ -1342,7 +1360,8 @@ pub fn has_non_owning_mutable_access<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'
                 mutability.is_mut() || !pointee_ty.is_freeze(cx.tcx, cx.typing_env())
             },
             ty::Closure(_, closure_args) => {
-                matches!(closure_args.types().next_back(), Some(captures) if has_non_owning_mutable_access_inner(cx, phantoms, captures))
+                matches!(closure_args.types().next_back(),
+                         Some(captures) if has_non_owning_mutable_access_inner(cx, phantoms, captures))
             },
             ty::Tuple(tuple_args) => tuple_args
                 .iter()
diff --git a/src/tools/clippy/rust-toolchain.toml b/src/tools/clippy/rust-toolchain.toml
index b6817d9a146..3fc5a1224a8 100644
--- a/src/tools/clippy/rust-toolchain.toml
+++ b/src/tools/clippy/rust-toolchain.toml
@@ -1,6 +1,6 @@
 [toolchain]
 # begin autogenerated nightly
-channel = "nightly-2025-05-31"
+channel = "nightly-2025-06-12"
 # end autogenerated nightly
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
 profile = "minimal"
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index 78b27e2f613..99a01257a7b 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -273,10 +273,10 @@ fn run_ui_cargo(cx: &TestContext) {
     config.program.input_file_flag = CommandBuilder::cargo().input_file_flag;
     config.program.out_dir_flag = CommandBuilder::cargo().out_dir_flag;
     config.program.args = vec!["clippy".into(), "--color".into(), "never".into(), "--quiet".into()];
-    config
-        .program
-        .envs
-        .push(("RUSTFLAGS".into(), Some("-Dwarnings".into())));
+    config.program.envs.extend([
+        ("RUSTFLAGS".into(), Some("-Dwarnings".into())),
+        ("CARGO_INCREMENTAL".into(), Some("0".into())),
+    ]);
     // We need to do this while we still have a rustc in the `program` field.
     config.fill_host_and_target().unwrap();
     config.program.program.set_file_name(if cfg!(windows) {
diff --git a/src/tools/clippy/tests/symbols-used.rs b/src/tools/clippy/tests/symbols-used.rs
new file mode 100644
index 00000000000..bc0456711fb
--- /dev/null
+++ b/src/tools/clippy/tests/symbols-used.rs
@@ -0,0 +1,81 @@
+// This test checks that all symbols defined in Clippy's `sym.rs` file
+// are used in Clippy. Otherwise, it will fail with a list of symbols
+// which are unused.
+//
+// This test is a no-op if run as part of the compiler test suite
+// and will always succeed.
+
+use std::collections::HashSet;
+use std::ffi::OsStr;
+use std::fs;
+
+use regex::Regex;
+use walkdir::{DirEntry, WalkDir};
+
+const SYM_FILE: &str = "clippy_utils/src/sym.rs";
+
+type Result<T, E = AnyError> = std::result::Result<T, E>;
+type AnyError = Box<dyn std::error::Error>;
+
+#[test]
+#[allow(clippy::case_sensitive_file_extension_comparisons)]
+fn all_symbols_are_used() -> Result<()> {
+    if option_env!("RUSTC_TEST_SUITE").is_some() {
+        return Ok(());
+    }
+
+    // Load all symbols defined in `SYM_FILE`.
+    let content = fs::read_to_string(SYM_FILE)?;
+    let content = content
+        .split_once("generate! {")
+        .ok_or("cannot find symbols start")?
+        .1
+        .split_once("\n}\n")
+        .ok_or("cannot find symbols end")?
+        .0;
+    let mut interned: HashSet<String> = Regex::new(r"(?m)^    (\w+)")
+        .unwrap()
+        .captures_iter(content)
+        .map(|m| m[1].to_owned())
+        .collect();
+
+    // Remove symbols used as `sym::*`.
+    let used_re = Regex::new(r"\bsym::(\w+)\b").unwrap();
+    let rs_ext = OsStr::new("rs");
+    for dir in ["clippy_lints", "clippy_lints_internal", "clippy_utils", "src"] {
+        for file in WalkDir::new(dir)
+            .into_iter()
+            .flatten()
+            .map(DirEntry::into_path)
+            .filter(|p| p.extension() == Some(rs_ext))
+        {
+            for cap in used_re.captures_iter(&fs::read_to_string(file)?) {
+                interned.remove(&cap[1]);
+            }
+        }
+    }
+
+    // Remove symbols used as part of paths.
+    let paths_re = Regex::new(r"path!\(([\w:]+)\)").unwrap();
+    for path in [
+        "clippy_utils/src/paths.rs",
+        "clippy_lints_internal/src/internal_paths.rs",
+    ] {
+        for cap in paths_re.captures_iter(&fs::read_to_string(path)?) {
+            for sym in cap[1].split("::") {
+                interned.remove(sym);
+            }
+        }
+    }
+
+    let mut extra = interned.iter().collect::<Vec<_>>();
+    if !extra.is_empty() {
+        extra.sort_unstable();
+        eprintln!("Unused symbols defined in {SYM_FILE}:");
+        for sym in extra {
+            eprintln!("  - {sym}");
+        }
+        Err(format!("extra symbols found — remove them {SYM_FILE}"))?;
+    }
+    Ok(())
+}
diff --git a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs
index 6a9a49324db..4a179cd929f 100644
--- a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs
+++ b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs
@@ -1,4 +1,5 @@
 #![warn(clippy::await_holding_invalid_type)]
+#![allow(clippy::ip_constant)]
 use std::net::Ipv4Addr;
 
 async fn bad() -> u32 {
diff --git a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr
index deb7f49db9e..c3c88698032 100644
--- a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr
+++ b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.stderr
@@ -1,5 +1,5 @@
 error: holding a disallowed type across an await point `std::string::String`
-  --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:5:9
+  --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:6:9
    |
 LL |     let _x = String::from("hello");
    |         ^^
@@ -9,13 +9,13 @@ LL |     let _x = String::from("hello");
    = help: to override `-D warnings` add `#[allow(clippy::await_holding_invalid_type)]`
 
 error: holding a disallowed type across an await point `std::net::Ipv4Addr`
-  --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:11:9
+  --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:12:9
    |
 LL |     let x = Ipv4Addr::new(127, 0, 0, 1);
    |         ^
 
 error: holding a disallowed type across an await point `std::string::String`
-  --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:35:13
+  --> tests/ui-toml/await_holding_invalid_type/await_holding_invalid_type.rs:36:13
    |
 LL |         let _x = String::from("hi!");
    |             ^^
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs
index 06472a4f5d5..922d30443fc 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.rs
@@ -239,3 +239,40 @@ fn fp_if_let_issue7054() {
 }
 
 fn main() {}
+
+mod issue14873 {
+    fn foo() -> i32 {
+        todo!()
+    }
+
+    macro_rules! qux {
+        ($a:ident, $b:ident, $condition:expr) => {
+            if $condition {
+                "."
+            } else {
+                ""
+            };
+            $a = foo();
+            $b = foo();
+        };
+    }
+
+    fn share_on_bottom() {
+        let mut a = 0;
+        let mut b = 0;
+        if false {
+            qux!(a, b, a == b);
+        } else {
+            qux!(a, b, a != b);
+        };
+
+        if false {
+            qux!(a, b, a == b);
+            let y = 1;
+        } else {
+            qux!(a, b, a != b);
+            let y = 1;
+            //~^ branches_sharing_code
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr
index 648a99c65ed..f437db8b733 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_bottom.stderr
@@ -157,5 +157,20 @@ LL ~     if x == 17 { b = 1; a = 0x99; } else { }
 LL +     a = 0x99;
    |
 
-error: aborting due to 9 previous errors
+error: all if blocks contain the same code at the end
+  --> tests/ui/branches_sharing_code/shared_at_bottom.rs:274:9
+   |
+LL | /             let y = 1;
+LL | |
+LL | |         }
+   | |_________^
+   |
+   = warning: some moved values might need to be renamed to avoid wrong references
+help: consider moving these statements after the if
+   |
+LL ~         }
+LL +         let y = 1;
+   |
+
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs
index 694c67d4c85..dcd77679fc6 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.rs
@@ -124,3 +124,34 @@ fn pf_local_with_inferred_type_issue7053() {
 }
 
 fn main() {}
+
+mod issue14873 {
+    fn foo() -> i32 {
+        todo!()
+    }
+
+    macro_rules! qux {
+        ($a:ident, $b:ident, $condition:expr) => {
+            let $a: i32 = foo();
+            let $b: i32 = foo();
+            if $condition { "." } else { "" }
+        };
+    }
+
+    fn share_on_top() {
+        if false {
+            qux!(a, b, a == b);
+        } else {
+            qux!(a, b, a != b);
+        };
+
+        if false {
+            //~^ branches_sharing_code
+            let x = 1;
+            qux!(a, b, a == b);
+        } else {
+            let x = 1;
+            qux!(a, b, a != b);
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr
index d28e9c7af29..30efb98b3f5 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top.stderr
@@ -125,5 +125,20 @@ note: the lint level is defined here
 LL | #![deny(clippy::branches_sharing_code, clippy::if_same_then_else)]
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 7 previous errors
+error: all if blocks contain the same code at the start
+  --> tests/ui/branches_sharing_code/shared_at_top.rs:148:9
+   |
+LL | /         if false {
+LL | |
+LL | |             let x = 1;
+   | |______________________^
+   |
+   = warning: some moved values might need to be renamed to avoid wrong references
+help: consider moving these statements before the if
+   |
+LL ~         let x = 1;
+LL +         if false {
+   |
+
+error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs
index 75334f70f1f..e848f0601e3 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs
@@ -128,3 +128,42 @@ fn added_note_for_expression_use() -> u32 {
 }
 
 fn main() {}
+
+mod issue14873 {
+    fn foo() -> i32 {
+        todo!()
+    }
+
+    macro_rules! qux {
+        ($a:ident, $b:ident, $condition:expr) => {
+            let mut $a: i32 = foo();
+            let mut $b: i32 = foo();
+            if $condition {
+                "."
+            } else {
+                ""
+            };
+            $a = foo();
+            $b = foo();
+        };
+    }
+
+    fn share_on_top_and_bottom() {
+        if false {
+            qux!(a, b, a == b);
+        } else {
+            qux!(a, b, a != b);
+        };
+
+        if false {
+            //~^ branches_sharing_code
+            let x = 1;
+            qux!(a, b, a == b);
+            let y = 1;
+        } else {
+            let x = 1;
+            qux!(a, b, a != b);
+            let y = 1;
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr
index 2200ab45089..40f3453edb9 100644
--- a/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr
+++ b/src/tools/clippy/tests/ui/branches_sharing_code/shared_at_top_and_bottom.stderr
@@ -159,5 +159,31 @@ LL ~     }
 LL +     x * 4
    |
 
-error: aborting due to 5 previous errors
+error: all if blocks contain the same code at both the start and the end
+  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:158:9
+   |
+LL | /         if false {
+LL | |
+LL | |             let x = 1;
+   | |______________________^
+   |
+note: this code is shared at the end
+  --> tests/ui/branches_sharing_code/shared_at_top_and_bottom.rs:166:9
+   |
+LL | /             let y = 1;
+LL | |         }
+   | |_________^
+   = warning: some moved values might need to be renamed to avoid wrong references
+help: consider moving these statements before the if
+   |
+LL ~         let x = 1;
+LL +         if false {
+   |
+help: consider moving these statements after the if
+   |
+LL ~         }
+LL +         let y = 1;
+   |
+
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/cmp_null.fixed b/src/tools/clippy/tests/ui/cmp_null.fixed
index 140ddb10aeb..04b8ec50160 100644
--- a/src/tools/clippy/tests/ui/cmp_null.fixed
+++ b/src/tools/clippy/tests/ui/cmp_null.fixed
@@ -33,3 +33,9 @@ fn main() {
     let _ = (x as *const ()).is_null();
     //~^ cmp_null
 }
+
+fn issue15010() {
+    let f: *mut i32 = std::ptr::null_mut();
+    debug_assert!(!f.is_null());
+    //~^ cmp_null
+}
diff --git a/src/tools/clippy/tests/ui/cmp_null.rs b/src/tools/clippy/tests/ui/cmp_null.rs
index 16ed17765da..6f7762e6ae8 100644
--- a/src/tools/clippy/tests/ui/cmp_null.rs
+++ b/src/tools/clippy/tests/ui/cmp_null.rs
@@ -33,3 +33,9 @@ fn main() {
     let _ = x as *const () == ptr::null();
     //~^ cmp_null
 }
+
+fn issue15010() {
+    let f: *mut i32 = std::ptr::null_mut();
+    debug_assert!(f != std::ptr::null_mut());
+    //~^ cmp_null
+}
diff --git a/src/tools/clippy/tests/ui/cmp_null.stderr b/src/tools/clippy/tests/ui/cmp_null.stderr
index 6821846d046..8a75b050111 100644
--- a/src/tools/clippy/tests/ui/cmp_null.stderr
+++ b/src/tools/clippy/tests/ui/cmp_null.stderr
@@ -31,5 +31,11 @@ error: comparing with null is better expressed by the `.is_null()` method
 LL |     let _ = x as *const () == ptr::null();
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(x as *const ()).is_null()`
 
-error: aborting due to 5 previous errors
+error: comparing with null is better expressed by the `.is_null()` method
+  --> tests/ui/cmp_null.rs:39:19
+   |
+LL |     debug_assert!(f != std::ptr::null_mut());
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!f.is_null()`
+
+error: aborting due to 6 previous errors
 
diff --git a/src/tools/clippy/tests/ui/coerce_container_to_any.fixed b/src/tools/clippy/tests/ui/coerce_container_to_any.fixed
new file mode 100644
index 00000000000..ae9d3ef9656
--- /dev/null
+++ b/src/tools/clippy/tests/ui/coerce_container_to_any.fixed
@@ -0,0 +1,26 @@
+#![warn(clippy::coerce_container_to_any)]
+
+use std::any::Any;
+
+fn main() {
+    let x: Box<dyn Any> = Box::new(());
+    let ref_x = &x;
+
+    f(&*x);
+    //~^ coerce_container_to_any
+
+    f(&**ref_x);
+    //~^ coerce_container_to_any
+
+    let _: &dyn Any = &*x;
+    //~^ coerce_container_to_any
+
+    f(&42);
+    f(&Box::new(()));
+    f(&Box::new(Box::new(())));
+    f(&**ref_x);
+    f(&*x);
+    let _: &dyn Any = &*x;
+}
+
+fn f(_: &dyn Any) {}
diff --git a/src/tools/clippy/tests/ui/coerce_container_to_any.rs b/src/tools/clippy/tests/ui/coerce_container_to_any.rs
new file mode 100644
index 00000000000..9948bd48e0d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/coerce_container_to_any.rs
@@ -0,0 +1,26 @@
+#![warn(clippy::coerce_container_to_any)]
+
+use std::any::Any;
+
+fn main() {
+    let x: Box<dyn Any> = Box::new(());
+    let ref_x = &x;
+
+    f(&x);
+    //~^ coerce_container_to_any
+
+    f(ref_x);
+    //~^ coerce_container_to_any
+
+    let _: &dyn Any = &x;
+    //~^ coerce_container_to_any
+
+    f(&42);
+    f(&Box::new(()));
+    f(&Box::new(Box::new(())));
+    f(&**ref_x);
+    f(&*x);
+    let _: &dyn Any = &*x;
+}
+
+fn f(_: &dyn Any) {}
diff --git a/src/tools/clippy/tests/ui/coerce_container_to_any.stderr b/src/tools/clippy/tests/ui/coerce_container_to_any.stderr
new file mode 100644
index 00000000000..00ab77e0ce0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/coerce_container_to_any.stderr
@@ -0,0 +1,23 @@
+error: coercing `&std::boxed::Box<dyn std::any::Any>` to `&dyn Any`
+  --> tests/ui/coerce_container_to_any.rs:9:7
+   |
+LL |     f(&x);
+   |       ^^ help: consider dereferencing: `&*x`
+   |
+   = note: `-D clippy::coerce-container-to-any` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::coerce_container_to_any)]`
+
+error: coercing `&std::boxed::Box<dyn std::any::Any>` to `&dyn Any`
+  --> tests/ui/coerce_container_to_any.rs:12:7
+   |
+LL |     f(ref_x);
+   |       ^^^^^ help: consider dereferencing: `&**ref_x`
+
+error: coercing `&std::boxed::Box<dyn std::any::Any>` to `&dyn Any`
+  --> tests/ui/coerce_container_to_any.rs:15:23
+   |
+LL |     let _: &dyn Any = &x;
+   |                       ^^ help: consider dereferencing: `&*x`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/crashes/ice-14935.rs b/src/tools/clippy/tests/ui/crashes/ice-14935.rs
new file mode 100644
index 00000000000..74cda9aae53
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-14935.rs
@@ -0,0 +1,27 @@
+//@check-pass
+#![warn(clippy::mutable_key_type)]
+
+use std::marker::PhantomData;
+
+trait Group {
+    type ExposantSet: Group;
+}
+
+struct Pow<T: Group> {
+    exposant: Box<Pow<T::ExposantSet>>,
+    _p: PhantomData<T>,
+}
+
+impl<T: Group> Pow<T> {
+    fn is_zero(&self) -> bool {
+        false
+    }
+    fn normalize(&self) {
+        #[expect(clippy::if_same_then_else)]
+        if self.is_zero() {
+        } else if false {
+        }
+    }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-9463.rs b/src/tools/clippy/tests/ui/crashes/ice-9463.rs
index 93808e0f892..cfa6cdac6fa 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-9463.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-9463.rs
@@ -1,8 +1,7 @@
-#![deny(arithmetic_overflow)]
+//@check-pass
+
 fn main() {
     let _x = -1_i32 >> -1;
-    //~^ ERROR: this arithmetic operation will overflow
+    #[expect(overflowing_literals)]
     let _y = 1u32 >> 10000000000000u32;
-    //~^ ERROR: this arithmetic operation will overflow
-    //~| ERROR: literal out of range
 }
diff --git a/src/tools/clippy/tests/ui/crashes/ice-9463.stderr b/src/tools/clippy/tests/ui/crashes/ice-9463.stderr
deleted file mode 100644
index 9a3a5e444ad..00000000000
--- a/src/tools/clippy/tests/ui/crashes/ice-9463.stderr
+++ /dev/null
@@ -1,29 +0,0 @@
-error: this arithmetic operation will overflow
-  --> tests/ui/crashes/ice-9463.rs:3:14
-   |
-LL |     let _x = -1_i32 >> -1;
-   |              ^^^^^^^^^^^^ attempt to shift right by `-1_i32`, which would overflow
-   |
-note: the lint level is defined here
-  --> tests/ui/crashes/ice-9463.rs:1:9
-   |
-LL | #![deny(arithmetic_overflow)]
-   |         ^^^^^^^^^^^^^^^^^^^
-
-error: this arithmetic operation will overflow
-  --> tests/ui/crashes/ice-9463.rs:5:14
-   |
-LL |     let _y = 1u32 >> 10000000000000u32;
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to shift right by `1316134912_u32`, which would overflow
-
-error: literal out of range for `u32`
-  --> tests/ui/crashes/ice-9463.rs:5:22
-   |
-LL |     let _y = 1u32 >> 10000000000000u32;
-   |                      ^^^^^^^^^^^^^^^^^
-   |
-   = note: the literal `10000000000000u32` does not fit into the type `u32` whose range is `0..=4294967295`
-   = note: `#[deny(overflowing_literals)]` on by default
-
-error: aborting due to 3 previous errors
-
diff --git a/src/tools/clippy/tests/ui/crashes/ice-rust-107877.rs b/src/tools/clippy/tests/ui/crashes/ice-rust-107877.rs
index 55fe418bed1..dccb0cf8ac1 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-rust-107877.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-rust-107877.rs
@@ -4,6 +4,7 @@
 
 struct Foo;
 
+#[allow(clippy::infallible_try_from)]
 impl<'a> std::convert::TryFrom<&'a String> for Foo {
     type Error = std::convert::Infallible;
 
diff --git a/src/tools/clippy/tests/ui/create_dir.fixed b/src/tools/clippy/tests/ui/create_dir.fixed
index 4a5b1b77be6..d4b8f8b4d07 100644
--- a/src/tools/clippy/tests/ui/create_dir.fixed
+++ b/src/tools/clippy/tests/ui/create_dir.fixed
@@ -7,12 +7,31 @@ fn create_dir() {}
 
 fn main() {
     // Should be warned
-    create_dir_all("foo");
+    std::fs::create_dir_all("foo");
     //~^ create_dir
-    create_dir_all("bar").unwrap();
+    std::fs::create_dir_all("bar").unwrap();
     //~^ create_dir
 
     // Shouldn't be warned
     create_dir();
     std::fs::create_dir_all("foobar");
 }
+
+mod issue14994 {
+    fn with_no_prefix() {
+        use std::fs::create_dir;
+        std::fs::create_dir_all("some/dir").unwrap();
+        //~^ create_dir
+    }
+
+    fn with_fs_prefix() {
+        use std::fs;
+        fs::create_dir_all("/some/dir").unwrap();
+        //~^ create_dir
+    }
+
+    fn with_full_prefix() {
+        std::fs::create_dir_all("/some/dir").unwrap();
+        //~^ create_dir
+    }
+}
diff --git a/src/tools/clippy/tests/ui/create_dir.rs b/src/tools/clippy/tests/ui/create_dir.rs
index bf185ba3a7c..21e0bdba03b 100644
--- a/src/tools/clippy/tests/ui/create_dir.rs
+++ b/src/tools/clippy/tests/ui/create_dir.rs
@@ -16,3 +16,22 @@ fn main() {
     create_dir();
     std::fs::create_dir_all("foobar");
 }
+
+mod issue14994 {
+    fn with_no_prefix() {
+        use std::fs::create_dir;
+        create_dir("some/dir").unwrap();
+        //~^ create_dir
+    }
+
+    fn with_fs_prefix() {
+        use std::fs;
+        fs::create_dir("/some/dir").unwrap();
+        //~^ create_dir
+    }
+
+    fn with_full_prefix() {
+        std::fs::create_dir("/some/dir").unwrap();
+        //~^ create_dir
+    }
+}
diff --git a/src/tools/clippy/tests/ui/create_dir.stderr b/src/tools/clippy/tests/ui/create_dir.stderr
index 51d6ac686e0..e3ca0e7255c 100644
--- a/src/tools/clippy/tests/ui/create_dir.stderr
+++ b/src/tools/clippy/tests/ui/create_dir.stderr
@@ -8,9 +8,8 @@ LL |     std::fs::create_dir("foo");
    = help: to override `-D warnings` add `#[allow(clippy::create_dir)]`
 help: consider calling `std::fs::create_dir_all` instead
    |
-LL -     std::fs::create_dir("foo");
-LL +     create_dir_all("foo");
-   |
+LL |     std::fs::create_dir_all("foo");
+   |                        ++++
 
 error: calling `std::fs::create_dir` where there may be a better way
   --> tests/ui/create_dir.rs:12:5
@@ -20,9 +19,41 @@ LL |     std::fs::create_dir("bar").unwrap();
    |
 help: consider calling `std::fs::create_dir_all` instead
    |
-LL -     std::fs::create_dir("bar").unwrap();
-LL +     create_dir_all("bar").unwrap();
+LL |     std::fs::create_dir_all("bar").unwrap();
+   |                        ++++
+
+error: calling `std::fs::create_dir` where there may be a better way
+  --> tests/ui/create_dir.rs:23:9
+   |
+LL |         create_dir("some/dir").unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider calling `std::fs::create_dir_all` instead
+   |
+LL |         std::fs::create_dir_all("some/dir").unwrap();
+   |         +++++++++          ++++
+
+error: calling `std::fs::create_dir` where there may be a better way
+  --> tests/ui/create_dir.rs:29:9
+   |
+LL |         fs::create_dir("/some/dir").unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider calling `std::fs::create_dir_all` instead
+   |
+LL |         fs::create_dir_all("/some/dir").unwrap();
+   |                       ++++
+
+error: calling `std::fs::create_dir` where there may be a better way
+  --> tests/ui/create_dir.rs:34:9
+   |
+LL |         std::fs::create_dir("/some/dir").unwrap();
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: consider calling `std::fs::create_dir_all` instead
    |
+LL |         std::fs::create_dir_all("/some/dir").unwrap();
+   |                            ++++
 
-error: aborting due to 2 previous errors
+error: aborting due to 5 previous errors
 
diff --git a/src/tools/clippy/tests/ui/disallowed_names.rs b/src/tools/clippy/tests/ui/disallowed_names.rs
index 30fbdbc1fdc..15bb6734997 100644
--- a/src/tools/clippy/tests/ui/disallowed_names.rs
+++ b/src/tools/clippy/tests/ui/disallowed_names.rs
@@ -1,3 +1,4 @@
+//@aux-build:proc_macros.rs
 #![allow(
     dead_code,
     clippy::needless_if,
@@ -9,6 +10,9 @@
 )]
 #![warn(clippy::disallowed_names)]
 
+extern crate proc_macros;
+use proc_macros::{external, with_span};
+
 fn test(foo: ()) {}
 //~^ disallowed_names
 
@@ -66,6 +70,17 @@ fn issue_1647_ref_mut() {
     //~^ disallowed_names
 }
 
+pub fn issue_14958_proc_macro() {
+    // does not lint macro-generated code
+    external! {
+        let foo = 0;
+    }
+    with_span! {
+        span
+        let foo = 0;
+    }
+}
+
 #[cfg(test)]
 mod tests {
     fn issue_7305() {
diff --git a/src/tools/clippy/tests/ui/disallowed_names.stderr b/src/tools/clippy/tests/ui/disallowed_names.stderr
index 09398ebbab7..b43d1b3ebfa 100644
--- a/src/tools/clippy/tests/ui/disallowed_names.stderr
+++ b/src/tools/clippy/tests/ui/disallowed_names.stderr
@@ -1,5 +1,5 @@
 error: use of a disallowed/placeholder name `foo`
-  --> tests/ui/disallowed_names.rs:12:9
+  --> tests/ui/disallowed_names.rs:16:9
    |
 LL | fn test(foo: ()) {}
    |         ^^^
@@ -8,79 +8,79 @@ LL | fn test(foo: ()) {}
    = help: to override `-D warnings` add `#[allow(clippy::disallowed_names)]`
 
 error: use of a disallowed/placeholder name `foo`
-  --> tests/ui/disallowed_names.rs:16:9
+  --> tests/ui/disallowed_names.rs:20:9
    |
 LL |     let foo = 42;
    |         ^^^
 
 error: use of a disallowed/placeholder name `baz`
-  --> tests/ui/disallowed_names.rs:19:9
+  --> tests/ui/disallowed_names.rs:23:9
    |
 LL |     let baz = 42;
    |         ^^^
 
 error: use of a disallowed/placeholder name `quux`
-  --> tests/ui/disallowed_names.rs:22:9
+  --> tests/ui/disallowed_names.rs:26:9
    |
 LL |     let quux = 42;
    |         ^^^^
 
 error: use of a disallowed/placeholder name `foo`
-  --> tests/ui/disallowed_names.rs:35:10
+  --> tests/ui/disallowed_names.rs:39:10
    |
 LL |         (foo, Some(baz), quux @ Some(_)) => (),
    |          ^^^
 
 error: use of a disallowed/placeholder name `baz`
-  --> tests/ui/disallowed_names.rs:35:20
+  --> tests/ui/disallowed_names.rs:39:20
    |
 LL |         (foo, Some(baz), quux @ Some(_)) => (),
    |                    ^^^
 
 error: use of a disallowed/placeholder name `quux`
-  --> tests/ui/disallowed_names.rs:35:26
+  --> tests/ui/disallowed_names.rs:39:26
    |
 LL |         (foo, Some(baz), quux @ Some(_)) => (),
    |                          ^^^^
 
 error: use of a disallowed/placeholder name `foo`
-  --> tests/ui/disallowed_names.rs:43:19
+  --> tests/ui/disallowed_names.rs:47:19
    |
 LL | fn issue_1647(mut foo: u8) {
    |                   ^^^
 
 error: use of a disallowed/placeholder name `baz`
-  --> tests/ui/disallowed_names.rs:46:13
+  --> tests/ui/disallowed_names.rs:50:13
    |
 LL |     let mut baz = 0;
    |             ^^^
 
 error: use of a disallowed/placeholder name `quux`
-  --> tests/ui/disallowed_names.rs:49:21
+  --> tests/ui/disallowed_names.rs:53:21
    |
 LL |     if let Some(mut quux) = Some(42) {}
    |                     ^^^^
 
 error: use of a disallowed/placeholder name `baz`
-  --> tests/ui/disallowed_names.rs:54:13
+  --> tests/ui/disallowed_names.rs:58:13
    |
 LL |     let ref baz = 0;
    |             ^^^
 
 error: use of a disallowed/placeholder name `quux`
-  --> tests/ui/disallowed_names.rs:57:21
+  --> tests/ui/disallowed_names.rs:61:21
    |
 LL |     if let Some(ref quux) = Some(42) {}
    |                     ^^^^
 
 error: use of a disallowed/placeholder name `baz`
-  --> tests/ui/disallowed_names.rs:62:17
+  --> tests/ui/disallowed_names.rs:66:17
    |
 LL |     let ref mut baz = 0;
    |                 ^^^
 
 error: use of a disallowed/placeholder name `quux`
-  --> tests/ui/disallowed_names.rs:65:25
+  --> tests/ui/disallowed_names.rs:69:25
    |
 LL |     if let Some(ref mut quux) = Some(42) {}
    |                         ^^^^
diff --git a/src/tools/clippy/tests/ui/doc_suspicious_footnotes.fixed b/src/tools/clippy/tests/ui/doc_suspicious_footnotes.fixed
new file mode 100644
index 00000000000..9ed3fd4ef31
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc_suspicious_footnotes.fixed
@@ -0,0 +1,186 @@
+#![warn(clippy::doc_suspicious_footnotes)]
+#![allow(clippy::needless_raw_string_hashes)]
+//! This is not a footnote[^1].
+//!
+//! [^1]: <!-- description -->
+//~^ doc_suspicious_footnotes
+//!
+//! This is not a footnote[^either], but it doesn't warn.
+//!
+//! This is not a footnote\[^1], but it also doesn't warn.
+//!
+//! This is not a footnote[^1\], but it also doesn't warn.
+//!
+//! This is not a `footnote[^1]`, but it also doesn't warn.
+//!
+//! This is a footnote[^2].
+//!
+//! [^2]: hello world
+
+/// This is not a footnote[^1].
+///
+/// [^1]: <!-- description -->
+//~^ doc_suspicious_footnotes
+///
+/// This is not a footnote[^either], but it doesn't warn.
+///
+/// This is not a footnote\[^1], but it also doesn't warn.
+///
+/// This is not a footnote[^1\], but it also doesn't warn.
+///
+/// This is not a `footnote[^1]`, but it also doesn't warn.
+///
+/// This is a footnote[^2].
+///
+/// [^2]: hello world
+pub fn footnotes() {
+    // test code goes here
+}
+
+pub struct Foo;
+#[rustfmt::skip]
+impl Foo {
+    #[doc = r#"This is not a footnote[^1].
+
+[^1]: <!-- description -->"#]
+    //~^ doc_suspicious_footnotes
+    #[doc = r#""#]
+    #[doc = r#"This is not a footnote[^either], but it doesn't warn."#]
+    #[doc = r#""#]
+    #[doc = r#"This is not a footnote\[^1], but it also doesn't warn."#]
+    #[doc = r#""#]
+    #[doc = r#"This is not a footnote[^1\], but it also doesn't warn."#]
+    #[doc = r#""#]
+    #[doc = r#"This is not a `footnote[^1]`, but it also doesn't warn."#]
+    #[doc = r#""#]
+    #[doc = r#"This is a footnote[^2]."#]
+    #[doc = r#""#]
+    #[doc = r#"[^2]: hello world"#]
+    pub fn footnotes() {
+        // test code goes here
+    }
+    #[doc = r#"This is not a footnote[^1].
+
+    This is not a footnote[^either], but it doesn't warn.
+
+    This is not a footnote\[^1], but it also doesn't warn.
+
+    This is not a footnote[^1\], but it also doesn't warn.
+
+    This is not a `footnote[^1]`, but it also doesn't warn.
+
+    This is a footnote[^2].
+
+    [^2]: hello world
+    
+
+[^1]: <!-- description -->"#]
+    //~^^^^^^^^^^^^^^ doc_suspicious_footnotes
+    pub fn footnotes2() {
+        // test code goes here
+    }
+    #[cfg_attr(
+        not(FALSE),
+        doc = r#"This is not a footnote[^1].
+
+This is not a footnote[^either], but it doesn't warn.
+
+[^1]: <!-- description -->"#
+    //~^ doc_suspicious_footnotes
+    )]
+    pub fn footnotes3() {
+        // test code goes here
+    }
+    #[doc = "My footnote [^foot\note]"]
+    pub fn footnote4() {
+        // test code goes here
+    }
+    #[doc = "Hihi"]pub fn footnote5() {
+        // test code goes here
+    }
+}
+
+#[doc = r#"This is not a footnote[^1].
+
+[^1]: <!-- description -->"#]
+//~^ doc_suspicious_footnotes
+#[doc = r""]
+#[doc = r"This is not a footnote[^either], but it doesn't warn."]
+#[doc = r""]
+#[doc = r"This is not a footnote\[^1], but it also doesn't warn."]
+#[doc = r""]
+#[doc = r"This is not a footnote[^1\], but it also doesn't warn."]
+#[doc = r""]
+#[doc = r"This is not a `footnote[^1]`, but it also doesn't warn."]
+#[doc = r""]
+#[doc = r"This is a footnote[^2]."]
+#[doc = r""]
+#[doc = r"[^2]: hello world"]
+pub fn footnotes_attrs() {
+    // test code goes here
+}
+
+pub mod multiline {
+    /*!
+     * This is not a footnote[^1]. //~ doc_suspicious_footnotes
+     *
+     * This is not a footnote\[^1], but it doesn't warn.
+     *
+     * This is a footnote[^2].
+     *
+     * These give weird results, but correct ones, so it works.
+     *
+     * [^2]: hello world
+     */
+/*! [^1]: <!-- description --> */
+    /**
+     * This is not a footnote[^1]. //~ doc_suspicious_footnotes
+     *
+     * This is not a footnote\[^1], but it doesn't warn.
+     *
+     * This is a footnote[^2].
+     *
+     * These give weird results, but correct ones, so it works.
+     *
+     * [^2]: hello world
+     */
+/** [^1]: <!-- description --> */
+    pub fn foo() {}
+}
+
+/// This is not a footnote [^1]
+///
+/// [^1]: <!-- description -->
+//~^ doc_suspicious_footnotes
+///
+/// This one is [^2]
+///
+/// [^2]: contents
+#[doc = r#"This is not a footnote [^3]
+
+[^3]: <!-- description -->"#]
+//~^ doc_suspicious_footnotes
+#[doc = ""]
+#[doc = "This one is [^4]"]
+#[doc = ""]
+#[doc = "[^4]: contents"]
+pub struct MultiFragmentFootnote;
+
+#[doc(inline)]
+/// This is not a footnote [^5]
+///
+/// [^5]: <!-- description -->
+//~^ doc_suspicious_footnotes
+///
+/// This one is [^6]
+///
+/// [^6]: contents
+#[doc = r#"This is not a footnote [^7]
+
+[^7]: <!-- description -->"#]
+//~^ doc_suspicious_footnotes
+#[doc = ""]
+#[doc = "This one is [^8]"]
+#[doc = ""]
+#[doc = "[^8]: contents"]
+pub use MultiFragmentFootnote as OtherInlinedFootnote;
diff --git a/src/tools/clippy/tests/ui/doc_suspicious_footnotes.rs b/src/tools/clippy/tests/ui/doc_suspicious_footnotes.rs
new file mode 100644
index 00000000000..9a8d0dcf475
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc_suspicious_footnotes.rs
@@ -0,0 +1,162 @@
+#![warn(clippy::doc_suspicious_footnotes)]
+#![allow(clippy::needless_raw_string_hashes)]
+//! This is not a footnote[^1].
+//~^ doc_suspicious_footnotes
+//!
+//! This is not a footnote[^either], but it doesn't warn.
+//!
+//! This is not a footnote\[^1], but it also doesn't warn.
+//!
+//! This is not a footnote[^1\], but it also doesn't warn.
+//!
+//! This is not a `footnote[^1]`, but it also doesn't warn.
+//!
+//! This is a footnote[^2].
+//!
+//! [^2]: hello world
+
+/// This is not a footnote[^1].
+//~^ doc_suspicious_footnotes
+///
+/// This is not a footnote[^either], but it doesn't warn.
+///
+/// This is not a footnote\[^1], but it also doesn't warn.
+///
+/// This is not a footnote[^1\], but it also doesn't warn.
+///
+/// This is not a `footnote[^1]`, but it also doesn't warn.
+///
+/// This is a footnote[^2].
+///
+/// [^2]: hello world
+pub fn footnotes() {
+    // test code goes here
+}
+
+pub struct Foo;
+#[rustfmt::skip]
+impl Foo {
+    #[doc = r#"This is not a footnote[^1]."#]
+    //~^ doc_suspicious_footnotes
+    #[doc = r#""#]
+    #[doc = r#"This is not a footnote[^either], but it doesn't warn."#]
+    #[doc = r#""#]
+    #[doc = r#"This is not a footnote\[^1], but it also doesn't warn."#]
+    #[doc = r#""#]
+    #[doc = r#"This is not a footnote[^1\], but it also doesn't warn."#]
+    #[doc = r#""#]
+    #[doc = r#"This is not a `footnote[^1]`, but it also doesn't warn."#]
+    #[doc = r#""#]
+    #[doc = r#"This is a footnote[^2]."#]
+    #[doc = r#""#]
+    #[doc = r#"[^2]: hello world"#]
+    pub fn footnotes() {
+        // test code goes here
+    }
+    #[doc = "This is not a footnote[^1].
+
+    This is not a footnote[^either], but it doesn't warn.
+
+    This is not a footnote\\[^1], but it also doesn't warn.
+
+    This is not a footnote[^1\\], but it also doesn't warn.
+
+    This is not a `footnote[^1]`, but it also doesn't warn.
+
+    This is a footnote[^2].
+
+    [^2]: hello world
+    "]
+    //~^^^^^^^^^^^^^^ doc_suspicious_footnotes
+    pub fn footnotes2() {
+        // test code goes here
+    }
+    #[cfg_attr(
+        not(FALSE),
+        doc = "This is not a footnote[^1].\n\nThis is not a footnote[^either], but it doesn't warn."
+    //~^ doc_suspicious_footnotes
+    )]
+    pub fn footnotes3() {
+        // test code goes here
+    }
+    #[doc = "My footnote [^foot\note]"]
+    pub fn footnote4() {
+        // test code goes here
+    }
+    #[doc = "Hihi"]pub fn footnote5() {
+        // test code goes here
+    }
+}
+
+#[doc = r"This is not a footnote[^1]."]
+//~^ doc_suspicious_footnotes
+#[doc = r""]
+#[doc = r"This is not a footnote[^either], but it doesn't warn."]
+#[doc = r""]
+#[doc = r"This is not a footnote\[^1], but it also doesn't warn."]
+#[doc = r""]
+#[doc = r"This is not a footnote[^1\], but it also doesn't warn."]
+#[doc = r""]
+#[doc = r"This is not a `footnote[^1]`, but it also doesn't warn."]
+#[doc = r""]
+#[doc = r"This is a footnote[^2]."]
+#[doc = r""]
+#[doc = r"[^2]: hello world"]
+pub fn footnotes_attrs() {
+    // test code goes here
+}
+
+pub mod multiline {
+    /*!
+     * This is not a footnote[^1]. //~ doc_suspicious_footnotes
+     *
+     * This is not a footnote\[^1], but it doesn't warn.
+     *
+     * This is a footnote[^2].
+     *
+     * These give weird results, but correct ones, so it works.
+     *
+     * [^2]: hello world
+     */
+    /**
+     * This is not a footnote[^1]. //~ doc_suspicious_footnotes
+     *
+     * This is not a footnote\[^1], but it doesn't warn.
+     *
+     * This is a footnote[^2].
+     *
+     * These give weird results, but correct ones, so it works.
+     *
+     * [^2]: hello world
+     */
+    pub fn foo() {}
+}
+
+/// This is not a footnote [^1]
+//~^ doc_suspicious_footnotes
+///
+/// This one is [^2]
+///
+/// [^2]: contents
+#[doc = "This is not a footnote [^3]"]
+//~^ doc_suspicious_footnotes
+#[doc = ""]
+#[doc = "This one is [^4]"]
+#[doc = ""]
+#[doc = "[^4]: contents"]
+pub struct MultiFragmentFootnote;
+
+#[doc(inline)]
+/// This is not a footnote [^5]
+//~^ doc_suspicious_footnotes
+///
+/// This one is [^6]
+///
+/// [^6]: contents
+#[doc = "This is not a footnote [^7]"]
+//~^ doc_suspicious_footnotes
+#[doc = ""]
+#[doc = "This one is [^8]"]
+#[doc = ""]
+#[doc = "[^8]: contents"]
+pub use MultiFragmentFootnote as OtherInlinedFootnote;
diff --git a/src/tools/clippy/tests/ui/doc_suspicious_footnotes.stderr b/src/tools/clippy/tests/ui/doc_suspicious_footnotes.stderr
new file mode 100644
index 00000000000..4f920f37a62
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc_suspicious_footnotes.stderr
@@ -0,0 +1,179 @@
+error: looks like a footnote ref, but has no matching footnote
+  --> tests/ui/doc_suspicious_footnotes.rs:3:27
+   |
+LL | //! This is not a footnote[^1].
+   |                           ^^^^
+   |
+   = note: `-D clippy::doc-suspicious-footnotes` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::doc_suspicious_footnotes)]`
+help: add footnote definition
+   |
+LL ~ //! This is not a footnote[^1].
+LL + //!
+LL + //! [^1]: <!-- description -->
+   |
+
+error: looks like a footnote ref, but has no matching footnote
+  --> tests/ui/doc_suspicious_footnotes.rs:18:27
+   |
+LL | /// This is not a footnote[^1].
+   |                           ^^^^
+   |
+help: add footnote definition
+   |
+LL ~ /// This is not a footnote[^1].
+LL + ///
+LL + /// [^1]: <!-- description -->
+   |
+
+error: looks like a footnote ref, but has no matching footnote
+  --> tests/ui/doc_suspicious_footnotes.rs:39:13
+   |
+LL |     #[doc = r#"This is not a footnote[^1]."#]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: add footnote definition
+   |
+LL ~     #[doc = r#"This is not a footnote[^1].
+LL + 
+LL ~ [^1]: <!-- description -->"#]
+   |
+
+error: looks like a footnote ref, but has no matching footnote
+  --> tests/ui/doc_suspicious_footnotes.rs:56:13
+   |
+LL |       #[doc = "This is not a footnote[^1].
+   |  _____________^
+LL | |
+LL | |     This is not a footnote[^either], but it doesn't warn.
+...  |
+LL | |     [^2]: hello world
+LL | |     "]
+   | |_____^
+   |
+help: add footnote definition
+   |
+LL ~     #[doc = r#"This is not a footnote[^1].
+LL + 
+LL +     This is not a footnote[^either], but it doesn't warn.
+LL + 
+LL +     This is not a footnote\[^1], but it also doesn't warn.
+LL + 
+LL +     This is not a footnote[^1\], but it also doesn't warn.
+LL + 
+LL +     This is not a `footnote[^1]`, but it also doesn't warn.
+LL + 
+LL +     This is a footnote[^2].
+LL + 
+LL +     [^2]: hello world
+LL +     
+LL + 
+LL ~ [^1]: <!-- description -->"#]
+   |
+
+error: looks like a footnote ref, but has no matching footnote
+  --> tests/ui/doc_suspicious_footnotes.rs:76:38
+   |
+LL |         doc = "This is not a footnote[^1].\n\nThis is not a footnote[^either], but it doesn't warn."
+   |                                      ^^^^
+   |
+help: add footnote definition
+   |
+LL ~         doc = r#"This is not a footnote[^1].
+LL + 
+LL + This is not a footnote[^either], but it doesn't warn.
+LL + 
+LL + [^1]: <!-- description -->"#
+   |
+
+error: looks like a footnote ref, but has no matching footnote
+  --> tests/ui/doc_suspicious_footnotes.rs:91:9
+   |
+LL | #[doc = r"This is not a footnote[^1]."]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: add footnote definition
+   |
+LL ~ #[doc = r#"This is not a footnote[^1].
+LL + 
+LL ~ [^1]: <!-- description -->"#]
+   |
+
+error: looks like a footnote ref, but has no matching footnote
+  --> tests/ui/doc_suspicious_footnotes.rs:111:30
+   |
+LL |      * This is not a footnote[^1].
+   |                              ^^^^
+   |
+help: add footnote definition
+   |
+LL ~      */
+LL + /*! [^1]: <!-- description --> */
+   |
+
+error: looks like a footnote ref, but has no matching footnote
+  --> tests/ui/doc_suspicious_footnotes.rs:122:30
+   |
+LL |      * This is not a footnote[^1].
+   |                              ^^^^
+   |
+help: add footnote definition
+   |
+LL ~      */
+LL + /** [^1]: <!-- description --> */
+   |
+
+error: looks like a footnote ref, but has no matching footnote
+  --> tests/ui/doc_suspicious_footnotes.rs:135:28
+   |
+LL | /// This is not a footnote [^1]
+   |                            ^^^^
+   |
+help: add footnote definition
+   |
+LL ~ /// This is not a footnote [^1]
+LL + ///
+LL + /// [^1]: <!-- description -->
+   |
+
+error: looks like a footnote ref, but has no matching footnote
+  --> tests/ui/doc_suspicious_footnotes.rs:141:33
+   |
+LL | #[doc = "This is not a footnote [^3]"]
+   |                                 ^^^^
+   |
+help: add footnote definition
+   |
+LL ~ #[doc = r#"This is not a footnote [^3]
+LL + 
+LL ~ [^3]: <!-- description -->"#]
+   |
+
+error: looks like a footnote ref, but has no matching footnote
+  --> tests/ui/doc_suspicious_footnotes.rs:150:28
+   |
+LL | /// This is not a footnote [^5]
+   |                            ^^^^
+   |
+help: add footnote definition
+   |
+LL ~ /// This is not a footnote [^5]
+LL + ///
+LL + /// [^5]: <!-- description -->
+   |
+
+error: looks like a footnote ref, but has no matching footnote
+  --> tests/ui/doc_suspicious_footnotes.rs:156:33
+   |
+LL | #[doc = "This is not a footnote [^7]"]
+   |                                 ^^^^
+   |
+help: add footnote definition
+   |
+LL ~ #[doc = r#"This is not a footnote [^7]
+LL + 
+LL ~ [^7]: <!-- description -->"#]
+   |
+
+error: aborting due to 12 previous errors
+
diff --git a/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.rs b/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.rs
new file mode 100644
index 00000000000..4f75ad94eaf
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.rs
@@ -0,0 +1,4 @@
+//@ error-in-other-file: footnote
+//@ no-rustfix
+#![warn(clippy::doc_suspicious_footnotes)]
+#![doc=include_str!("doc_suspicious_footnotes_include.txt")]
diff --git a/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.stderr b/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.stderr
new file mode 100644
index 00000000000..74154e3f4ef
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.stderr
@@ -0,0 +1,17 @@
+error: looks like a footnote ref, but has no matching footnote
+  --> tests/ui/doc_suspicious_footnotes_include.txt:1:23
+   |
+LL | This is not a footnote[^1].
+   |                       ^^^^
+   |
+   = note: `-D clippy::doc-suspicious-footnotes` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::doc_suspicious_footnotes)]`
+help: add footnote definition
+   |
+LL ~ [^2]: hello world
+LL + 
+LL + [^1]: <!-- description -->
+   |
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.txt b/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.txt
new file mode 100644
index 00000000000..2a533e32c4a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc_suspicious_footnotes_include.txt
@@ -0,0 +1,13 @@
+This is not a footnote[^1]. //~ doc_suspicious_footnotes
+
+This is not a footnote[^either], but it doesn't warn.
+
+This is not a footnote\[^1], but it also doesn't warn.
+
+This is not a footnote[^1\], but it also doesn't warn.
+
+This is not a `footnote[^1]`, but it also doesn't warn.
+
+This is a footnote[^2].
+
+[^2]: hello world
diff --git a/src/tools/clippy/tests/ui/format_args.fixed b/src/tools/clippy/tests/ui/format_args.fixed
index edfdaa23ca1..3cb6c0b4d97 100644
--- a/src/tools/clippy/tests/ui/format_args.fixed
+++ b/src/tools/clippy/tests/ui/format_args.fixed
@@ -192,3 +192,13 @@ mod issue_9256 {
         print_substring("Hello, world!");
     }
 }
+
+mod issue14952 {
+    use std::path::Path;
+    struct Foo(Path);
+    impl std::fmt::Debug for Foo {
+        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            write!(f, "{:?}", &self.0)
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/format_args.rs b/src/tools/clippy/tests/ui/format_args.rs
index 367560d577d..8a9c369fff3 100644
--- a/src/tools/clippy/tests/ui/format_args.rs
+++ b/src/tools/clippy/tests/ui/format_args.rs
@@ -192,3 +192,13 @@ mod issue_9256 {
         print_substring("Hello, world!");
     }
 }
+
+mod issue14952 {
+    use std::path::Path;
+    struct Foo(Path);
+    impl std::fmt::Debug for Foo {
+        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+            write!(f, "{:?}", &self.0)
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.rs b/src/tools/clippy/tests/ui/indexing_slicing_index.rs
index ab6a8235008..2510a023acd 100644
--- a/src/tools/clippy/tests/ui/indexing_slicing_index.rs
+++ b/src/tools/clippy/tests/ui/indexing_slicing_index.rs
@@ -68,7 +68,6 @@ fn main() {
     // This should be linted, since `suppress-restriction-lint-in-const` default is false.
     const { &ARR[idx4()] };
     //~^ ERROR: indexing may panic
-    //~| ERROR: index out of bounds
 
     let y = &x;
     // Ok, referencing shouldn't affect this lint. See the issue 6021
diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr
index 8e24b898ed5..c68e1d53a93 100644
--- a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr
+++ b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr
@@ -9,18 +9,6 @@ LL | const REF: &i32 = &ARR[idx()]; // This should be linted, since `suppress-re
    = note: `-D clippy::indexing-slicing` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::indexing_slicing)]`
 
-error[E0080]: index out of bounds: the length is 2 but the index is 4
-  --> tests/ui/indexing_slicing_index.rs:69:14
-   |
-LL |     const { &ARR[idx4()] };
-   |              ^^^^^^^^^^^ evaluation of `main::{constant#3}` failed here
-
-note: erroneous constant encountered
-  --> tests/ui/indexing_slicing_index.rs:69:5
-   |
-LL |     const { &ARR[idx4()] };
-   |     ^^^^^^^^^^^^^^^^^^^^^^
-
 error: indexing may panic
   --> tests/ui/indexing_slicing_index.rs:48:5
    |
@@ -63,13 +51,13 @@ LL |     const { &ARR[idx4()] };
    = note: the suggestion might not be applicable in constant blocks
 
 error: index is out of bounds
-  --> tests/ui/indexing_slicing_index.rs:77:5
+  --> tests/ui/indexing_slicing_index.rs:76:5
    |
 LL |     y[4];
    |     ^^^^
 
 error: indexing may panic
-  --> tests/ui/indexing_slicing_index.rs:81:5
+  --> tests/ui/indexing_slicing_index.rs:80:5
    |
 LL |     v[0];
    |     ^^^^
@@ -77,7 +65,7 @@ LL |     v[0];
    = help: consider using `.get(n)` or `.get_mut(n)` instead
 
 error: indexing may panic
-  --> tests/ui/indexing_slicing_index.rs:83:5
+  --> tests/ui/indexing_slicing_index.rs:82:5
    |
 LL |     v[10];
    |     ^^^^^
@@ -85,7 +73,7 @@ LL |     v[10];
    = help: consider using `.get(n)` or `.get_mut(n)` instead
 
 error: indexing may panic
-  --> tests/ui/indexing_slicing_index.rs:85:5
+  --> tests/ui/indexing_slicing_index.rs:84:5
    |
 LL |     v[1 << 3];
    |     ^^^^^^^^^
@@ -93,13 +81,13 @@ LL |     v[1 << 3];
    = help: consider using `.get(n)` or `.get_mut(n)` instead
 
 error: index is out of bounds
-  --> tests/ui/indexing_slicing_index.rs:93:5
+  --> tests/ui/indexing_slicing_index.rs:92:5
    |
 LL |     x[N];
    |     ^^^^
 
 error: indexing may panic
-  --> tests/ui/indexing_slicing_index.rs:97:5
+  --> tests/ui/indexing_slicing_index.rs:96:5
    |
 LL |     v[N];
    |     ^^^^
@@ -107,7 +95,7 @@ LL |     v[N];
    = help: consider using `.get(n)` or `.get_mut(n)` instead
 
 error: indexing may panic
-  --> tests/ui/indexing_slicing_index.rs:99:5
+  --> tests/ui/indexing_slicing_index.rs:98:5
    |
 LL |     v[M];
    |     ^^^^
@@ -115,11 +103,10 @@ LL |     v[M];
    = help: consider using `.get(n)` or `.get_mut(n)` instead
 
 error: index is out of bounds
-  --> tests/ui/indexing_slicing_index.rs:103:13
+  --> tests/ui/indexing_slicing_index.rs:102:13
    |
 LL |     let _ = x[4];
    |             ^^^^
 
-error: aborting due to 15 previous errors
+error: aborting due to 14 previous errors
 
-For more information about this error, try `rustc --explain E0080`.
diff --git a/src/tools/clippy/tests/ui/infallible_try_from.rs b/src/tools/clippy/tests/ui/infallible_try_from.rs
new file mode 100644
index 00000000000..6a1f12f824f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/infallible_try_from.rs
@@ -0,0 +1,33 @@
+#![feature(never_type)]
+#![warn(clippy::infallible_try_from)]
+
+use std::convert::Infallible;
+
+struct MyStruct(i32);
+
+impl TryFrom<i8> for MyStruct {
+    //~^ infallible_try_from
+    type Error = !;
+    fn try_from(other: i8) -> Result<Self, !> {
+        Ok(Self(other.into()))
+    }
+}
+
+impl TryFrom<i16> for MyStruct {
+    //~^ infallible_try_from
+    type Error = Infallible;
+    fn try_from(other: i16) -> Result<Self, Infallible> {
+        Ok(Self(other.into()))
+    }
+}
+
+impl TryFrom<i64> for MyStruct {
+    type Error = i64;
+    fn try_from(other: i64) -> Result<Self, i64> {
+        Ok(Self(i32::try_from(other).map_err(|_| other)?))
+    }
+}
+
+fn main() {
+    // test code goes here
+}
diff --git a/src/tools/clippy/tests/ui/infallible_try_from.stderr b/src/tools/clippy/tests/ui/infallible_try_from.stderr
new file mode 100644
index 00000000000..705b1188489
--- /dev/null
+++ b/src/tools/clippy/tests/ui/infallible_try_from.stderr
@@ -0,0 +1,23 @@
+error: infallible TryFrom impl; consider implementing From, instead
+  --> tests/ui/infallible_try_from.rs:8:1
+   |
+LL | impl TryFrom<i8> for MyStruct {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |     type Error = !;
+   |                  - infallible error type
+   |
+   = note: `-D clippy::infallible-try-from` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::infallible_try_from)]`
+
+error: infallible TryFrom impl; consider implementing From, instead
+  --> tests/ui/infallible_try_from.rs:16:1
+   |
+LL | impl TryFrom<i16> for MyStruct {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL |     type Error = Infallible;
+   |                  ---------- infallible error type
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/ip_constant.fixed b/src/tools/clippy/tests/ui/ip_constant.fixed
new file mode 100644
index 00000000000..2e3389c1193
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ip_constant.fixed
@@ -0,0 +1,107 @@
+#![warn(clippy::ip_constant)]
+#![allow(dead_code)]
+#![allow(clippy::identity_op)]
+#![allow(clippy::eq_op)]
+
+fn literal_test1() {
+    use std::net::Ipv4Addr;
+    let _ = Ipv4Addr::LOCALHOST;
+    //~^ ip_constant
+    let _ = Ipv4Addr::BROADCAST;
+    //~^ ip_constant
+    let _ = Ipv4Addr::UNSPECIFIED;
+    //~^ ip_constant
+
+    use std::net::Ipv6Addr;
+    let _ = Ipv6Addr::LOCALHOST;
+    //~^ ip_constant
+    let _ = Ipv6Addr::UNSPECIFIED;
+    //~^ ip_constant
+}
+
+fn literal_test2() {
+    use std::net;
+    let _ = net::Ipv4Addr::LOCALHOST;
+    //~^ ip_constant
+    let _ = net::Ipv4Addr::BROADCAST;
+    //~^ ip_constant
+    let _ = net::Ipv4Addr::UNSPECIFIED;
+    //~^ ip_constant
+
+    let _ = net::Ipv6Addr::LOCALHOST;
+    //~^ ip_constant
+    let _ = net::Ipv6Addr::UNSPECIFIED;
+    //~^ ip_constant
+}
+
+fn literal_test3() {
+    let _ = std::net::Ipv4Addr::LOCALHOST;
+    //~^ ip_constant
+    let _ = std::net::Ipv4Addr::BROADCAST;
+    //~^ ip_constant
+    let _ = std::net::Ipv4Addr::UNSPECIFIED;
+    //~^ ip_constant
+
+    let _ = std::net::Ipv6Addr::LOCALHOST;
+    //~^ ip_constant
+    let _ = std::net::Ipv6Addr::UNSPECIFIED;
+    //~^ ip_constant
+}
+
+const CONST_U8_0: u8 = 0;
+const CONST_U8_1: u8 = 1;
+const CONST_U8_127: u8 = 127;
+const CONST_U8_255: u8 = 255;
+
+const CONST_U16_0: u16 = 0;
+const CONST_U16_1: u16 = 1;
+
+fn const_test1() {
+    use std::net::Ipv4Addr;
+    let _ = Ipv4Addr::LOCALHOST;
+    //~^ ip_constant
+    let _ = Ipv4Addr::BROADCAST;
+    //~^ ip_constant
+    let _ = Ipv4Addr::UNSPECIFIED;
+    //~^ ip_constant
+
+    use std::net::Ipv6Addr;
+    let _ = Ipv6Addr::LOCALHOST;
+
+    let _ = Ipv6Addr::UNSPECIFIED;
+}
+
+fn const_test2() {
+    use std::net::Ipv4Addr;
+    let _ = Ipv4Addr::LOCALHOST;
+    //~^ ip_constant
+    let _ = Ipv4Addr::BROADCAST;
+    //~^ ip_constant
+    let _ = Ipv4Addr::UNSPECIFIED;
+    //~^ ip_constant
+
+    use std::net::Ipv6Addr;
+    let _ = Ipv6Addr::LOCALHOST;
+    //~^ ip_constant
+    let _ = Ipv6Addr::LOCALHOST;
+    //~^ ip_constant
+}
+
+macro_rules! ipv4_new {
+    ($a:expr, $b:expr, $c:expr, $d:expr) => {
+        std::net::Ipv4Addr::new($a, $b, $c, $d)
+    };
+}
+
+fn macro_test() {
+    let _ = ipv4_new!(127, 0, 0, 1);
+    // no lint
+    let _ = ipv4_new!(255, 255, 255, 255);
+    // no lint
+    let _ = ipv4_new!(0, 0, 0, 0);
+    // no lint
+}
+
+fn main() {
+    // UI Test
+}
diff --git a/src/tools/clippy/tests/ui/ip_constant.rs b/src/tools/clippy/tests/ui/ip_constant.rs
new file mode 100644
index 00000000000..15e0b0551ba
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ip_constant.rs
@@ -0,0 +1,127 @@
+#![warn(clippy::ip_constant)]
+#![allow(dead_code)]
+#![allow(clippy::identity_op)]
+#![allow(clippy::eq_op)]
+
+fn literal_test1() {
+    use std::net::Ipv4Addr;
+    let _ = Ipv4Addr::new(127, 0, 0, 1);
+    //~^ ip_constant
+    let _ = Ipv4Addr::new(255, 255, 255, 255);
+    //~^ ip_constant
+    let _ = Ipv4Addr::new(0, 0, 0, 0);
+    //~^ ip_constant
+
+    use std::net::Ipv6Addr;
+    let _ = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+    //~^ ip_constant
+    let _ = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
+    //~^ ip_constant
+}
+
+fn literal_test2() {
+    use std::net;
+    let _ = net::Ipv4Addr::new(127, 0, 0, 1);
+    //~^ ip_constant
+    let _ = net::Ipv4Addr::new(255, 255, 255, 255);
+    //~^ ip_constant
+    let _ = net::Ipv4Addr::new(0, 0, 0, 0);
+    //~^ ip_constant
+
+    let _ = net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+    //~^ ip_constant
+    let _ = net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
+    //~^ ip_constant
+}
+
+fn literal_test3() {
+    let _ = std::net::Ipv4Addr::new(127, 0, 0, 1);
+    //~^ ip_constant
+    let _ = std::net::Ipv4Addr::new(255, 255, 255, 255);
+    //~^ ip_constant
+    let _ = std::net::Ipv4Addr::new(0, 0, 0, 0);
+    //~^ ip_constant
+
+    let _ = std::net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+    //~^ ip_constant
+    let _ = std::net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
+    //~^ ip_constant
+}
+
+const CONST_U8_0: u8 = 0;
+const CONST_U8_1: u8 = 1;
+const CONST_U8_127: u8 = 127;
+const CONST_U8_255: u8 = 255;
+
+const CONST_U16_0: u16 = 0;
+const CONST_U16_1: u16 = 1;
+
+fn const_test1() {
+    use std::net::Ipv4Addr;
+    let _ = Ipv4Addr::new(CONST_U8_127, CONST_U8_0, CONST_U8_0, CONST_U8_1);
+    //~^ ip_constant
+    let _ = Ipv4Addr::new(CONST_U8_255, CONST_U8_255, CONST_U8_255, CONST_U8_255);
+    //~^ ip_constant
+    let _ = Ipv4Addr::new(CONST_U8_0, CONST_U8_0, CONST_U8_0, CONST_U8_0);
+    //~^ ip_constant
+
+    use std::net::Ipv6Addr;
+    let _ = Ipv6Addr::new(
+        //~^ ip_constant
+        CONST_U16_0,
+        CONST_U16_0,
+        CONST_U16_0,
+        CONST_U16_0,
+        CONST_U16_0,
+        CONST_U16_0,
+        CONST_U16_0,
+        CONST_U16_1,
+    );
+
+    let _ = Ipv6Addr::new(
+        //~^ ip_constant
+        CONST_U16_0,
+        CONST_U16_0,
+        CONST_U16_0,
+        CONST_U16_0,
+        CONST_U16_0,
+        CONST_U16_0,
+        CONST_U16_0,
+        CONST_U16_0,
+    );
+}
+
+fn const_test2() {
+    use std::net::Ipv4Addr;
+    let _ = Ipv4Addr::new(126 + 1, 0, 0, 1);
+    //~^ ip_constant
+    let _ = Ipv4Addr::new(254 + CONST_U8_1, 255, { 255 - CONST_U8_0 }, CONST_U8_255);
+    //~^ ip_constant
+    let _ = Ipv4Addr::new(0, CONST_U8_255 - 255, 0, { 1 + 0 - 1 });
+    //~^ ip_constant
+
+    use std::net::Ipv6Addr;
+    let _ = Ipv6Addr::new(0 + CONST_U16_0, 0, 0, 0, 0, 0, 0, 1);
+    //~^ ip_constant
+    let _ = Ipv6Addr::new(0 + 0, 0, 0, 0, 0, { 2 - 1 - CONST_U16_1 }, 0, 1);
+    //~^ ip_constant
+}
+
+macro_rules! ipv4_new {
+    ($a:expr, $b:expr, $c:expr, $d:expr) => {
+        std::net::Ipv4Addr::new($a, $b, $c, $d)
+    };
+}
+
+fn macro_test() {
+    let _ = ipv4_new!(127, 0, 0, 1);
+    // no lint
+    let _ = ipv4_new!(255, 255, 255, 255);
+    // no lint
+    let _ = ipv4_new!(0, 0, 0, 0);
+    // no lint
+}
+
+fn main() {
+    // UI Test
+}
diff --git a/src/tools/clippy/tests/ui/ip_constant.stderr b/src/tools/clippy/tests/ui/ip_constant.stderr
new file mode 100644
index 00000000000..3e984c6cb3b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ip_constant.stderr
@@ -0,0 +1,338 @@
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:8:13
+   |
+LL |     let _ = Ipv4Addr::new(127, 0, 0, 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::ip-constant` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::ip_constant)]`
+help: use
+   |
+LL -     let _ = Ipv4Addr::new(127, 0, 0, 1);
+LL +     let _ = Ipv4Addr::LOCALHOST;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:10:13
+   |
+LL |     let _ = Ipv4Addr::new(255, 255, 255, 255);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use
+   |
+LL -     let _ = Ipv4Addr::new(255, 255, 255, 255);
+LL +     let _ = Ipv4Addr::BROADCAST;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:12:13
+   |
+LL |     let _ = Ipv4Addr::new(0, 0, 0, 0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use
+   |
+LL -     let _ = Ipv4Addr::new(0, 0, 0, 0);
+LL +     let _ = Ipv4Addr::UNSPECIFIED;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:16:13
+   |
+LL |     let _ = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use
+   |
+LL -     let _ = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+LL +     let _ = Ipv6Addr::LOCALHOST;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:18:13
+   |
+LL |     let _ = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use
+   |
+LL -     let _ = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
+LL +     let _ = Ipv6Addr::UNSPECIFIED;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:24:13
+   |
+LL |     let _ = net::Ipv4Addr::new(127, 0, 0, 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use
+   |
+LL -     let _ = net::Ipv4Addr::new(127, 0, 0, 1);
+LL +     let _ = net::Ipv4Addr::LOCALHOST;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:26:13
+   |
+LL |     let _ = net::Ipv4Addr::new(255, 255, 255, 255);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use
+   |
+LL -     let _ = net::Ipv4Addr::new(255, 255, 255, 255);
+LL +     let _ = net::Ipv4Addr::BROADCAST;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:28:13
+   |
+LL |     let _ = net::Ipv4Addr::new(0, 0, 0, 0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use
+   |
+LL -     let _ = net::Ipv4Addr::new(0, 0, 0, 0);
+LL +     let _ = net::Ipv4Addr::UNSPECIFIED;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:31:13
+   |
+LL |     let _ = net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use
+   |
+LL -     let _ = net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+LL +     let _ = net::Ipv6Addr::LOCALHOST;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:33:13
+   |
+LL |     let _ = net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use
+   |
+LL -     let _ = net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
+LL +     let _ = net::Ipv6Addr::UNSPECIFIED;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:38:13
+   |
+LL |     let _ = std::net::Ipv4Addr::new(127, 0, 0, 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use
+   |
+LL -     let _ = std::net::Ipv4Addr::new(127, 0, 0, 1);
+LL +     let _ = std::net::Ipv4Addr::LOCALHOST;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:40:13
+   |
+LL |     let _ = std::net::Ipv4Addr::new(255, 255, 255, 255);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use
+   |
+LL -     let _ = std::net::Ipv4Addr::new(255, 255, 255, 255);
+LL +     let _ = std::net::Ipv4Addr::BROADCAST;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:42:13
+   |
+LL |     let _ = std::net::Ipv4Addr::new(0, 0, 0, 0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use
+   |
+LL -     let _ = std::net::Ipv4Addr::new(0, 0, 0, 0);
+LL +     let _ = std::net::Ipv4Addr::UNSPECIFIED;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:45:13
+   |
+LL |     let _ = std::net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use
+   |
+LL -     let _ = std::net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1);
+LL +     let _ = std::net::Ipv6Addr::LOCALHOST;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:47:13
+   |
+LL |     let _ = std::net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use
+   |
+LL -     let _ = std::net::Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0);
+LL +     let _ = std::net::Ipv6Addr::UNSPECIFIED;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:61:13
+   |
+LL |     let _ = Ipv4Addr::new(CONST_U8_127, CONST_U8_0, CONST_U8_0, CONST_U8_1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use
+   |
+LL -     let _ = Ipv4Addr::new(CONST_U8_127, CONST_U8_0, CONST_U8_0, CONST_U8_1);
+LL +     let _ = Ipv4Addr::LOCALHOST;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:63:13
+   |
+LL |     let _ = Ipv4Addr::new(CONST_U8_255, CONST_U8_255, CONST_U8_255, CONST_U8_255);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use
+   |
+LL -     let _ = Ipv4Addr::new(CONST_U8_255, CONST_U8_255, CONST_U8_255, CONST_U8_255);
+LL +     let _ = Ipv4Addr::BROADCAST;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:65:13
+   |
+LL |     let _ = Ipv4Addr::new(CONST_U8_0, CONST_U8_0, CONST_U8_0, CONST_U8_0);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use
+   |
+LL -     let _ = Ipv4Addr::new(CONST_U8_0, CONST_U8_0, CONST_U8_0, CONST_U8_0);
+LL +     let _ = Ipv4Addr::UNSPECIFIED;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:69:13
+   |
+LL |       let _ = Ipv6Addr::new(
+   |  _____________^
+LL | |
+LL | |         CONST_U16_0,
+LL | |         CONST_U16_0,
+...  |
+LL | |         CONST_U16_1,
+LL | |     );
+   | |_____^
+   |
+help: use
+   |
+LL -     let _ = Ipv6Addr::new(
+LL -
+LL -         CONST_U16_0,
+LL -         CONST_U16_0,
+LL -         CONST_U16_0,
+LL -         CONST_U16_0,
+LL -         CONST_U16_0,
+LL -         CONST_U16_0,
+LL -         CONST_U16_0,
+LL -         CONST_U16_1,
+LL -     );
+LL +     let _ = Ipv6Addr::LOCALHOST;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:81:13
+   |
+LL |       let _ = Ipv6Addr::new(
+   |  _____________^
+LL | |
+LL | |         CONST_U16_0,
+LL | |         CONST_U16_0,
+...  |
+LL | |         CONST_U16_0,
+LL | |     );
+   | |_____^
+   |
+help: use
+   |
+LL -     let _ = Ipv6Addr::new(
+LL -
+LL -         CONST_U16_0,
+LL -         CONST_U16_0,
+LL -         CONST_U16_0,
+LL -         CONST_U16_0,
+LL -         CONST_U16_0,
+LL -         CONST_U16_0,
+LL -         CONST_U16_0,
+LL -         CONST_U16_0,
+LL -     );
+LL +     let _ = Ipv6Addr::UNSPECIFIED;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:96:13
+   |
+LL |     let _ = Ipv4Addr::new(126 + 1, 0, 0, 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use
+   |
+LL -     let _ = Ipv4Addr::new(126 + 1, 0, 0, 1);
+LL +     let _ = Ipv4Addr::LOCALHOST;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:98:13
+   |
+LL |     let _ = Ipv4Addr::new(254 + CONST_U8_1, 255, { 255 - CONST_U8_0 }, CONST_U8_255);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use
+   |
+LL -     let _ = Ipv4Addr::new(254 + CONST_U8_1, 255, { 255 - CONST_U8_0 }, CONST_U8_255);
+LL +     let _ = Ipv4Addr::BROADCAST;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:100:13
+   |
+LL |     let _ = Ipv4Addr::new(0, CONST_U8_255 - 255, 0, { 1 + 0 - 1 });
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use
+   |
+LL -     let _ = Ipv4Addr::new(0, CONST_U8_255 - 255, 0, { 1 + 0 - 1 });
+LL +     let _ = Ipv4Addr::UNSPECIFIED;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:104:13
+   |
+LL |     let _ = Ipv6Addr::new(0 + CONST_U16_0, 0, 0, 0, 0, 0, 0, 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use
+   |
+LL -     let _ = Ipv6Addr::new(0 + CONST_U16_0, 0, 0, 0, 0, 0, 0, 1);
+LL +     let _ = Ipv6Addr::LOCALHOST;
+   |
+
+error: hand-coded well-known IP address
+  --> tests/ui/ip_constant.rs:106:13
+   |
+LL |     let _ = Ipv6Addr::new(0 + 0, 0, 0, 0, 0, { 2 - 1 - CONST_U16_1 }, 0, 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: use
+   |
+LL -     let _ = Ipv6Addr::new(0 + 0, 0, 0, 0, 0, { 2 - 1 - CONST_U16_1 }, 0, 1);
+LL +     let _ = Ipv6Addr::LOCALHOST;
+   |
+
+error: aborting due to 25 previous errors
+
diff --git a/src/tools/clippy/tests/ui/ip_constant_from_external.rs b/src/tools/clippy/tests/ui/ip_constant_from_external.rs
new file mode 100644
index 00000000000..7fd27022f12
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ip_constant_from_external.rs
@@ -0,0 +1,12 @@
+//@error-in-other-file: hand-coded well-known IP address
+//@no-rustfix
+#![warn(clippy::ip_constant)]
+
+fn external_constant_test() {
+    let _ = include!("localhost.txt");
+    // lint in external file `localhost.txt`
+}
+
+fn main() {
+    external_constant_test();
+}
diff --git a/src/tools/clippy/tests/ui/ip_constant_from_external.stderr b/src/tools/clippy/tests/ui/ip_constant_from_external.stderr
new file mode 100644
index 00000000000..99dd827d41f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ip_constant_from_external.stderr
@@ -0,0 +1,16 @@
+error: hand-coded well-known IP address
+  --> tests/ui/localhost.txt:1:1
+   |
+LL | std::net::Ipv4Addr::new(127, 0, 0, 1)
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `-D clippy::ip-constant` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::ip_constant)]`
+help: use
+   |
+LL - std::net::Ipv4Addr::new(127, 0, 0, 1)
+LL + std::net::Ipv4Addr::LOCALHOST
+   |
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/localhost.txt b/src/tools/clippy/tests/ui/localhost.txt
new file mode 100644
index 00000000000..4502ec2b234
--- /dev/null
+++ b/src/tools/clippy/tests/ui/localhost.txt
@@ -0,0 +1 @@
+std::net::Ipv4Addr::new(127, 0, 0, 1)
\ No newline at end of file
diff --git a/src/tools/clippy/tests/ui/manual_flatten.fixed b/src/tools/clippy/tests/ui/manual_flatten.fixed
new file mode 100644
index 00000000000..cc1fbd25765
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_flatten.fixed
@@ -0,0 +1,148 @@
+#![warn(clippy::manual_flatten)]
+#![allow(clippy::useless_vec, clippy::uninlined_format_args)]
+
+fn main() {
+    // Test for loop over implicitly adjusted `Iterator` with `if let` expression
+    let x = vec![Some(1), Some(2), Some(3)];
+    for y in x.into_iter().flatten() {
+        println!("{}", y);
+    }
+
+    // Test for loop over implicitly adjusted `Iterator` with `if let` statement
+    let y: Vec<Result<i32, i32>> = vec![];
+    for n in y.clone().into_iter().flatten() {
+        println!("{}", n);
+    }
+
+    // Test for loop over by reference
+    for n in y.iter().flatten() {
+        println!("{}", n);
+    }
+
+    // Test for loop over an implicit reference
+    let z = &y;
+    for n in z.iter().flatten() {
+        println!("{}", n);
+    }
+
+    // Test for loop over `Iterator` with `if let` expression
+    let z = vec![Some(1), Some(2), Some(3)];
+    let z = z.iter();
+    for m in z.flatten() {
+        println!("{}", m);
+    }
+
+    // Using the `None` variant should not trigger the lint
+    // Note: for an autofixable suggestion, the binding in the for loop has to take the
+    // name of the binding in the `if let`
+    let z = vec![Some(1), Some(2), Some(3)];
+    for n in z {
+        if n.is_none() {
+            println!("Nada.");
+        }
+    }
+
+    // Using the `Err` variant should not trigger the lint
+    for n in y.clone() {
+        if let Err(e) = n {
+            println!("Oops: {}!", e);
+        }
+    }
+
+    // Having an else clause should not trigger the lint
+    for n in y.clone() {
+        if let Ok(n) = n {
+            println!("{}", n);
+        } else {
+            println!("Oops!");
+        }
+    }
+
+    let vec_of_ref = vec![&Some(1)];
+    for n in vec_of_ref.iter().copied().flatten() {
+        println!("{:?}", n);
+    }
+
+    let vec_of_ref = &vec_of_ref;
+    for n in vec_of_ref.iter().copied().flatten() {
+        println!("{:?}", n);
+    }
+
+    let slice_of_ref = &[&Some(1)];
+    for n in slice_of_ref.iter().copied().flatten() {
+        println!("{:?}", n);
+    }
+
+    struct Test {
+        a: usize,
+    }
+
+    let mut vec_of_struct = [Some(Test { a: 1 }), None];
+
+    // Usage of `if let` expression should not trigger lint
+    for n in vec_of_struct.iter_mut() {
+        if let Some(z) = n {
+            *n = None;
+        }
+    }
+
+    // Using manual flatten should not trigger the lint
+    for n in vec![Some(1), Some(2), Some(3)].iter().flatten() {
+        println!("{}", n);
+    }
+
+    // Using nested `Some` pattern should not trigger the lint
+    for n in vec![Some((1, Some(2)))] {
+        if let Some((_, Some(n))) = n {
+            println!("{}", n);
+        }
+    }
+
+    macro_rules! inner {
+        ($id:ident / $new:pat => $action:expr) => {
+            if let Some($new) = $id {
+                $action;
+            }
+        };
+    }
+
+    // Usage of `if let` expression with macro should not trigger lint
+    for ab in [Some((1, 2)), Some((3, 4))] {
+        inner!(ab / (c, d) => println!("{c}-{d}"));
+    }
+
+    macro_rules! args {
+        ($($arg:expr),*) => {
+            vec![$(Some($arg)),*]
+        };
+    }
+
+    // Usage of `if let` expression with macro should not trigger lint
+    for n in args!(1, 2, 3) {
+        if let Some(n) = n {
+            println!("{:?}", n);
+        }
+    }
+
+    // This should trigger the lint, but the applicability is `MaybeIncorrect`
+    let z = vec![Some(1), Some(2), Some(3)];
+    for n in z.into_iter().flatten() {
+        println!("{:?}", n);
+    }
+
+    run_unformatted_tests();
+}
+
+#[rustfmt::skip]
+fn run_unformatted_tests() {
+    // Skip rustfmt here on purpose so the suggestion does not fit in one line
+    for n in vec![
+    //~^ manual_flatten
+
+        Some(1),
+        Some(2),
+        Some(3)
+    ].iter().flatten() {
+        println!("{:?}", n);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_flatten.rs b/src/tools/clippy/tests/ui/manual_flatten.rs
index f1a0053ef38..53b4ac7d3b6 100644
--- a/src/tools/clippy/tests/ui/manual_flatten.rs
+++ b/src/tools/clippy/tests/ui/manual_flatten.rs
@@ -1,6 +1,6 @@
 #![warn(clippy::manual_flatten)]
 #![allow(clippy::useless_vec, clippy::uninlined_format_args)]
-//@no-rustfix
+
 fn main() {
     // Test for loop over implicitly adjusted `Iterator` with `if let` expression
     let x = vec![Some(1), Some(2), Some(3)];
@@ -130,6 +130,43 @@ fn main() {
         }
     }
 
+    macro_rules! inner {
+        ($id:ident / $new:pat => $action:expr) => {
+            if let Some($new) = $id {
+                $action;
+            }
+        };
+    }
+
+    // Usage of `if let` expression with macro should not trigger lint
+    for ab in [Some((1, 2)), Some((3, 4))] {
+        inner!(ab / (c, d) => println!("{c}-{d}"));
+    }
+
+    macro_rules! args {
+        ($($arg:expr),*) => {
+            vec![$(Some($arg)),*]
+        };
+    }
+
+    // Usage of `if let` expression with macro should not trigger lint
+    for n in args!(1, 2, 3) {
+        if let Some(n) = n {
+            println!("{:?}", n);
+        }
+    }
+
+    // This should trigger the lint, but the applicability is `MaybeIncorrect`
+    let z = vec![Some(1), Some(2), Some(3)];
+    for n in z {
+        //~^ manual_flatten
+
+        if let Some(n) = n {
+            println!("{:?}", n);
+        }
+        // foo
+    }
+
     run_unformatted_tests();
 }
 
diff --git a/src/tools/clippy/tests/ui/manual_flatten.stderr b/src/tools/clippy/tests/ui/manual_flatten.stderr
index 9a846fe17f3..eb39ee42071 100644
--- a/src/tools/clippy/tests/ui/manual_flatten.stderr
+++ b/src/tools/clippy/tests/ui/manual_flatten.stderr
@@ -1,10 +1,7 @@
 error: unnecessary `if let` since only the `Some` variant of the iterator element is used
   --> tests/ui/manual_flatten.rs:7:5
    |
-LL |       for n in x {
-   |       ^        - help: try: `x.into_iter().flatten()`
-   |  _____|
-   | |
+LL | /     for n in x {
 LL | |
 LL | |
 LL | |         if let Some(y) = n {
@@ -12,7 +9,7 @@ LL | |         if let Some(y) = n {
 LL | |     }
    | |_____^
    |
-help: ...and remove the `if let` statement in the for loop
+help: try `.flatten()` and remove the `if let` statement in the for loop
   --> tests/ui/manual_flatten.rs:10:9
    |
 LL | /         if let Some(y) = n {
@@ -21,14 +18,17 @@ LL | |         }
    | |_________^
    = note: `-D clippy::manual-flatten` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::manual_flatten)]`
+help: try
+   |
+LL ~     for y in x.into_iter().flatten() {
+LL +         println!("{}", y);
+LL +     }
+   |
 
 error: unnecessary `if let` since only the `Ok` variant of the iterator element is used
   --> tests/ui/manual_flatten.rs:17:5
    |
-LL |       for n in y.clone() {
-   |       ^        --------- help: try: `y.clone().into_iter().flatten()`
-   |  _____|
-   | |
+LL | /     for n in y.clone() {
 LL | |
 LL | |
 LL | |         if let Ok(n) = n {
@@ -37,21 +37,24 @@ LL | |         };
 LL | |     }
    | |_____^
    |
-help: ...and remove the `if let` statement in the for loop
+help: try `.flatten()` and remove the `if let` statement in the for loop
   --> tests/ui/manual_flatten.rs:20:9
    |
 LL | /         if let Ok(n) = n {
 LL | |             println!("{}", n);
 LL | |         };
    | |_________^
+help: try
+   |
+LL ~     for n in y.clone().into_iter().flatten() {
+LL +         println!("{}", n);
+LL +     }
+   |
 
 error: unnecessary `if let` since only the `Ok` variant of the iterator element is used
   --> tests/ui/manual_flatten.rs:26:5
    |
-LL |       for n in &y {
-   |       ^        -- help: try: `y.iter().flatten()`
-   |  _____|
-   | |
+LL | /     for n in &y {
 LL | |
 LL | |
 LL | |         if let Ok(n) = n {
@@ -59,21 +62,24 @@ LL | |         if let Ok(n) = n {
 LL | |     }
    | |_____^
    |
-help: ...and remove the `if let` statement in the for loop
+help: try `.flatten()` and remove the `if let` statement in the for loop
   --> tests/ui/manual_flatten.rs:29:9
    |
 LL | /         if let Ok(n) = n {
 LL | |             println!("{}", n);
 LL | |         }
    | |_________^
+help: try
+   |
+LL ~     for n in y.iter().flatten() {
+LL +         println!("{}", n);
+LL +     }
+   |
 
 error: unnecessary `if let` since only the `Ok` variant of the iterator element is used
   --> tests/ui/manual_flatten.rs:36:5
    |
-LL |       for n in z {
-   |       ^        - help: try: `z.iter().flatten()`
-   |  _____|
-   | |
+LL | /     for n in z {
 LL | |
 LL | |
 LL | |         if let Ok(n) = n {
@@ -81,21 +87,24 @@ LL | |         if let Ok(n) = n {
 LL | |     }
    | |_____^
    |
-help: ...and remove the `if let` statement in the for loop
+help: try `.flatten()` and remove the `if let` statement in the for loop
   --> tests/ui/manual_flatten.rs:39:9
    |
 LL | /         if let Ok(n) = n {
 LL | |             println!("{}", n);
 LL | |         }
    | |_________^
+help: try
+   |
+LL ~     for n in z.iter().flatten() {
+LL +         println!("{}", n);
+LL +     }
+   |
 
 error: unnecessary `if let` since only the `Some` variant of the iterator element is used
   --> tests/ui/manual_flatten.rs:47:5
    |
-LL |       for n in z {
-   |       ^        - help: try: `z.flatten()`
-   |  _____|
-   | |
+LL | /     for n in z {
 LL | |
 LL | |
 LL | |         if let Some(m) = n {
@@ -103,21 +112,24 @@ LL | |         if let Some(m) = n {
 LL | |     }
    | |_____^
    |
-help: ...and remove the `if let` statement in the for loop
+help: try `.flatten()` and remove the `if let` statement in the for loop
   --> tests/ui/manual_flatten.rs:50:9
    |
 LL | /         if let Some(m) = n {
 LL | |             println!("{}", m);
 LL | |         }
    | |_________^
+help: try
+   |
+LL ~     for m in z.flatten() {
+LL +         println!("{}", m);
+LL +     }
+   |
 
 error: unnecessary `if let` since only the `Some` variant of the iterator element is used
   --> tests/ui/manual_flatten.rs:82:5
    |
-LL |       for n in &vec_of_ref {
-   |       ^        ----------- help: try: `vec_of_ref.iter().copied().flatten()`
-   |  _____|
-   | |
+LL | /     for n in &vec_of_ref {
 LL | |
 LL | |
 LL | |         if let Some(n) = n {
@@ -125,21 +137,24 @@ LL | |         if let Some(n) = n {
 LL | |     }
    | |_____^
    |
-help: ...and remove the `if let` statement in the for loop
+help: try `.flatten()` and remove the `if let` statement in the for loop
   --> tests/ui/manual_flatten.rs:85:9
    |
 LL | /         if let Some(n) = n {
 LL | |             println!("{:?}", n);
 LL | |         }
    | |_________^
+help: try
+   |
+LL ~     for n in vec_of_ref.iter().copied().flatten() {
+LL +         println!("{:?}", n);
+LL +     }
+   |
 
 error: unnecessary `if let` since only the `Some` variant of the iterator element is used
   --> tests/ui/manual_flatten.rs:91:5
    |
-LL |       for n in vec_of_ref {
-   |       ^        ---------- help: try: `vec_of_ref.iter().copied().flatten()`
-   |  _____|
-   | |
+LL | /     for n in vec_of_ref {
 LL | |
 LL | |
 LL | |         if let Some(n) = n {
@@ -147,21 +162,24 @@ LL | |         if let Some(n) = n {
 LL | |     }
    | |_____^
    |
-help: ...and remove the `if let` statement in the for loop
+help: try `.flatten()` and remove the `if let` statement in the for loop
   --> tests/ui/manual_flatten.rs:94:9
    |
 LL | /         if let Some(n) = n {
 LL | |             println!("{:?}", n);
 LL | |         }
    | |_________^
+help: try
+   |
+LL ~     for n in vec_of_ref.iter().copied().flatten() {
+LL +         println!("{:?}", n);
+LL +     }
+   |
 
 error: unnecessary `if let` since only the `Some` variant of the iterator element is used
   --> tests/ui/manual_flatten.rs:100:5
    |
-LL |       for n in slice_of_ref {
-   |       ^        ------------ help: try: `slice_of_ref.iter().copied().flatten()`
-   |  _____|
-   | |
+LL | /     for n in slice_of_ref {
 LL | |
 LL | |
 LL | |         if let Some(n) = n {
@@ -169,16 +187,47 @@ LL | |         if let Some(n) = n {
 LL | |     }
    | |_____^
    |
-help: ...and remove the `if let` statement in the for loop
+help: try `.flatten()` and remove the `if let` statement in the for loop
   --> tests/ui/manual_flatten.rs:103:9
    |
 LL | /         if let Some(n) = n {
 LL | |             println!("{:?}", n);
 LL | |         }
    | |_________^
+help: try
+   |
+LL ~     for n in slice_of_ref.iter().copied().flatten() {
+LL +         println!("{:?}", n);
+LL +     }
+   |
+
+error: unnecessary `if let` since only the `Some` variant of the iterator element is used
+  --> tests/ui/manual_flatten.rs:161:5
+   |
+LL | /     for n in z {
+LL | |
+LL | |
+LL | |         if let Some(n) = n {
+...  |
+LL | |     }
+   | |_____^
+   |
+help: try `.flatten()` and remove the `if let` statement in the for loop
+  --> tests/ui/manual_flatten.rs:164:9
+   |
+LL | /         if let Some(n) = n {
+LL | |             println!("{:?}", n);
+LL | |         }
+   | |_________^
+help: try
+   |
+LL ~     for n in z.into_iter().flatten() {
+LL +         println!("{:?}", n);
+LL +     }
+   |
 
 error: unnecessary `if let` since only the `Some` variant of the iterator element is used
-  --> tests/ui/manual_flatten.rs:139:5
+  --> tests/ui/manual_flatten.rs:176:5
    |
 LL | /     for n in vec![
 LL | |
@@ -188,8 +237,8 @@ LL | |         Some(1),
 LL | |     }
    | |_____^
    |
-help: remove the `if let` statement in the for loop and then...
-  --> tests/ui/manual_flatten.rs:146:9
+help: try `.flatten()` and remove the `if let` statement in the for loop
+  --> tests/ui/manual_flatten.rs:183:9
    |
 LL | /         if let Some(n) = n {
 LL | |             println!("{:?}", n);
@@ -201,7 +250,9 @@ LL |     for n in vec![
 ...
 LL |         Some(3)
 LL ~     ].iter().flatten() {
+LL +         println!("{:?}", n);
+LL +     }
    |
 
-error: aborting due to 9 previous errors
+error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/manual_swap_auto_fix.fixed b/src/tools/clippy/tests/ui/manual_swap_auto_fix.fixed
index 28466ff3f9b..6cd81bafce8 100644
--- a/src/tools/clippy/tests/ui/manual_swap_auto_fix.fixed
+++ b/src/tools/clippy/tests/ui/manual_swap_auto_fix.fixed
@@ -55,3 +55,14 @@ fn swap8() {
     let i2 = 1;
     v.swap(i1 + i2, i2);
 }
+
+fn issue_14931() {
+    let mut v = [1, 2, 3, 4];
+
+    let mut i1 = 0;
+    for i2 in 0..4 {
+        v.swap(i1, i2);
+
+        i1 += 2;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_swap_auto_fix.rs b/src/tools/clippy/tests/ui/manual_swap_auto_fix.rs
index c9880e651cd..19dabfd833f 100644
--- a/src/tools/clippy/tests/ui/manual_swap_auto_fix.rs
+++ b/src/tools/clippy/tests/ui/manual_swap_auto_fix.rs
@@ -78,3 +78,17 @@ fn swap8() {
     v[i1 + i2] = v[i2];
     v[i2] = tmp;
 }
+
+fn issue_14931() {
+    let mut v = [1, 2, 3, 4];
+
+    let mut i1 = 0;
+    for i2 in 0..4 {
+        let tmp = v[i1];
+        //~^ manual_swap
+        v[i1] = v[i2];
+        v[i2] = tmp;
+
+        i1 += 2;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/manual_swap_auto_fix.stderr b/src/tools/clippy/tests/ui/manual_swap_auto_fix.stderr
index 7ab898fcc72..a0bb32233e2 100644
--- a/src/tools/clippy/tests/ui/manual_swap_auto_fix.stderr
+++ b/src/tools/clippy/tests/ui/manual_swap_auto_fix.stderr
@@ -92,5 +92,14 @@ LL | |     v[i1 + i2] = v[i2];
 LL | |     v[i2] = tmp;
    | |________________^ help: try: `v.swap(i1 + i2, i2);`
 
-error: aborting due to 8 previous errors
+error: this looks like you are swapping elements of `v` manually
+  --> tests/ui/manual_swap_auto_fix.rs:87:9
+   |
+LL | /         let tmp = v[i1];
+LL | |
+LL | |         v[i1] = v[i2];
+LL | |         v[i2] = tmp;
+   | |____________________^ help: try: `v.swap(i1, i2);`
+
+error: aborting due to 9 previous errors
 
diff --git a/src/tools/clippy/tests/ui/match_single_binding.fixed b/src/tools/clippy/tests/ui/match_single_binding.fixed
index bdf39796ebf..e11dea35204 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.fixed
+++ b/src/tools/clippy/tests/ui/match_single_binding.fixed
@@ -188,3 +188,19 @@ fn issue14634() {
     let id!(_a) = dbg!(b + 1);
     //~^^^ match_single_binding
 }
+
+mod issue14991 {
+    struct AnnoConstWOBlock {
+        inner: [(); {
+            let _n = 1;
+            42
+        }],
+    }
+
+    struct AnnoConstWBlock {
+        inner: [(); {
+            let _n = 1;
+            42
+        }],
+    }
+}
diff --git a/src/tools/clippy/tests/ui/match_single_binding.rs b/src/tools/clippy/tests/ui/match_single_binding.rs
index 419ff95d873..d498da30fc8 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.rs
+++ b/src/tools/clippy/tests/ui/match_single_binding.rs
@@ -249,3 +249,21 @@ fn issue14634() {
     };
     //~^^^ match_single_binding
 }
+
+mod issue14991 {
+    struct AnnoConstWOBlock {
+        inner: [(); match 1 {
+            //~^ match_single_binding
+            _n => 42,
+        }],
+    }
+
+    struct AnnoConstWBlock {
+        inner: [(); {
+            match 1 {
+                //~^ match_single_binding
+                _n => 42,
+            }
+        }],
+    }
+}
diff --git a/src/tools/clippy/tests/ui/match_single_binding.stderr b/src/tools/clippy/tests/ui/match_single_binding.stderr
index bdd0134a5f1..f274f80c81d 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.stderr
+++ b/src/tools/clippy/tests/ui/match_single_binding.stderr
@@ -378,5 +378,38 @@ LL ~     let id!(b) = dbg!(3);
 LL +     let id!(_a) = dbg!(b + 1);
    |
 
-error: aborting due to 27 previous errors
+error: this match could be written as a `let` statement
+  --> tests/ui/match_single_binding.rs:255:21
+   |
+LL |           inner: [(); match 1 {
+   |  _____________________^
+LL | |
+LL | |             _n => 42,
+LL | |         }],
+   | |_________^
+   |
+help: consider using a `let` statement
+   |
+LL ~         inner: [(); {
+LL +             let _n = 1;
+LL +             42
+LL ~         }],
+   |
+
+error: this match could be written as a `let` statement
+  --> tests/ui/match_single_binding.rs:263:13
+   |
+LL | /             match 1 {
+LL | |
+LL | |                 _n => 42,
+LL | |             }
+   | |_____________^
+   |
+help: consider using a `let` statement
+   |
+LL ~             let _n = 1;
+LL +             42
+   |
+
+error: aborting due to 29 previous errors
 
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed
new file mode 100644
index 00000000000..7e0d4fccaae
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.fixed
@@ -0,0 +1,36 @@
+#![feature(const_trait_impl)]
+#![warn(clippy::missing_const_for_fn)]
+
+// Reduced test case from https://github.com/rust-lang/rust-clippy/issues/14658
+
+#[const_trait]
+trait ConstTrait {
+    fn method(self);
+}
+
+impl ConstTrait for u32 {
+    fn method(self) {}
+}
+
+impl const ConstTrait for u64 {
+    fn method(self) {}
+}
+
+fn cannot_be_const() {
+    0u32.method();
+}
+
+//~v missing_const_for_fn
+const fn can_be_const() {
+    0u64.method();
+}
+
+// False negative, see FIXME comment in `clipy_utils::qualify_min_const`
+fn could_be_const_but_does_not_trigger<T>(t: T)
+where
+    T: const ConstTrait,
+{
+    t.method();
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs
new file mode 100644
index 00000000000..439da4622d7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.rs
@@ -0,0 +1,36 @@
+#![feature(const_trait_impl)]
+#![warn(clippy::missing_const_for_fn)]
+
+// Reduced test case from https://github.com/rust-lang/rust-clippy/issues/14658
+
+#[const_trait]
+trait ConstTrait {
+    fn method(self);
+}
+
+impl ConstTrait for u32 {
+    fn method(self) {}
+}
+
+impl const ConstTrait for u64 {
+    fn method(self) {}
+}
+
+fn cannot_be_const() {
+    0u32.method();
+}
+
+//~v missing_const_for_fn
+fn can_be_const() {
+    0u64.method();
+}
+
+// False negative, see FIXME comment in `clipy_utils::qualify_min_const`
+fn could_be_const_but_does_not_trigger<T>(t: T)
+where
+    T: const ConstTrait,
+{
+    t.method();
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr
new file mode 100644
index 00000000000..b994b88fac6
--- /dev/null
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/const_trait.stderr
@@ -0,0 +1,17 @@
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/const_trait.rs:24:1
+   |
+LL | / fn can_be_const() {
+LL | |     0u64.method();
+LL | | }
+   | |_^
+   |
+   = note: `-D clippy::missing-const-for-fn` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::missing_const_for_fn)]`
+help: make the function `const`
+   |
+LL | const fn can_be_const() {
+   | +++++
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.fixed b/src/tools/clippy/tests/ui/needless_lifetimes.fixed
index ceea4480d0d..15ca409c95b 100644
--- a/src/tools/clippy/tests/ui/needless_lifetimes.fixed
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.fixed
@@ -10,7 +10,7 @@
     clippy::unnecessary_wraps,
     dyn_drop,
     clippy::get_first,
-    mismatched_lifetime_syntaxes,
+    mismatched_lifetime_syntaxes
 )]
 
 extern crate proc_macros;
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs
index 8432f9e6d2f..af9649d7298 100644
--- a/src/tools/clippy/tests/ui/needless_lifetimes.rs
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs
@@ -10,7 +10,7 @@
     clippy::unnecessary_wraps,
     dyn_drop,
     clippy::get_first,
-    mismatched_lifetime_syntaxes,
+    mismatched_lifetime_syntaxes
 )]
 
 extern crate proc_macros;
diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed
index 23dbee5a084..6915e1984fb 100644
--- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed
+++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed
@@ -195,3 +195,19 @@ impl PartialOrd for K {
     //~^ non_canonical_partial_ord_impl
     fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
 }
+
+// #14574, check that partial_cmp invokes other.cmp
+
+#[derive(Eq, PartialEq)]
+struct L(u32);
+
+impl Ord for L {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl PartialOrd for L {
+    //~^ non_canonical_partial_ord_impl
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
+}
diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs
index 12f055a542b..7ce4cdc9aec 100644
--- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs
+++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs
@@ -201,3 +201,21 @@ impl PartialOrd for K {
         Ordering::Greater.into()
     }
 }
+
+// #14574, check that partial_cmp invokes other.cmp
+
+#[derive(Eq, PartialEq)]
+struct L(u32);
+
+impl Ord for L {
+    fn cmp(&self, other: &Self) -> Ordering {
+        todo!();
+    }
+}
+
+impl PartialOrd for L {
+    //~^ non_canonical_partial_ord_impl
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        Some(other.cmp(self))
+    }
+}
diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr
index c7de968588f..9bd6b1f726d 100644
--- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr
+++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr
@@ -44,5 +44,18 @@ LL | ||     }
 LL | |  }
    | |__^
 
-error: aborting due to 3 previous errors
+error: non-canonical implementation of `partial_cmp` on an `Ord` type
+  --> tests/ui/non_canonical_partial_ord_impl.rs:216:1
+   |
+LL | /  impl PartialOrd for L {
+LL | |
+LL | |      fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+   | | _____________________________________________________________-
+LL | ||         Some(other.cmp(self))
+LL | ||     }
+   | ||_____- help: change this to: `{ Some(self.cmp(other)) }`
+LL | |  }
+   | |__^
+
+error: aborting due to 4 previous errors
 
diff --git a/src/tools/clippy/tests/ui/pointer_format.rs b/src/tools/clippy/tests/ui/pointer_format.rs
new file mode 100644
index 00000000000..0621f966ad1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/pointer_format.rs
@@ -0,0 +1,66 @@
+#![warn(clippy::pointer_format)]
+
+use core::fmt::Debug;
+use core::marker::PhantomData;
+
+#[derive(Debug)]
+struct ContainsPointerDeep {
+    w: WithPointer,
+}
+
+struct ManualDebug {
+    ptr: *const u8,
+}
+
+#[derive(Debug)]
+struct WithPointer {
+    len: usize,
+    ptr: *const u8,
+}
+
+impl std::fmt::Debug for ManualDebug {
+    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+        f.write_str("ManualDebug")
+    }
+}
+
+trait Foo {
+    type Assoc: Foo + Debug;
+}
+
+#[derive(Debug)]
+struct S<T: Foo + 'static>(&'static S<T::Assoc>, PhantomData<T>);
+
+#[allow(unused)]
+fn unbounded<T: Foo + Debug + 'static>(s: &S<T>) {
+    format!("{s:?}");
+}
+
+fn main() {
+    let m = &(main as fn());
+    let g = &0;
+    let o = &format!("{m:p}");
+    //~^ pointer_format
+    let _ = format!("{m:?}");
+    //~^ pointer_format
+    println!("{g:p}");
+    //~^ pointer_format
+    panic!("{o:p}");
+    //~^ pointer_format
+    let answer = 42;
+    let x = &raw const answer;
+    let arr = [0u8; 8];
+    let with_ptr = WithPointer { len: 8, ptr: &arr as _ };
+    let _ = format!("{x:?}");
+    //~^ pointer_format
+    print!("{with_ptr:?}");
+    //~^ pointer_format
+    let container = ContainsPointerDeep { w: with_ptr };
+    print!("{container:?}");
+    //~^ pointer_format
+
+    let no_pointer = "foo";
+    println!("{no_pointer:?}");
+    let manual_debug = ManualDebug { ptr: &arr as _ };
+    println!("{manual_debug:?}");
+}
diff --git a/src/tools/clippy/tests/ui/pointer_format.stderr b/src/tools/clippy/tests/ui/pointer_format.stderr
new file mode 100644
index 00000000000..21ba39b8f8c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/pointer_format.stderr
@@ -0,0 +1,47 @@
+error: pointer formatting detected
+  --> tests/ui/pointer_format.rs:42:23
+   |
+LL |     let o = &format!("{m:p}");
+   |                       ^^^^^
+   |
+   = note: `-D clippy::pointer-format` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::pointer_format)]`
+
+error: pointer formatting detected
+  --> tests/ui/pointer_format.rs:44:22
+   |
+LL |     let _ = format!("{m:?}");
+   |                      ^^^^^
+
+error: pointer formatting detected
+  --> tests/ui/pointer_format.rs:46:15
+   |
+LL |     println!("{g:p}");
+   |               ^^^^^
+
+error: pointer formatting detected
+  --> tests/ui/pointer_format.rs:48:13
+   |
+LL |     panic!("{o:p}");
+   |             ^^^^^
+
+error: pointer formatting detected
+  --> tests/ui/pointer_format.rs:54:22
+   |
+LL |     let _ = format!("{x:?}");
+   |                      ^^^^^
+
+error: pointer formatting detected
+  --> tests/ui/pointer_format.rs:56:13
+   |
+LL |     print!("{with_ptr:?}");
+   |             ^^^^^^^^^^^^
+
+error: pointer formatting detected
+  --> tests/ui/pointer_format.rs:59:13
+   |
+LL |     print!("{container:?}");
+   |             ^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/print_literal.fixed b/src/tools/clippy/tests/ui/print_literal.fixed
index 24c45a4a61b..ebfe19c700e 100644
--- a/src/tools/clippy/tests/ui/print_literal.fixed
+++ b/src/tools/clippy/tests/ui/print_literal.fixed
@@ -94,3 +94,14 @@ fn issue_13959() {
 "
     );
 }
+
+fn issue_14930() {
+    println!("Hello x is {0:2$.1$}", 0.01, 2, 3);
+    //~^ print_literal
+    println!("Hello x is {0:2$.1$}", 0.01, 2, 3);
+    //~^ print_literal
+    println!("Hello x is {0:2$.1$}", 0.01, 2, 3);
+    //~^ print_literal
+    println!("Hello x is {0:2$.1$}", 0.01, 2, 3);
+    //~^ print_literal
+}
diff --git a/src/tools/clippy/tests/ui/print_literal.rs b/src/tools/clippy/tests/ui/print_literal.rs
index 42ae589ca63..8f3d9be0698 100644
--- a/src/tools/clippy/tests/ui/print_literal.rs
+++ b/src/tools/clippy/tests/ui/print_literal.rs
@@ -95,3 +95,14 @@ fn issue_13959() {
 "#
     );
 }
+
+fn issue_14930() {
+    println!("Hello {3} is {0:2$.1$}", 0.01, 2, 3, "x");
+    //~^ print_literal
+    println!("Hello {2} is {0:3$.1$}", 0.01, 2, "x", 3);
+    //~^ print_literal
+    println!("Hello {1} is {0:3$.2$}", 0.01, "x", 2, 3);
+    //~^ print_literal
+    println!("Hello {0} is {1:3$.2$}", "x", 0.01, 2, 3);
+    //~^ print_literal
+}
diff --git a/src/tools/clippy/tests/ui/print_literal.stderr b/src/tools/clippy/tests/ui/print_literal.stderr
index da663000686..1c378017d15 100644
--- a/src/tools/clippy/tests/ui/print_literal.stderr
+++ b/src/tools/clippy/tests/ui/print_literal.stderr
@@ -229,5 +229,53 @@ LL +         bar
 LL ~ "
    |
 
-error: aborting due to 18 previous errors
+error: literal with an empty format string
+  --> tests/ui/print_literal.rs:100:52
+   |
+LL |     println!("Hello {3} is {0:2$.1$}", 0.01, 2, 3, "x");
+   |                                                    ^^^
+   |
+help: try
+   |
+LL -     println!("Hello {3} is {0:2$.1$}", 0.01, 2, 3, "x");
+LL +     println!("Hello x is {0:2$.1$}", 0.01, 2, 3);
+   |
+
+error: literal with an empty format string
+  --> tests/ui/print_literal.rs:102:49
+   |
+LL |     println!("Hello {2} is {0:3$.1$}", 0.01, 2, "x", 3);
+   |                                                 ^^^
+   |
+help: try
+   |
+LL -     println!("Hello {2} is {0:3$.1$}", 0.01, 2, "x", 3);
+LL +     println!("Hello x is {0:2$.1$}", 0.01, 2, 3);
+   |
+
+error: literal with an empty format string
+  --> tests/ui/print_literal.rs:104:46
+   |
+LL |     println!("Hello {1} is {0:3$.2$}", 0.01, "x", 2, 3);
+   |                                              ^^^
+   |
+help: try
+   |
+LL -     println!("Hello {1} is {0:3$.2$}", 0.01, "x", 2, 3);
+LL +     println!("Hello x is {0:2$.1$}", 0.01, 2, 3);
+   |
+
+error: literal with an empty format string
+  --> tests/ui/print_literal.rs:106:40
+   |
+LL |     println!("Hello {0} is {1:3$.2$}", "x", 0.01, 2, 3);
+   |                                        ^^^
+   |
+help: try
+   |
+LL -     println!("Hello {0} is {1:3$.2$}", "x", 0.01, 2, 3);
+LL +     println!("Hello x is {0:2$.1$}", 0.01, 2, 3);
+   |
+
+error: aborting due to 22 previous errors
 
diff --git a/src/tools/clippy/tests/ui/semicolon_outside_block.fixed b/src/tools/clippy/tests/ui/semicolon_outside_block.fixed
index 52fae9a3aff..a3be80b4928 100644
--- a/src/tools/clippy/tests/ui/semicolon_outside_block.fixed
+++ b/src/tools/clippy/tests/ui/semicolon_outside_block.fixed
@@ -96,3 +96,28 @@ fn main() {
 
     unit_fn_block()
 }
+
+fn issue14926() {
+    macro_rules! gen_code {
+        [$l:lifetime: $b:block, $b2: block $(,)?] => {
+            $l: loop {
+                $b
+                break $l;
+            }
+            $l: loop {
+                $b2
+                break $l;
+            }
+        };
+    }
+
+    gen_code! {
+        'root:
+        {
+            println!("Block1");
+        },
+        {
+            println!("Block2");
+        },
+    }
+}
diff --git a/src/tools/clippy/tests/ui/semicolon_outside_block.rs b/src/tools/clippy/tests/ui/semicolon_outside_block.rs
index 5975e66fbb8..3b7bf68029f 100644
--- a/src/tools/clippy/tests/ui/semicolon_outside_block.rs
+++ b/src/tools/clippy/tests/ui/semicolon_outside_block.rs
@@ -96,3 +96,28 @@ fn main() {
 
     unit_fn_block()
 }
+
+fn issue14926() {
+    macro_rules! gen_code {
+        [$l:lifetime: $b:block, $b2: block $(,)?] => {
+            $l: loop {
+                $b
+                break $l;
+            }
+            $l: loop {
+                $b2
+                break $l;
+            }
+        };
+    }
+
+    gen_code! {
+        'root:
+        {
+            println!("Block1");
+        },
+        {
+            println!("Block2");
+        },
+    }
+}
diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.fixed b/src/tools/clippy/tests/ui/std_instead_of_core.fixed
index ab2e801eee2..1820ade422f 100644
--- a/src/tools/clippy/tests/ui/std_instead_of_core.fixed
+++ b/src/tools/clippy/tests/ui/std_instead_of_core.fixed
@@ -90,3 +90,9 @@ fn msrv_1_76(_: std::net::IpAddr) {}
 #[clippy::msrv = "1.77"]
 fn msrv_1_77(_: core::net::IpAddr) {}
 //~^ std_instead_of_core
+
+#[warn(clippy::std_instead_of_core)]
+#[rustfmt::skip]
+fn issue14982() {
+    use std::{collections::HashMap, hash::Hash};
+}
diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.rs b/src/tools/clippy/tests/ui/std_instead_of_core.rs
index f760b3561ae..32c49330981 100644
--- a/src/tools/clippy/tests/ui/std_instead_of_core.rs
+++ b/src/tools/clippy/tests/ui/std_instead_of_core.rs
@@ -90,3 +90,9 @@ fn msrv_1_76(_: std::net::IpAddr) {}
 #[clippy::msrv = "1.77"]
 fn msrv_1_77(_: std::net::IpAddr) {}
 //~^ std_instead_of_core
+
+#[warn(clippy::std_instead_of_core)]
+#[rustfmt::skip]
+fn issue14982() {
+    use std::{collections::HashMap, hash::Hash};
+}
diff --git a/src/tools/clippy/tests/ui/unit_arg.rs b/src/tools/clippy/tests/ui/unit_arg.rs
index 22a6a26dab6..4208efad677 100644
--- a/src/tools/clippy/tests/ui/unit_arg.rs
+++ b/src/tools/clippy/tests/ui/unit_arg.rs
@@ -151,3 +151,27 @@ fn main() {
     bad();
     ok();
 }
+
+fn issue14857() {
+    let fn_take_unit = |_: ()| {};
+    fn some_other_fn(_: &i32) {}
+
+    macro_rules! mac {
+        (def) => {
+            Default::default()
+        };
+        (func $f:expr) => {
+            $f()
+        };
+        (nonempty_block $e:expr) => {{
+            some_other_fn(&$e);
+            $e
+        }};
+    }
+    fn_take_unit(mac!(def));
+    //~^ unit_arg
+    fn_take_unit(mac!(func Default::default));
+    //~^ unit_arg
+    fn_take_unit(mac!(nonempty_block Default::default()));
+    //~^ unit_arg
+}
diff --git a/src/tools/clippy/tests/ui/unit_arg.stderr b/src/tools/clippy/tests/ui/unit_arg.stderr
index 6c333d9792d..0dcfb02b9fa 100644
--- a/src/tools/clippy/tests/ui/unit_arg.stderr
+++ b/src/tools/clippy/tests/ui/unit_arg.stderr
@@ -199,5 +199,26 @@ LL ~     foo(1);
 LL +     Some(())
    |
 
-error: aborting due to 10 previous errors
+error: passing a unit value to a function
+  --> tests/ui/unit_arg.rs:171:5
+   |
+LL |     fn_take_unit(mac!(def));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+
+error: passing a unit value to a function
+  --> tests/ui/unit_arg.rs:173:5
+   |
+LL |     fn_take_unit(mac!(func Default::default));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+
+error: passing a unit value to a function
+  --> tests/ui/unit_arg.rs:175:5
+   |
+LL |     fn_take_unit(mac!(nonempty_block Default::default()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.fixed b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.fixed
deleted file mode 100644
index b045a33608d..00000000000
--- a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.fixed
+++ /dev/null
@@ -1,34 +0,0 @@
-#![warn(clippy::unit_arg)]
-#![allow(unused_must_use, unused_variables)]
-#![allow(clippy::no_effect, clippy::uninlined_format_args)]
-
-use std::fmt::Debug;
-
-fn foo<T: Debug>(t: T) {
-    println!("{:?}", t);
-}
-
-fn foo3<T1: Debug, T2: Debug, T3: Debug>(t1: T1, t2: T2, t3: T3) {
-    println!("{:?}, {:?}, {:?}", t1, t2, t3);
-}
-
-fn bad() {
-    foo(());
-    //~^ unit_arg
-    foo3((), 2, 2);
-    //~^ unit_arg
-    foo(0);
-    taking_two_units((), ());
-    //~^ unit_arg
-    foo(0);
-    foo(1);
-    taking_three_units((), (), ());
-    //~^ unit_arg
-}
-
-fn taking_two_units(a: (), b: ()) {}
-fn taking_three_units(a: (), b: (), c: ()) {}
-
-fn main() {
-    bad();
-}
diff --git a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs
deleted file mode 100644
index ab305913f3f..00000000000
--- a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-#![warn(clippy::unit_arg)]
-#![allow(unused_must_use, unused_variables)]
-#![allow(clippy::no_effect, clippy::uninlined_format_args)]
-
-use std::fmt::Debug;
-
-fn foo<T: Debug>(t: T) {
-    println!("{:?}", t);
-}
-
-fn foo3<T1: Debug, T2: Debug, T3: Debug>(t1: T1, t2: T2, t3: T3) {
-    println!("{:?}, {:?}, {:?}", t1, t2, t3);
-}
-
-fn bad() {
-    foo({});
-    //~^ unit_arg
-    foo3({}, 2, 2);
-    //~^ unit_arg
-    taking_two_units({}, foo(0));
-    //~^ unit_arg
-    taking_three_units({}, foo(0), foo(1));
-    //~^ unit_arg
-}
-
-fn taking_two_units(a: (), b: ()) {}
-fn taking_three_units(a: (), b: (), c: ()) {}
-
-fn main() {
-    bad();
-}
diff --git a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr
deleted file mode 100644
index 2c686d58ecc..00000000000
--- a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.stderr
+++ /dev/null
@@ -1,46 +0,0 @@
-error: passing a unit value to a function
-  --> tests/ui/unit_arg_empty_blocks.rs:16:5
-   |
-LL |     foo({});
-   |     ^^^^--^
-   |         |
-   |         help: use a unit literal instead: `()`
-   |
-   = note: `-D clippy::unit-arg` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::unit_arg)]`
-
-error: passing a unit value to a function
-  --> tests/ui/unit_arg_empty_blocks.rs:18:5
-   |
-LL |     foo3({}, 2, 2);
-   |     ^^^^^--^^^^^^^
-   |          |
-   |          help: use a unit literal instead: `()`
-
-error: passing unit values to a function
-  --> tests/ui/unit_arg_empty_blocks.rs:20:5
-   |
-LL |     taking_two_units({}, foo(0));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: move the expression in front of the call and replace it with the unit literal `()`
-   |
-LL ~     foo(0);
-LL ~     taking_two_units((), ());
-   |
-
-error: passing unit values to a function
-  --> tests/ui/unit_arg_empty_blocks.rs:22:5
-   |
-LL |     taking_three_units({}, foo(0), foo(1));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: move the expressions in front of the call and replace them with the unit literal `()`
-   |
-LL ~     foo(0);
-LL +     foo(1);
-LL ~     taking_three_units((), (), ());
-   |
-
-error: aborting due to 4 previous errors
-
diff --git a/src/tools/clippy/tests/ui/unit_arg_fixable.fixed b/src/tools/clippy/tests/ui/unit_arg_fixable.fixed
new file mode 100644
index 00000000000..03353a14081
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unit_arg_fixable.fixed
@@ -0,0 +1,78 @@
+#![warn(clippy::unit_arg)]
+#![allow(unused_must_use, unused_variables)]
+#![allow(clippy::no_effect, clippy::uninlined_format_args)]
+
+use std::fmt::Debug;
+
+fn foo<T: Debug>(t: T) {
+    println!("{:?}", t);
+}
+
+fn foo3<T1: Debug, T2: Debug, T3: Debug>(t1: T1, t2: T2, t3: T3) {
+    println!("{:?}, {:?}, {:?}", t1, t2, t3);
+}
+
+fn bad() {
+    foo(());
+    //~^ unit_arg
+    foo3((), 2, 2);
+    //~^ unit_arg
+    foo(0);
+    taking_two_units((), ());
+    //~^ unit_arg
+    foo(0);
+    foo(1);
+    taking_three_units((), (), ());
+    //~^ unit_arg
+}
+
+fn taking_two_units(a: (), b: ()) {}
+fn taking_three_units(a: (), b: (), c: ()) {}
+
+fn main() {
+    bad();
+}
+
+fn issue14857() {
+    let fn_take_unit = |_: ()| {};
+    fn_take_unit(());
+    //~^ unit_arg
+
+    fn some_other_fn(_: &i32) {}
+
+    macro_rules! another_mac {
+        () => {
+            some_other_fn(&Default::default())
+        };
+        ($e:expr) => {
+            some_other_fn(&$e)
+        };
+    }
+
+    another_mac!();
+    fn_take_unit(());
+    //~^ unit_arg
+    another_mac!(1);
+    fn_take_unit(());
+    //~^ unit_arg
+
+    macro_rules! mac {
+        (nondef $e:expr) => {
+            $e
+        };
+        (empty_block) => {{}};
+    }
+    fn_take_unit(mac!(nondef ()));
+    //~^ unit_arg
+    mac!(empty_block);
+    fn_take_unit(());
+    //~^ unit_arg
+
+    fn def<T: Default>() -> T {
+        Default::default()
+    }
+
+    let _: () = def();
+    fn_take_unit(());
+    //~^ unit_arg
+}
diff --git a/src/tools/clippy/tests/ui/unit_arg_fixable.rs b/src/tools/clippy/tests/ui/unit_arg_fixable.rs
new file mode 100644
index 00000000000..03fd96efdf9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unit_arg_fixable.rs
@@ -0,0 +1,71 @@
+#![warn(clippy::unit_arg)]
+#![allow(unused_must_use, unused_variables)]
+#![allow(clippy::no_effect, clippy::uninlined_format_args)]
+
+use std::fmt::Debug;
+
+fn foo<T: Debug>(t: T) {
+    println!("{:?}", t);
+}
+
+fn foo3<T1: Debug, T2: Debug, T3: Debug>(t1: T1, t2: T2, t3: T3) {
+    println!("{:?}, {:?}, {:?}", t1, t2, t3);
+}
+
+fn bad() {
+    foo({});
+    //~^ unit_arg
+    foo3({}, 2, 2);
+    //~^ unit_arg
+    taking_two_units({}, foo(0));
+    //~^ unit_arg
+    taking_three_units({}, foo(0), foo(1));
+    //~^ unit_arg
+}
+
+fn taking_two_units(a: (), b: ()) {}
+fn taking_three_units(a: (), b: (), c: ()) {}
+
+fn main() {
+    bad();
+}
+
+fn issue14857() {
+    let fn_take_unit = |_: ()| {};
+    fn_take_unit(Default::default());
+    //~^ unit_arg
+
+    fn some_other_fn(_: &i32) {}
+
+    macro_rules! another_mac {
+        () => {
+            some_other_fn(&Default::default())
+        };
+        ($e:expr) => {
+            some_other_fn(&$e)
+        };
+    }
+
+    fn_take_unit(another_mac!());
+    //~^ unit_arg
+    fn_take_unit(another_mac!(1));
+    //~^ unit_arg
+
+    macro_rules! mac {
+        (nondef $e:expr) => {
+            $e
+        };
+        (empty_block) => {{}};
+    }
+    fn_take_unit(mac!(nondef Default::default()));
+    //~^ unit_arg
+    fn_take_unit(mac!(empty_block));
+    //~^ unit_arg
+
+    fn def<T: Default>() -> T {
+        Default::default()
+    }
+
+    fn_take_unit(def());
+    //~^ unit_arg
+}
diff --git a/src/tools/clippy/tests/ui/unit_arg_fixable.stderr b/src/tools/clippy/tests/ui/unit_arg_fixable.stderr
new file mode 100644
index 00000000000..ccd5aa8322f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unit_arg_fixable.stderr
@@ -0,0 +1,110 @@
+error: passing a unit value to a function
+  --> tests/ui/unit_arg_fixable.rs:16:5
+   |
+LL |     foo({});
+   |     ^^^^--^
+   |         |
+   |         help: use a unit literal instead: `()`
+   |
+   = note: `-D clippy::unit-arg` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::unit_arg)]`
+
+error: passing a unit value to a function
+  --> tests/ui/unit_arg_fixable.rs:18:5
+   |
+LL |     foo3({}, 2, 2);
+   |     ^^^^^--^^^^^^^
+   |          |
+   |          help: use a unit literal instead: `()`
+
+error: passing unit values to a function
+  --> tests/ui/unit_arg_fixable.rs:20:5
+   |
+LL |     taking_two_units({}, foo(0));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: move the expression in front of the call and replace it with the unit literal `()`
+   |
+LL ~     foo(0);
+LL ~     taking_two_units((), ());
+   |
+
+error: passing unit values to a function
+  --> tests/ui/unit_arg_fixable.rs:22:5
+   |
+LL |     taking_three_units({}, foo(0), foo(1));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: move the expressions in front of the call and replace them with the unit literal `()`
+   |
+LL ~     foo(0);
+LL +     foo(1);
+LL ~     taking_three_units((), (), ());
+   |
+
+error: passing a unit value to a function
+  --> tests/ui/unit_arg_fixable.rs:35:5
+   |
+LL |     fn_take_unit(Default::default());
+   |     ^^^^^^^^^^^^^------------------^
+   |                  |
+   |                  help: use a unit literal instead: `()`
+
+error: passing a unit value to a function
+  --> tests/ui/unit_arg_fixable.rs:49:5
+   |
+LL |     fn_take_unit(another_mac!());
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: move the expression in front of the call and replace it with the unit literal `()`
+   |
+LL ~     another_mac!();
+LL ~     fn_take_unit(());
+   |
+
+error: passing a unit value to a function
+  --> tests/ui/unit_arg_fixable.rs:51:5
+   |
+LL |     fn_take_unit(another_mac!(1));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: move the expression in front of the call and replace it with the unit literal `()`
+   |
+LL ~     another_mac!(1);
+LL ~     fn_take_unit(());
+   |
+
+error: passing a unit value to a function
+  --> tests/ui/unit_arg_fixable.rs:60:5
+   |
+LL |     fn_take_unit(mac!(nondef Default::default()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^------------------^^
+   |                              |
+   |                              help: use a unit literal instead: `()`
+
+error: passing a unit value to a function
+  --> tests/ui/unit_arg_fixable.rs:62:5
+   |
+LL |     fn_take_unit(mac!(empty_block));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: move the expression in front of the call and replace it with the unit literal `()`
+   |
+LL ~     mac!(empty_block);
+LL ~     fn_take_unit(());
+   |
+
+error: passing a unit value to a function
+  --> tests/ui/unit_arg_fixable.rs:69:5
+   |
+LL |     fn_take_unit(def());
+   |     ^^^^^^^^^^^^^^^^^^^
+   |
+help: move the expression in front of the call and replace it with the unit literal `()`
+   |
+LL ~     let _: () = def();
+LL ~     fn_take_unit(());
+   |
+
+error: aborting due to 10 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed b/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed
index 93dd58b8e9d..def8ef86e3c 100644
--- a/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed
+++ b/src/tools/clippy/tests/ui/unused_unit.edition2021.fixed
@@ -143,4 +143,10 @@ mod issue14577 {
             todo!()
         }
     }
-}
\ No newline at end of file
+}
+
+mod pr14962 {
+    #[allow(unused_parens)]
+    type UnusedParensButNoUnit = Box<dyn (Fn())>;
+}
+
diff --git a/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed b/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed
index 987d901b97d..f908b958b19 100644
--- a/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed
+++ b/src/tools/clippy/tests/ui/unused_unit.edition2024.fixed
@@ -143,4 +143,10 @@ mod issue14577 {
             todo!()
         }
     }
-}
\ No newline at end of file
+}
+
+mod pr14962 {
+    #[allow(unused_parens)]
+    type UnusedParensButNoUnit = Box<dyn (Fn())>;
+}
+
diff --git a/src/tools/clippy/tests/ui/unused_unit.rs b/src/tools/clippy/tests/ui/unused_unit.rs
index b7645f7b6a2..7298ec40cc2 100644
--- a/src/tools/clippy/tests/ui/unused_unit.rs
+++ b/src/tools/clippy/tests/ui/unused_unit.rs
@@ -143,4 +143,10 @@ mod issue14577 {
             todo!()
         }
     }
-}
\ No newline at end of file
+}
+
+mod pr14962 {
+    #[allow(unused_parens)]
+    type UnusedParensButNoUnit = Box<dyn (Fn())>;
+}
+
diff --git a/src/tools/clippy/tests/ui/write_literal.fixed b/src/tools/clippy/tests/ui/write_literal.fixed
index e84f768e33d..29352fd468e 100644
--- a/src/tools/clippy/tests/ui/write_literal.fixed
+++ b/src/tools/clippy/tests/ui/write_literal.fixed
@@ -87,3 +87,15 @@ fn issue_13959() {
 "
     );
 }
+
+fn issue_14930() {
+    let mut v = Vec::new();
+    writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3);
+    //~^ write_literal
+    writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3);
+    //~^ write_literal
+    writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3);
+    //~^ write_literal
+    writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3);
+    //~^ write_literal
+}
diff --git a/src/tools/clippy/tests/ui/write_literal.rs b/src/tools/clippy/tests/ui/write_literal.rs
index fc29fcbede7..92872752759 100644
--- a/src/tools/clippy/tests/ui/write_literal.rs
+++ b/src/tools/clippy/tests/ui/write_literal.rs
@@ -88,3 +88,15 @@ fn issue_13959() {
 "#
     );
 }
+
+fn issue_14930() {
+    let mut v = Vec::new();
+    writeln!(v, "Hello {3} is {0:2$.1$}", 0.01, 2, 3, "x");
+    //~^ write_literal
+    writeln!(v, "Hello {2} is {0:3$.1$}", 0.01, 2, "x", 3);
+    //~^ write_literal
+    writeln!(v, "Hello {1} is {0:3$.2$}", 0.01, "x", 2, 3);
+    //~^ write_literal
+    writeln!(v, "Hello {0} is {1:3$.2$}", "x", 0.01, 2, 3);
+    //~^ write_literal
+}
diff --git a/src/tools/clippy/tests/ui/write_literal.stderr b/src/tools/clippy/tests/ui/write_literal.stderr
index d53c2a7de2e..ca37406c811 100644
--- a/src/tools/clippy/tests/ui/write_literal.stderr
+++ b/src/tools/clippy/tests/ui/write_literal.stderr
@@ -181,5 +181,53 @@ LL +         bar
 LL ~ "
    |
 
-error: aborting due to 14 previous errors
+error: literal with an empty format string
+  --> tests/ui/write_literal.rs:94:55
+   |
+LL |     writeln!(v, "Hello {3} is {0:2$.1$}", 0.01, 2, 3, "x");
+   |                                                       ^^^
+   |
+help: try
+   |
+LL -     writeln!(v, "Hello {3} is {0:2$.1$}", 0.01, 2, 3, "x");
+LL +     writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3);
+   |
+
+error: literal with an empty format string
+  --> tests/ui/write_literal.rs:96:52
+   |
+LL |     writeln!(v, "Hello {2} is {0:3$.1$}", 0.01, 2, "x", 3);
+   |                                                    ^^^
+   |
+help: try
+   |
+LL -     writeln!(v, "Hello {2} is {0:3$.1$}", 0.01, 2, "x", 3);
+LL +     writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3);
+   |
+
+error: literal with an empty format string
+  --> tests/ui/write_literal.rs:98:49
+   |
+LL |     writeln!(v, "Hello {1} is {0:3$.2$}", 0.01, "x", 2, 3);
+   |                                                 ^^^
+   |
+help: try
+   |
+LL -     writeln!(v, "Hello {1} is {0:3$.2$}", 0.01, "x", 2, 3);
+LL +     writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3);
+   |
+
+error: literal with an empty format string
+  --> tests/ui/write_literal.rs:100:43
+   |
+LL |     writeln!(v, "Hello {0} is {1:3$.2$}", "x", 0.01, 2, 3);
+   |                                           ^^^
+   |
+help: try
+   |
+LL -     writeln!(v, "Hello {0} is {1:3$.2$}", "x", 0.01, 2, 3);
+LL +     writeln!(v, "Hello x is {0:2$.1$}", 0.01, 2, 3);
+   |
+
+error: aborting due to 18 previous errors
 
diff --git a/src/tools/clippy/tests/ui/zombie_processes.rs b/src/tools/clippy/tests/ui/zombie_processes.rs
index 395f9dd2def..e81b5fd4f3e 100644
--- a/src/tools/clippy/tests/ui/zombie_processes.rs
+++ b/src/tools/clippy/tests/ui/zombie_processes.rs
@@ -198,3 +198,13 @@ mod issue14677 {
         child.wait().unwrap();
     }
 }
+
+fn issue14911() -> std::io::Result<String> {
+    let (mut recv, send) = std::io::pipe()?;
+    let mut command = Command::new("ls")
+        .stdout(send.try_clone()?)
+        .spawn()
+        .expect("Could not spawn new process...");
+    command.wait()?;
+    Ok("".into())
+}
diff --git a/src/tools/clippy/util/gh-pages/script.js b/src/tools/clippy/util/gh-pages/script.js
index fec883938d6..285aa34e701 100644
--- a/src/tools/clippy/util/gh-pages/script.js
+++ b/src/tools/clippy/util/gh-pages/script.js
@@ -602,7 +602,7 @@ filters.filterLints();
 updateLintCount();
 
 function updateLintCount() {
-    const allLints = filters.getAllLints();
+    const allLints = filters.getAllLints().filter(lint => lint.group != "deprecated");
     const totalLints = allLints.length;
     
     const countElement = document.getElementById("lint-count");
diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs
index 1406553c9ea..2ecb4fc8652 100644
--- a/src/tools/compiletest/src/directive-list.rs
+++ b/src/tools/compiletest/src/directive-list.rs
@@ -166,6 +166,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "needs-subprocess",
     "needs-symlink",
     "needs-target-has-atomic",
+    "needs-target-std",
     "needs-threads",
     "needs-unwind",
     "needs-wasmtime",
diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs
index 2ace40c490b..b1165f4bb18 100644
--- a/src/tools/compiletest/src/header/needs.rs
+++ b/src/tools/compiletest/src/header/needs.rs
@@ -174,6 +174,11 @@ pub(super) fn handle_needs(
             condition: config.with_std_debug_assertions,
             ignore_reason: "ignored if std wasn't built with debug assertions",
         },
+        Need {
+            name: "needs-target-std",
+            condition: build_helper::targets::target_supports_std(&config.target),
+            ignore_reason: "ignored if target does not support std",
+        },
     ];
 
     let (name, rest) = match ln.split_once([':', ' ']) {
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index e7e5ff0ab00..31b49b09bcd 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -945,3 +945,14 @@ fn test_ignore_auxiliary() {
     let config = cfg().build();
     assert!(check_ignore(&config, "//@ ignore-auxiliary"));
 }
+
+#[test]
+fn test_needs_target_std() {
+    // Cherry-picks two targets:
+    // 1. `x86_64-unknown-none`: Tier 2, intentionally never supports std.
+    // 2. `x86_64-unknown-linux-gnu`: Tier 1, always supports std.
+    let config = cfg().target("x86_64-unknown-none").build();
+    assert!(check_ignore(&config, "//@ needs-target-std"));
+    let config = cfg().target("x86_64-unknown-linux-gnu").build();
+    assert!(!check_ignore(&config, "//@ needs-target-std"));
+}
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index fc7942a49c0..5554c7975ff 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -286,6 +286,11 @@ environment variable. We first document the most relevant and most commonly used
   specific circumstances, but Miri's behavior will also be more stable across versions and targets.
   This is equivalent to `-Zmiri-fixed-schedule -Zmiri-compare-exchange-weak-failure-rate=0.0
   -Zmiri-address-reuse-cross-thread-rate=0.0 -Zmiri-disable-weak-memory-emulation`.
+* `-Zmiri-deterministic-floats` makes Miri's floating-point behavior fully deterministic. This means
+  that operations will always return the preferred NaN, imprecise operations will not have any
+  random error applied to them, and `min`/`max` as "maybe fused" multiply-add all behave
+  deterministically. Note that Miri still uses host floats for some operations, so behavior can
+  still differ depending on the host target and setup.
 * `-Zmiri-disable-isolation` disables host isolation. As a consequence,
   the program has access to host resources such as environment variables, file
   systems, and randomness.
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 2faaec5a174..d4ba7fbd6a4 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -601,6 +601,8 @@ fn main() {
             miri_config.collect_leak_backtraces = false;
         } else if arg == "-Zmiri-force-intrinsic-fallback" {
             miri_config.force_intrinsic_fallback = true;
+        } else if arg == "-Zmiri-deterministic-floats" {
+            miri_config.float_nondet = false;
         } else if arg == "-Zmiri-strict-provenance" {
             miri_config.provenance_mode = ProvenanceMode::Strict;
         } else if arg == "-Zmiri-permissive-provenance" {
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 6f5f756e144..7a5f96ec177 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -166,6 +166,8 @@ pub struct MiriConfig {
     pub fixed_scheduling: bool,
     /// Always prefer the intrinsic fallback body over the native Miri implementation.
     pub force_intrinsic_fallback: bool,
+    /// Whether floating-point operations can behave non-deterministically.
+    pub float_nondet: bool,
 }
 
 impl Default for MiriConfig {
@@ -205,6 +207,7 @@ impl Default for MiriConfig {
             address_reuse_cross_thread_rate: 0.1,
             fixed_scheduling: false,
             force_intrinsic_fallback: false,
+            float_nondet: true,
         }
     }
 }
diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs
index 9957e351ff1..458b7723299 100644
--- a/src/tools/miri/src/intrinsics/mod.rs
+++ b/src/tools/miri/src/intrinsics/mod.rs
@@ -272,8 +272,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let a = this.read_scalar(a)?.to_f32()?;
                 let b = this.read_scalar(b)?.to_f32()?;
                 let c = this.read_scalar(c)?.to_f32()?;
-                // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
-                let res = a.to_host().mul_add(b.to_host(), c.to_host()).to_soft();
+                let res = a.mul_add(b, c).value;
                 let res = this.adjust_nan(res, &[a, b, c]);
                 this.write_scalar(res, dest)?;
             }
@@ -282,8 +281,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let a = this.read_scalar(a)?.to_f64()?;
                 let b = this.read_scalar(b)?.to_f64()?;
                 let c = this.read_scalar(c)?.to_f64()?;
-                // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
-                let res = a.to_host().mul_add(b.to_host(), c.to_host()).to_soft();
+                let res = a.mul_add(b, c).value;
                 let res = this.adjust_nan(res, &[a, b, c]);
                 this.write_scalar(res, dest)?;
             }
@@ -293,10 +291,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let a = this.read_scalar(a)?.to_f32()?;
                 let b = this.read_scalar(b)?.to_f32()?;
                 let c = this.read_scalar(c)?.to_f32()?;
-                let fuse: bool = this.machine.rng.get_mut().random();
+                let fuse: bool = this.machine.float_nondet && this.machine.rng.get_mut().random();
                 let res = if fuse {
-                    // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
-                    a.to_host().mul_add(b.to_host(), c.to_host()).to_soft()
+                    a.mul_add(b, c).value
                 } else {
                     ((a * b).value + c).value
                 };
@@ -308,10 +305,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let a = this.read_scalar(a)?.to_f64()?;
                 let b = this.read_scalar(b)?.to_f64()?;
                 let c = this.read_scalar(c)?.to_f64()?;
-                let fuse: bool = this.machine.rng.get_mut().random();
+                let fuse: bool = this.machine.float_nondet && this.machine.rng.get_mut().random();
                 let res = if fuse {
-                    // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
-                    a.to_host().mul_add(b.to_host(), c.to_host()).to_soft()
+                    a.mul_add(b, c).value
                 } else {
                     ((a * b).value + c).value
                 };
diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs
index b17fd4fb7f9..dbe193bdbda 100644
--- a/src/tools/miri/src/intrinsics/simd.rs
+++ b/src/tools/miri/src/intrinsics/simd.rs
@@ -306,7 +306,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     let c = this.read_scalar(&this.project_index(&c, i)?)?;
                     let dest = this.project_index(&dest, i)?;
 
-                    let fuse: bool = intrinsic_name == "fma" || this.machine.rng.get_mut().random();
+                    let fuse: bool = intrinsic_name == "fma"
+                        || (this.machine.float_nondet && this.machine.rng.get_mut().random());
 
                     // Works for f32 and f64.
                     // FIXME: using host floats to work around https://github.com/rust-lang/miri/issues/2468.
@@ -320,7 +321,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                             let b = b.to_f32()?;
                             let c = c.to_f32()?;
                             let res = if fuse {
-                                a.to_host().mul_add(b.to_host(), c.to_host()).to_soft()
+                                a.mul_add(b, c).value
                             } else {
                                 ((a * b).value + c).value
                             };
@@ -332,7 +333,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                             let b = b.to_f64()?;
                             let c = c.to_f64()?;
                             let res = if fuse {
-                                a.to_host().mul_add(b.to_host(), c.to_host()).to_soft()
+                                a.mul_add(b, c).value
                             } else {
                                 ((a * b).value + c).value
                             };
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index b221dd85092..b4d7db34efa 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -618,6 +618,9 @@ pub struct MiriMachine<'tcx> {
 
     /// Always prefer the intrinsic fallback body over the native Miri implementation.
     pub force_intrinsic_fallback: bool,
+
+    /// Whether floating-point operations can behave non-deterministically.
+    pub float_nondet: bool,
 }
 
 impl<'tcx> MiriMachine<'tcx> {
@@ -778,6 +781,7 @@ impl<'tcx> MiriMachine<'tcx> {
             int2ptr_warned: Default::default(),
             mangle_internal_symbol_cache: Default::default(),
             force_intrinsic_fallback: config.force_intrinsic_fallback,
+            float_nondet: config.float_nondet,
         }
     }
 
@@ -956,6 +960,7 @@ impl VisitProvenance for MiriMachine<'_> {
             int2ptr_warned: _,
             mangle_internal_symbol_cache: _,
             force_intrinsic_fallback: _,
+            float_nondet: _,
         } = self;
 
         threads.visit_provenance(visit);
diff --git a/src/tools/miri/src/math.rs b/src/tools/miri/src/math.rs
index d1355a21684..cf16a5676d6 100644
--- a/src/tools/miri/src/math.rs
+++ b/src/tools/miri/src/math.rs
@@ -15,6 +15,10 @@ pub(crate) fn apply_random_float_error<F: rustc_apfloat::Float>(
     val: F,
     err_scale: i32,
 ) -> F {
+    if !ecx.machine.float_nondet {
+        return val;
+    }
+
     let rng = ecx.machine.rng.get_mut();
     // Generate a random integer in the range [0, 2^PREC).
     // (When read as binary, the position of the first `1` determines the exponent,
diff --git a/src/tools/miri/src/operator.rs b/src/tools/miri/src/operator.rs
index 81f22b2d0b2..73d671121f6 100644
--- a/src/tools/miri/src/operator.rs
+++ b/src/tools/miri/src/operator.rs
@@ -76,6 +76,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     }
 
     fn generate_nan<F1: Float + FloatConvert<F2>, F2: Float>(&self, inputs: &[F1]) -> F2 {
+        let this = self.eval_context_ref();
+        if !this.machine.float_nondet {
+            return F2::NAN;
+        }
+
         /// Make the given NaN a signaling NaN.
         /// Returns `None` if this would not result in a NaN.
         fn make_signaling<F: Float>(f: F) -> Option<F> {
@@ -89,7 +94,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             if f.is_nan() { Some(f) } else { None }
         }
 
-        let this = self.eval_context_ref();
         let mut rand = this.machine.rng.borrow_mut();
         // Assemble an iterator of possible NaNs: preferred, quieting propagation, unchanged propagation.
         // On some targets there are more possibilities; for now we just generate those options that
@@ -118,6 +122,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
 
     fn equal_float_min_max<F: Float>(&self, a: F, b: F) -> F {
         let this = self.eval_context_ref();
+        if !this.machine.float_nondet {
+            return a;
+        }
         // Return one side non-deterministically.
         let mut rand = this.machine.rng.borrow_mut();
         if rand.random() { a } else { b }
diff --git a/src/tools/rust-analyzer/.github/workflows/autopublish.yaml b/src/tools/rust-analyzer/.github/workflows/autopublish.yaml
index d3f0499e434..6e2be7fd3da 100644
--- a/src/tools/rust-analyzer/.github/workflows/autopublish.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/autopublish.yaml
@@ -28,7 +28,7 @@ jobs:
         run: rustup update --no-self-update stable
 
       - name: Install cargo-workspaces
-        run: cargo install cargo-workspaces
+        run: cargo install cargo-workspaces --version "0.3.6"
 
       - name: Publish Crates
         env:
@@ -54,8 +54,8 @@ jobs:
           cargo workspaces rename --from project-model project_model
           cargo workspaces rename --from test-fixture test_fixture
           cargo workspaces rename --from test-utils test_utils
-          # Remove library crates from the workspaces so we don't auto-publish them as well
-          sed -i 's/ "lib\/\*",//' ./Cargo.toml
+          # Remove library crates and xtask from the workspaces so we don't auto-publish them as well
+          sed -i 's|^members = .*$|members = ["crates/*"]|' Cargo.toml
           cargo workspaces rename ra_ap_%n
           find crates/rust-analyzer -type f -name '*.rs' -exec sed -i 's/rust_analyzer/ra_ap_rust_analyzer/g' {} +
           cargo workspaces publish --yes --force '*' --exact --no-git-commit --allow-dirty --skip-published custom 0.0.$(($RUN_NUMBER + 133))
diff --git a/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml b/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml
index 93ae5675a71..f2c8b6365b6 100644
--- a/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml
@@ -22,7 +22,7 @@ jobs:
         run: rustup update --no-self-update stable
 
       - name: Install cargo-workspaces
-        run: cargo install cargo-workspaces
+        run: cargo install cargo-workspaces --version "0.3.6"
 
       - name: Publish Crates
         env:
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 8c507189846..975fe277b22 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -21,6 +21,8 @@ smol_str.opt-level = 3
 text-size.opt-level = 3
 serde.opt-level = 3
 salsa.opt-level = 3
+dissimilar.opt-level = 3
+
 # This speeds up `cargo xtask dist`.
 miniz_oxide.opt-level = 3
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs
index eed1490a7af..20018b61e5c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map.rs
@@ -67,8 +67,14 @@ pub mod keys {
     pub const PROC_MACRO: Key<ast::Fn, ProcMacroId> = Key::new();
     pub const MACRO_CALL: Key<ast::MacroCall, MacroCallId> = Key::new();
     pub const ATTR_MACRO_CALL: Key<ast::Item, MacroCallId> = Key::new();
-    pub const DERIVE_MACRO_CALL: Key<ast::Attr, (AttrId, MacroCallId, Box<[Option<MacroCallId>]>)> =
-        Key::new();
+    pub const DERIVE_MACRO_CALL: Key<
+        ast::Attr,
+        (
+            AttrId,
+            /* derive() */ MacroCallId,
+            /* actual derive macros */ Box<[Option<MacroCallId>]>,
+        ),
+    > = Key::new();
 
     /// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are
     /// equal if they point to exactly the same object.
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
index cb4fcd887d8..2cc3ca8c752 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
@@ -931,11 +931,12 @@ pub fn new() {
 //                             PATH_TYPE@23..26
 //                               PATH@23..26
 //                                 PATH_SEGMENT@23..26
-//                                   L_ANGLE@23..24 "<"
-//                                   PAREN_TYPE@24..26
-//                                     L_PAREN@24..25 "("
-//                                     ERROR@25..26
-//                                       INT_NUMBER@25..26 "8"
+//                                   TYPE_ANCHOR@23..26
+//                                     L_ANGLE@23..24 "<"
+//                                     PAREN_TYPE@24..26
+//                                       L_PAREN@24..25 "("
+//                                       ERROR@25..26
+//                                         INT_NUMBER@25..26 "8"
 //                           PLUS@26..27 "+"
 //                     CONST_ARG@27..28
 //                       LITERAL@27..28
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
index 980ee264b02..1e985dc604e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
@@ -31,6 +31,7 @@ use crate::{
 #[query_group::query_group]
 pub trait HirDatabase: DefDatabase + std::fmt::Debug {
     #[salsa::invoke(crate::infer::infer_query)]
+    #[salsa::cycle(cycle_result = crate::infer::infer_cycle_result)]
     fn infer(&self, def: DefWithBodyId) -> Arc<InferenceResult>;
 
     // region:mir
@@ -132,6 +133,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
 
     // FIXME: Make this a non-interned query.
     #[salsa::invoke_interned(crate::lower::const_param_ty_with_diagnostics_query)]
+    #[salsa::cycle(cycle_result = crate::lower::const_param_ty_with_diagnostics_cycle_result)]
     fn const_param_ty_with_diagnostics(&self, def: ConstParamId) -> (Ty, Diagnostics);
 
     #[salsa::invoke(crate::lower::const_param_ty_query)]
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index e698fb201cb..14eb7160753 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -35,7 +35,8 @@ use chalk_ir::{
 use either::Either;
 use hir_def::{
     AdtId, AssocItemId, ConstId, DefWithBodyId, FieldId, FunctionId, GenericDefId, GenericParamId,
-    ImplId, ItemContainerId, Lookup, TraitId, TupleFieldId, TupleId, TypeAliasId, VariantId,
+    ImplId, ItemContainerId, LocalFieldId, Lookup, TraitId, TupleFieldId, TupleId, TypeAliasId,
+    VariantId,
     builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
     expr_store::{Body, ExpressionStore, HygieneId, path::Path},
     hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId},
@@ -135,6 +136,10 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
     Arc::new(ctx.resolve_all())
 }
 
+pub(crate) fn infer_cycle_result(_: &dyn HirDatabase, _: DefWithBodyId) -> Arc<InferenceResult> {
+    Arc::new(InferenceResult { has_errors: true, ..Default::default() })
+}
+
 /// Fully normalize all the types found within `ty` in context of `owner` body definition.
 ///
 /// This is appropriate to use only after type-check: it assumes
@@ -203,7 +208,7 @@ pub(crate) type InferResult<T> = Result<InferOk<T>, TypeError>;
 pub enum InferenceDiagnostic {
     NoSuchField {
         field: ExprOrPatId,
-        private: bool,
+        private: Option<LocalFieldId>,
         variant: VariantId,
     },
     PrivateField {
@@ -558,6 +563,9 @@ impl InferenceResult {
             ExprOrPatId::PatId(id) => self.type_of_pat.get(id),
         }
     }
+    pub fn is_erroneous(&self) -> bool {
+        self.has_errors && self.type_of_expr.iter().count() == 0
+    }
 }
 
 impl Index<ExprId> for InferenceResult {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index 87b7f3406ff..64031279296 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -554,7 +554,7 @@ impl InferenceContext<'_> {
                                             self.push_diagnostic(
                                                 InferenceDiagnostic::NoSuchField {
                                                     field: field.expr.into(),
-                                                    private: true,
+                                                    private: Some(local_id),
                                                     variant: def,
                                                 },
                                             );
@@ -564,7 +564,7 @@ impl InferenceContext<'_> {
                                     None => {
                                         self.push_diagnostic(InferenceDiagnostic::NoSuchField {
                                             field: field.expr.into(),
-                                            private: false,
+                                            private: None,
                                             variant: def,
                                         });
                                         None
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
index a9a3265858e..4bc3e167ebf 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
@@ -143,7 +143,7 @@ impl InferenceContext<'_> {
                                 {
                                     self.push_diagnostic(InferenceDiagnostic::NoSuchField {
                                         field: inner.into(),
-                                        private: true,
+                                        private: Some(local_id),
                                         variant: def,
                                     });
                                 }
@@ -157,7 +157,7 @@ impl InferenceContext<'_> {
                             None => {
                                 self.push_diagnostic(InferenceDiagnostic::NoSuchField {
                                     field: inner.into(),
-                                    private: false,
+                                    private: None,
                                     variant: def,
                                 });
                                 self.err_ty()
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index ea8e7cc2be9..0a546768dab 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -1604,6 +1604,14 @@ pub(crate) fn impl_self_ty_with_diagnostics_query(
     )
 }
 
+pub(crate) fn impl_self_ty_with_diagnostics_cycle_result(
+    db: &dyn HirDatabase,
+    impl_id: ImplId,
+) -> (Binders<Ty>, Diagnostics) {
+    let generics = generics(db, impl_id.into());
+    (make_binders(db, &generics, TyKind::Error.intern(Interner)), None)
+}
+
 pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty {
     db.const_param_ty_with_diagnostics(def).0
 }
@@ -1633,12 +1641,12 @@ pub(crate) fn const_param_ty_with_diagnostics_query(
     (ty, create_diagnostics(ctx.diagnostics))
 }
 
-pub(crate) fn impl_self_ty_with_diagnostics_cycle_result(
-    db: &dyn HirDatabase,
-    impl_id: ImplId,
-) -> (Binders<Ty>, Diagnostics) {
-    let generics = generics(db, impl_id.into());
-    (make_binders(db, &generics, TyKind::Error.intern(Interner)), None)
+pub(crate) fn const_param_ty_with_diagnostics_cycle_result(
+    _: &dyn HirDatabase,
+    _: crate::db::HirDatabaseData,
+    _: ConstParamId,
+) -> (Ty, Diagnostics) {
+    (TyKind::Error.intern(Interner), None)
 }
 
 pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
index e6caf2d8d97..99d93515303 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
@@ -2182,7 +2182,7 @@ pub fn lower_to_mir(
     // need to take this input explicitly.
     root_expr: ExprId,
 ) -> Result<MirBody> {
-    if infer.type_mismatches().next().is_some() {
+    if infer.type_mismatches().next().is_some() || infer.is_erroneous() {
         return Err(MirLowerError::HasErrors);
     }
     let mut ctx = MirLowerCtx::new(db, owner, body, infer);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
index 48474d2d26d..e8e3812c69d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
@@ -106,3 +106,256 @@ fn baz() -> i32 {
         assert_eq!(format!("{events:?}").matches("infer_shim").count(), 1, "{events:#?}")
     }
 }
+
+#[test]
+fn adding_struct_invalidates_infer() {
+    let (mut db, pos) = TestDB::with_position(
+        "
+//- /lib.rs
+fn foo() -> i32 {
+    1 + 1
+}
+
+fn bar() -> f32 {
+    2.0 * 3.0
+}
+$0",
+    );
+    {
+        let events = db.log_executed(|| {
+            let module = db.module_for_file(pos.file_id.file_id(&db));
+            let _crate_def_map = module.def_map(&db);
+            db.trait_impls_in_crate(module.krate());
+        });
+        assert!(format!("{events:?}").contains("trait_impls_in_crate_shim"))
+    }
+
+    let new_text = "
+fn foo() -> i32 {
+    1 + 1
+}
+
+fn bar() -> f32 {
+    2.0 * 3.0
+}
+
+pub struct NewStruct {
+    field: i32,
+}
+";
+
+    db.set_file_text(pos.file_id.file_id(&db), new_text);
+
+    {
+        let actual = db.log_executed(|| {
+            let module = db.module_for_file(pos.file_id.file_id(&db));
+            let _crate_def_map = module.def_map(&db);
+            db.trait_impls_in_crate(module.krate());
+        });
+
+        let expected = vec![
+            "parse_shim".to_owned(),
+            "ast_id_map_shim".to_owned(),
+            "file_item_tree_shim".to_owned(),
+            "real_span_map_shim".to_owned(),
+            "crate_local_def_map".to_owned(),
+            "trait_impls_in_crate_shim".to_owned(),
+        ];
+
+        assert_eq!(expected, actual);
+    }
+}
+
+#[test]
+fn adding_enum_query_log() {
+    let (mut db, pos) = TestDB::with_position(
+        "
+//- /lib.rs
+fn foo() -> i32 {
+    1 + 1
+}
+
+fn bar() -> f32 {
+    2.0 * 3.0
+}
+$0",
+    );
+    {
+        let events = db.log_executed(|| {
+            let module = db.module_for_file(pos.file_id.file_id(&db));
+            let _crate_def_map = module.def_map(&db);
+            db.trait_impls_in_crate(module.krate());
+        });
+        assert!(format!("{events:?}").contains("trait_impls_in_crate_shim"))
+    }
+
+    let new_text = "
+fn foo() -> i32 {
+    1 + 1
+}
+
+fn bar() -> f32 {
+    2.0 * 3.0
+}
+
+pub enum SomeEnum {
+    A,
+    B
+}
+";
+
+    db.set_file_text(pos.file_id.file_id(&db), new_text);
+
+    {
+        let actual = db.log_executed(|| {
+            let module = db.module_for_file(pos.file_id.file_id(&db));
+            let _crate_def_map = module.def_map(&db);
+            db.trait_impls_in_crate(module.krate());
+        });
+
+        let expected = vec![
+            "parse_shim".to_owned(),
+            "ast_id_map_shim".to_owned(),
+            "file_item_tree_shim".to_owned(),
+            "real_span_map_shim".to_owned(),
+            "crate_local_def_map".to_owned(),
+            "trait_impls_in_crate_shim".to_owned(),
+        ];
+
+        assert_eq!(expected, actual);
+    }
+}
+
+#[test]
+fn adding_use_query_log() {
+    let (mut db, pos) = TestDB::with_position(
+        "
+//- /lib.rs
+fn foo() -> i32 {
+    1 + 1
+}
+
+fn bar() -> f32 {
+    2.0 * 3.0
+}
+$0",
+    );
+    {
+        let events = db.log_executed(|| {
+            let module = db.module_for_file(pos.file_id.file_id(&db));
+            let _crate_def_map = module.def_map(&db);
+            db.trait_impls_in_crate(module.krate());
+        });
+        assert!(format!("{events:?}").contains("trait_impls_in_crate_shim"))
+    }
+
+    let new_text = "
+use std::collections::HashMap;
+
+fn foo() -> i32 {
+    1 + 1
+}
+
+fn bar() -> f32 {
+    2.0 * 3.0
+}
+";
+
+    db.set_file_text(pos.file_id.file_id(&db), new_text);
+
+    {
+        let actual = db.log_executed(|| {
+            let module = db.module_for_file(pos.file_id.file_id(&db));
+            let _crate_def_map = module.def_map(&db);
+            db.trait_impls_in_crate(module.krate());
+        });
+
+        let expected = vec![
+            "parse_shim".to_owned(),
+            "ast_id_map_shim".to_owned(),
+            "file_item_tree_shim".to_owned(),
+            "real_span_map_shim".to_owned(),
+            "crate_local_def_map".to_owned(),
+            "trait_impls_in_crate_shim".to_owned(),
+        ];
+
+        assert_eq!(expected, actual);
+    }
+}
+
+#[test]
+fn adding_impl_query_log() {
+    let (mut db, pos) = TestDB::with_position(
+        "
+//- /lib.rs
+fn foo() -> i32 {
+    1 + 1
+}
+
+fn bar() -> f32 {
+    2.0 * 3.0
+}
+
+pub struct SomeStruct {
+    field: i32,
+}
+$0",
+    );
+    {
+        let events = db.log_executed(|| {
+            let module = db.module_for_file(pos.file_id.file_id(&db));
+            let _crate_def_map = module.def_map(&db);
+            db.trait_impls_in_crate(module.krate());
+        });
+        assert!(format!("{events:?}").contains("trait_impls_in_crate_shim"))
+    }
+
+    let new_text = "
+fn foo() -> i32 {
+    1 + 1
+}
+
+fn bar() -> f32 {
+    2.0 * 3.0
+}
+
+pub struct SomeStruct {
+    field: i32,
+}
+
+impl SomeStruct {
+    pub fn new(value: i32) -> Self {
+        Self { field: value }
+    }
+}
+";
+
+    db.set_file_text(pos.file_id.file_id(&db), new_text);
+
+    {
+        let actual = db.log_executed(|| {
+            let module = db.module_for_file(pos.file_id.file_id(&db));
+            let _crate_def_map = module.def_map(&db);
+            db.trait_impls_in_crate(module.krate());
+        });
+
+        let expected = vec![
+            "parse_shim".to_owned(),
+            "ast_id_map_shim".to_owned(),
+            "file_item_tree_shim".to_owned(),
+            "real_span_map_shim".to_owned(),
+            "crate_local_def_map".to_owned(),
+            "trait_impls_in_crate_shim".to_owned(),
+            "attrs_shim".to_owned(),
+            "impl_trait_with_diagnostics_shim".to_owned(),
+            "impl_signature_shim".to_owned(),
+            "impl_signature_with_source_map_shim".to_owned(),
+            "impl_self_ty_with_diagnostics_shim".to_owned(),
+            "struct_signature_shim".to_owned(),
+            "struct_signature_with_source_map_shim".to_owned(),
+            "type_for_adt_tracked".to_owned(),
+        ];
+
+        assert_eq!(expected, actual);
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
index 47c695c6974..ff8adeef1db 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
@@ -2301,3 +2301,51 @@ trait Foo {
         "#]],
     );
 }
+
+#[test]
+fn no_panic_on_recursive_const() {
+    check_infer(
+        r#"
+struct Foo<const N: usize> {}
+impl<const N: Foo<N>> Foo<N> {
+    fn foo(self) {}
+}
+
+fn test() {
+    let _ = N;
+}
+"#,
+        expect![[r#"
+            72..76 'self': Foo<N>
+            78..80 '{}': ()
+            94..112 '{     ...= N; }': ()
+            104..105 '_': {unknown}
+            108..109 'N': {unknown}
+        "#]],
+    );
+
+    check_infer(
+        r#"
+struct Foo<const N: usize>;
+const N: Foo<N> = Foo;
+
+impl<const N: usize> Foo<N> {
+    fn foo(self) -> usize {
+        N
+    }
+}
+
+fn test() {
+    let _ = N;
+}
+"#,
+        expect![[r#"
+            93..97 'self': Foo<N>
+            108..125 '{     ...     }': usize
+            118..119 'N': usize
+            139..157 '{     ...= N; }': ()
+            149..150 '_': Foo<_>
+            153..154 'N': Foo<_>
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
index b6e3002ed5d..f7b140e03d4 100644
--- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
@@ -224,7 +224,7 @@ pub struct MalformedDerive {
 #[derive(Debug)]
 pub struct NoSuchField {
     pub field: InFile<AstPtr<Either<ast::RecordExprField, ast::RecordPatField>>>,
-    pub private: bool,
+    pub private: Option<Field>,
     pub variant: VariantId,
 }
 
@@ -648,6 +648,7 @@ impl AnyDiagnostic {
                     }
                     ExprOrPatId::PatId(pat) => source_map.pat_field_syntax(pat),
                 };
+                let private = private.map(|id| Field { id, parent: variant.into() });
                 NoSuchField { field: expr_or_pat, private, variant }.into()
             }
             &InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index e01774650b1..4a2e8e379fb 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -222,6 +222,21 @@ impl<DB: HirDatabase> Semantics<'_, DB> {
         self.imp.descend_node_at_offset(node, offset).filter_map(|mut it| it.find_map(N::cast))
     }
 
+    // FIXME: Rethink this API
+    pub fn find_namelike_at_offset_with_descend<'slf>(
+        &'slf self,
+        node: &SyntaxNode,
+        offset: TextSize,
+    ) -> impl Iterator<Item = ast::NameLike> + 'slf {
+        node.token_at_offset(offset)
+            .map(move |token| self.descend_into_macros_no_opaque(token))
+            .map(|descendants| descendants.into_iter().filter_map(move |it| it.value.parent()))
+            // re-order the tokens from token_at_offset by returning the ancestors with the smaller first nodes first
+            // See algo::ancestors_at_offset, which uses the same approach
+            .kmerge_by(|left, right| left.text_range().len().lt(&right.text_range().len()))
+            .filter_map(ast::NameLike::cast)
+    }
+
     pub fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<Struct> {
         self.imp.resolve_range_pat(range_pat).map(Struct::from)
     }
@@ -535,7 +550,7 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     pub fn is_derive_annotated(&self, adt: InFile<&ast::Adt>) -> bool {
-        self.with_ctx(|ctx| ctx.has_derives(adt))
+        self.with_ctx(|ctx| ctx.file_of_adt_has_derives(adt))
     }
 
     pub fn derive_helpers_in_scope(&self, adt: &ast::Adt) -> Option<Vec<(Symbol, Symbol)>> {
@@ -644,7 +659,7 @@ impl<'db> SemanticsImpl<'db> {
 
     /// Checks if renaming `renamed` to `new_name` may introduce conflicts with other locals,
     /// and returns the conflicting locals.
-    pub fn rename_conflicts(&self, to_be_renamed: &Local, new_name: &str) -> Vec<Local> {
+    pub fn rename_conflicts(&self, to_be_renamed: &Local, new_name: &Name) -> Vec<Local> {
         let body = self.db.body(to_be_renamed.parent);
         let resolver = to_be_renamed.parent.resolver(self.db);
         let starting_expr =
@@ -653,7 +668,7 @@ impl<'db> SemanticsImpl<'db> {
             body: &body,
             conflicts: FxHashSet::default(),
             db: self.db,
-            new_name: Symbol::intern(new_name),
+            new_name: new_name.symbol().clone(),
             old_name: to_be_renamed.name(self.db).symbol().clone(),
             owner: to_be_renamed.parent,
             to_be_renamed: to_be_renamed.binding_id,
@@ -877,8 +892,9 @@ impl<'db> SemanticsImpl<'db> {
 
         if first == last {
             // node is just the token, so descend the token
-            self.descend_into_macros_impl(
+            self.descend_into_macros_all(
                 InFile::new(file.file_id, first),
+                false,
                 &mut |InFile { value, .. }, _ctx| {
                     if let Some(node) = value
                         .parent_ancestors()
@@ -887,20 +903,21 @@ impl<'db> SemanticsImpl<'db> {
                     {
                         res.push(node)
                     }
-                    CONTINUE_NO_BREAKS
                 },
             );
         } else {
             // Descend first and last token, then zip them to look for the node they belong to
             let mut scratch: SmallVec<[_; 1]> = smallvec![];
-            self.descend_into_macros_impl(InFile::new(file.file_id, first), &mut |token, _ctx| {
-                scratch.push(token);
-                CONTINUE_NO_BREAKS
-            });
+            self.descend_into_macros_all(
+                InFile::new(file.file_id, first),
+                false,
+                &mut |token, _ctx| scratch.push(token),
+            );
 
             let mut scratch = scratch.into_iter();
-            self.descend_into_macros_impl(
+            self.descend_into_macros_all(
                 InFile::new(file.file_id, last),
+                false,
                 &mut |InFile { value: last, file_id: last_fid }, _ctx| {
                     if let Some(InFile { value: first, file_id: first_fid }) = scratch.next() {
                         if first_fid == last_fid {
@@ -917,17 +934,18 @@ impl<'db> SemanticsImpl<'db> {
                             }
                         }
                     }
-                    CONTINUE_NO_BREAKS
                 },
             );
         }
         res
     }
 
-    pub fn is_inside_macro_call(&self, token: InFile<&SyntaxToken>) -> bool {
-        // FIXME: Maybe `ancestors_with_macros()` is more suitable here? Currently
-        // this is only used on real (not macro) files so this is not a problem.
-        token.value.parent_ancestors().any(|ancestor| {
+    /// Returns true if the given input is within a macro call.
+    ///
+    /// Note that if this token itself is within the context of a macro expansion does not matter.
+    /// That is, we strictly check if it lies inside the input of a macro call.
+    pub fn is_inside_macro_call(&self, token @ InFile { value, .. }: InFile<&SyntaxToken>) -> bool {
+        value.parent_ancestors().any(|ancestor| {
             if ast::MacroCall::can_cast(ancestor.kind()) {
                 return true;
             }
@@ -952,7 +970,7 @@ impl<'db> SemanticsImpl<'db> {
                     ast::Item::Union(it) => it.into(),
                     _ => return false,
                 };
-                ctx.has_derives(token.with_value(&adt))
+                ctx.file_of_adt_has_derives(token.with_value(&adt))
             })
         })
     }
@@ -962,18 +980,18 @@ impl<'db> SemanticsImpl<'db> {
         token: SyntaxToken,
         mut cb: impl FnMut(InFile<SyntaxToken>, SyntaxContext),
     ) {
-        self.descend_into_macros_impl(self.wrap_token_infile(token), &mut |t, ctx| {
-            cb(t, ctx);
-            CONTINUE_NO_BREAKS
+        self.descend_into_macros_all(self.wrap_token_infile(token), false, &mut |t, ctx| {
+            cb(t, ctx)
         });
     }
 
     pub fn descend_into_macros(&self, token: SyntaxToken) -> SmallVec<[SyntaxToken; 1]> {
         let mut res = smallvec![];
-        self.descend_into_macros_impl(self.wrap_token_infile(token.clone()), &mut |t, _ctx| {
-            res.push(t.value);
-            CONTINUE_NO_BREAKS
-        });
+        self.descend_into_macros_all(
+            self.wrap_token_infile(token.clone()),
+            false,
+            &mut |t, _ctx| res.push(t.value),
+        );
         if res.is_empty() {
             res.push(token);
         }
@@ -986,12 +1004,11 @@ impl<'db> SemanticsImpl<'db> {
     ) -> SmallVec<[InFile<SyntaxToken>; 1]> {
         let mut res = smallvec![];
         let token = self.wrap_token_infile(token);
-        self.descend_into_macros_impl(token.clone(), &mut |t, ctx| {
+        self.descend_into_macros_all(token.clone(), true, &mut |t, ctx| {
             if !ctx.is_opaque(self.db) {
                 // Don't descend into opaque contexts
                 res.push(t);
             }
-            CONTINUE_NO_BREAKS
         });
         if res.is_empty() {
             res.push(token);
@@ -1004,7 +1021,7 @@ impl<'db> SemanticsImpl<'db> {
         token: InFile<SyntaxToken>,
         mut cb: impl FnMut(InFile<SyntaxToken>, SyntaxContext) -> ControlFlow<T>,
     ) -> Option<T> {
-        self.descend_into_macros_impl(token, &mut cb)
+        self.descend_into_macros_impl(token, false, &mut cb)
     }
 
     /// Descends the token into expansions, returning the tokens that matches the input
@@ -1074,44 +1091,56 @@ impl<'db> SemanticsImpl<'db> {
         .unwrap_or(token)
     }
 
+    fn descend_into_macros_all(
+        &self,
+        token: InFile<SyntaxToken>,
+        always_descend_into_derives: bool,
+        f: &mut dyn FnMut(InFile<SyntaxToken>, SyntaxContext),
+    ) {
+        self.descend_into_macros_impl(token, always_descend_into_derives, &mut |tok, ctx| {
+            f(tok, ctx);
+            CONTINUE_NO_BREAKS
+        });
+    }
+
     fn descend_into_macros_impl<T>(
         &self,
         InFile { value: token, file_id }: InFile<SyntaxToken>,
+        always_descend_into_derives: bool,
         f: &mut dyn FnMut(InFile<SyntaxToken>, SyntaxContext) -> ControlFlow<T>,
     ) -> Option<T> {
         let _p = tracing::info_span!("descend_into_macros_impl").entered();
 
-        let span = self.db.span_map(file_id).span_for_range(token.text_range());
+        let db = self.db;
+        let span = db.span_map(file_id).span_for_range(token.text_range());
 
         // Process the expansion of a call, pushing all tokens with our span in the expansion back onto our stack
-        let process_expansion_for_token = |stack: &mut Vec<_>, macro_file| {
-            let InMacroFile { file_id, value: mapped_tokens } = self.with_ctx(|ctx| {
-                Some(
-                    ctx.cache
-                        .get_or_insert_expansion(ctx.db, macro_file)
-                        .map_range_down(span)?
-                        .map(SmallVec::<[_; 2]>::from_iter),
-                )
-            })?;
-            // we have found a mapping for the token if the vec is non-empty
-            let res = mapped_tokens.is_empty().not().then_some(());
-            // requeue the tokens we got from mapping our current token down
-            stack.push((HirFileId::from(file_id), mapped_tokens));
-            res
-        };
+        let process_expansion_for_token =
+            |ctx: &mut SourceToDefCtx<'_, '_>, stack: &mut Vec<_>, macro_file| {
+                let InMacroFile { file_id, value: mapped_tokens } = ctx
+                    .cache
+                    .get_or_insert_expansion(ctx.db, macro_file)
+                    .map_range_down(span)?
+                    .map(SmallVec::<[_; 2]>::from_iter);
+                // we have found a mapping for the token if the vec is non-empty
+                let res = mapped_tokens.is_empty().not().then_some(());
+                // requeue the tokens we got from mapping our current token down
+                stack.push((HirFileId::from(file_id), mapped_tokens));
+                res
+            };
 
         // A stack of tokens to process, along with the file they came from
         // These are tracked to know which macro calls we still have to look into
         // the tokens themselves aren't that interesting as the span that is being used to map
         // things down never changes.
         let mut stack: Vec<(_, SmallVec<[_; 2]>)> = vec![];
-        let include = file_id.file_id().and_then(|file_id| {
-            self.s2d_cache.borrow_mut().get_or_insert_include_for(self.db, file_id)
-        });
+        let include = file_id
+            .file_id()
+            .and_then(|file_id| self.s2d_cache.borrow_mut().get_or_insert_include_for(db, file_id));
         match include {
             Some(include) => {
                 // include! inputs are always from real files, so they only need to be handled once upfront
-                process_expansion_for_token(&mut stack, include)?;
+                self.with_ctx(|ctx| process_expansion_for_token(ctx, &mut stack, include))?;
             }
             None => {
                 stack.push((file_id, smallvec![(token, span.ctx)]));
@@ -1133,62 +1162,120 @@ impl<'db> SemanticsImpl<'db> {
             tokens.reverse();
             while let Some((token, ctx)) = tokens.pop() {
                 let was_not_remapped = (|| {
-                    // First expand into attribute invocations
-                    let containing_attribute_macro_call = self.with_ctx(|ctx| {
-                        token.parent_ancestors().filter_map(ast::Item::cast).find_map(|item| {
-                            // Don't force populate the dyn cache for items that don't have an attribute anyways
-                            item.attrs().next()?;
-                            Some((ctx.item_to_macro_call(InFile::new(expansion, &item))?, item))
-                        })
-                    });
-                    if let Some((call_id, item)) = containing_attribute_macro_call {
-                        let attr_id = match self.db.lookup_intern_macro_call(call_id).kind {
-                            hir_expand::MacroCallKind::Attr { invoc_attr_index, .. } => {
-                                invoc_attr_index.ast_index()
-                            }
-                            _ => 0,
-                        };
-                        // FIXME: here, the attribute's text range is used to strip away all
-                        // entries from the start of the attribute "list" up the invoking
-                        // attribute. But in
-                        // ```
-                        // mod foo {
-                        //     #![inner]
-                        // }
-                        // ```
-                        // we don't wanna strip away stuff in the `mod foo {` range, that is
-                        // here if the id corresponds to an inner attribute we got strip all
-                        // text ranges of the outer ones, and then all of the inner ones up
-                        // to the invoking attribute so that the inbetween is ignored.
-                        let text_range = item.syntax().text_range();
-                        let start = collect_attrs(&item)
-                            .nth(attr_id)
-                            .map(|attr| match attr.1 {
-                                Either::Left(it) => it.syntax().text_range().start(),
-                                Either::Right(it) => it.syntax().text_range().start(),
+                    // First expand into attribute invocations, this is required to be handled
+                    // upfront as any other macro call within will not semantically resolve unless
+                    // also descended.
+                    let res = self.with_ctx(|ctx| {
+                        token
+                            .parent_ancestors()
+                            .filter_map(ast::Item::cast)
+                            // FIXME: This might work incorrectly when we have a derive, followed by
+                            // an attribute on an item, like:
+                            // ```
+                            // #[derive(Debug$0)]
+                            // #[my_attr]
+                            // struct MyStruct;
+                            // ```
+                            // here we should not consider the attribute at all, as our cursor
+                            // technically lies outside of its expansion
+                            .find_map(|item| {
+                                // Don't force populate the dyn cache for items that don't have an attribute anyways
+                                item.attrs().next()?;
+                                ctx.item_to_macro_call(InFile::new(expansion, &item))
+                                    .zip(Some(item))
                             })
-                            .unwrap_or_else(|| text_range.start());
-                        let text_range = TextRange::new(start, text_range.end());
-                        filter_duplicates(tokens, text_range);
-                        return process_expansion_for_token(&mut stack, call_id);
+                            .map(|(call_id, item)| {
+                                let attr_id = match db.lookup_intern_macro_call(call_id).kind {
+                                    hir_expand::MacroCallKind::Attr {
+                                        invoc_attr_index, ..
+                                    } => invoc_attr_index.ast_index(),
+                                    _ => 0,
+                                };
+                                // FIXME: here, the attribute's text range is used to strip away all
+                                // entries from the start of the attribute "list" up the invoking
+                                // attribute. But in
+                                // ```
+                                // mod foo {
+                                //     #![inner]
+                                // }
+                                // ```
+                                // we don't wanna strip away stuff in the `mod foo {` range, that is
+                                // here if the id corresponds to an inner attribute we got strip all
+                                // text ranges of the outer ones, and then all of the inner ones up
+                                // to the invoking attribute so that the inbetween is ignored.
+                                let text_range = item.syntax().text_range();
+                                let start = collect_attrs(&item)
+                                    .nth(attr_id)
+                                    .map(|attr| match attr.1 {
+                                        Either::Left(it) => it.syntax().text_range().start(),
+                                        Either::Right(it) => it.syntax().text_range().start(),
+                                    })
+                                    .unwrap_or_else(|| text_range.start());
+                                let text_range = TextRange::new(start, text_range.end());
+                                filter_duplicates(tokens, text_range);
+                                process_expansion_for_token(ctx, &mut stack, call_id)
+                            })
+                    });
+
+                    if let Some(res) = res {
+                        return res;
                     }
 
+                    if always_descend_into_derives {
+                        let res = self.with_ctx(|ctx| {
+                            let (derives, adt) = token
+                                .parent_ancestors()
+                                .filter_map(ast::Adt::cast)
+                                .find_map(|adt| {
+                                    Some((
+                                        ctx.derive_macro_calls(InFile::new(expansion, &adt))?
+                                            .map(|(a, b, c)| (a, b, c.to_owned()))
+                                            .collect::<SmallVec<[_; 2]>>(),
+                                        adt,
+                                    ))
+                                })?;
+                            let mut res = None;
+                            for (_, derive_attr, derives) in derives {
+                                // as there may be multiple derives registering the same helper
+                                // name, we gotta make sure to call this for all of them!
+                                // FIXME: We need to call `f` for all of them as well though!
+                                res = res.or(process_expansion_for_token(
+                                    ctx,
+                                    &mut stack,
+                                    derive_attr,
+                                ));
+                                for derive in derives.into_iter().flatten() {
+                                    res = res
+                                        .or(process_expansion_for_token(ctx, &mut stack, derive));
+                                }
+                            }
+                            // remove all tokens that are within the derives expansion
+                            filter_duplicates(tokens, adt.syntax().text_range());
+                            Some(res)
+                        });
+                        // if we found derives, we can early exit. There is no way we can be in any
+                        // macro call at this point given we are not in a token tree
+                        if let Some(res) = res {
+                            return res;
+                        }
+                    }
                     // Then check for token trees, that means we are either in a function-like macro or
                     // secondary attribute inputs
                     let tt = token
                         .parent_ancestors()
                         .map_while(Either::<ast::TokenTree, ast::Meta>::cast)
                         .last()?;
+
                     match tt {
                         // function-like macro call
                         Either::Left(tt) => {
+                            let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?;
                             if tt.left_delimiter_token().map_or(false, |it| it == token) {
                                 return None;
                             }
                             if tt.right_delimiter_token().map_or(false, |it| it == token) {
                                 return None;
                             }
-                            let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?;
                             let mcall = InFile::new(expansion, macro_call);
                             let file_id = match m_cache.get(&mcall) {
                                 Some(&it) => it,
@@ -1201,13 +1288,16 @@ impl<'db> SemanticsImpl<'db> {
                             let text_range = tt.syntax().text_range();
                             filter_duplicates(tokens, text_range);
 
-                            process_expansion_for_token(&mut stack, file_id).or(file_id
-                                .eager_arg(self.db)
-                                .and_then(|arg| {
-                                    // also descend into eager expansions
-                                    process_expansion_for_token(&mut stack, arg)
-                                }))
+                            self.with_ctx(|ctx| {
+                                process_expansion_for_token(ctx, &mut stack, file_id).or(file_id
+                                    .eager_arg(db)
+                                    .and_then(|arg| {
+                                        // also descend into eager expansions
+                                        process_expansion_for_token(ctx, &mut stack, arg)
+                                    }))
+                            })
                         }
+                        Either::Right(_) if always_descend_into_derives => None,
                         // derive or derive helper
                         Either::Right(meta) => {
                             // attribute we failed expansion for earlier, this might be a derive invocation
@@ -1216,31 +1306,33 @@ impl<'db> SemanticsImpl<'db> {
                             let adt = match attr.syntax().parent().and_then(ast::Adt::cast) {
                                 Some(adt) => {
                                     // this might be a derive on an ADT
-                                    let derive_call = self.with_ctx(|ctx| {
+                                    let res = self.with_ctx(|ctx| {
                                         // so try downmapping the token into the pseudo derive expansion
                                         // see [hir_expand::builtin_attr_macro] for how the pseudo derive expansion works
-                                        ctx.attr_to_derive_macro_call(
-                                            InFile::new(expansion, &adt),
-                                            InFile::new(expansion, attr.clone()),
-                                        )
-                                        .map(|(_, call_id, _)| call_id)
+                                        let derive_call = ctx
+                                            .attr_to_derive_macro_call(
+                                                InFile::new(expansion, &adt),
+                                                InFile::new(expansion, attr.clone()),
+                                            )?
+                                            .1;
+
+                                        // resolved to a derive
+                                        let text_range = attr.syntax().text_range();
+                                        // remove any other token in this macro input, all their mappings are the
+                                        // same as this
+                                        tokens.retain(|(t, _)| {
+                                            !text_range.contains_range(t.text_range())
+                                        });
+                                        Some(process_expansion_for_token(
+                                            ctx,
+                                            &mut stack,
+                                            derive_call,
+                                        ))
                                     });
-
-                                    match derive_call {
-                                        Some(call_id) => {
-                                            // resolved to a derive
-                                            let text_range = attr.syntax().text_range();
-                                            // remove any other token in this macro input, all their mappings are the
-                                            // same as this
-                                            tokens.retain(|(t, _)| {
-                                                !text_range.contains_range(t.text_range())
-                                            });
-                                            return process_expansion_for_token(
-                                                &mut stack, call_id,
-                                            );
-                                        }
-                                        None => Some(adt),
+                                    if let Some(res) = res {
+                                        return res;
                                     }
+                                    Some(adt)
                                 }
                                 None => {
                                     // Otherwise this could be a derive helper on a variant or field
@@ -1254,12 +1346,9 @@ impl<'db> SemanticsImpl<'db> {
                                     )
                                 }
                             }?;
-                            if !self.with_ctx(|ctx| ctx.has_derives(InFile::new(expansion, &adt))) {
-                                return None;
-                            }
                             let attr_name =
                                 attr.path().and_then(|it| it.as_single_name_ref())?.as_name();
-                            // Not an attribute, nor a derive, so it's either an intert attribute or a derive helper
+                            // Not an attribute, nor a derive, so it's either an inert attribute or a derive helper
                             // Try to resolve to a derive helper and downmap
                             let resolver = &token
                                 .parent()
@@ -1267,7 +1356,7 @@ impl<'db> SemanticsImpl<'db> {
                                     self.analyze_impl(InFile::new(expansion, &parent), None, false)
                                 })?
                                 .resolver;
-                            let id = self.db.ast_id_map(expansion).ast_id(&adt);
+                            let id = db.ast_id_map(expansion).ast_id(&adt);
                             let helpers = resolver
                                 .def_map()
                                 .derive_helpers_in_scope(InFile::new(expansion, id))?;
@@ -1278,20 +1367,22 @@ impl<'db> SemanticsImpl<'db> {
                             }
 
                             let mut res = None;
-                            for (.., derive) in
-                                helpers.iter().filter(|(helper, ..)| *helper == attr_name)
-                            {
-                                // as there may be multiple derives registering the same helper
-                                // name, we gotta make sure to call this for all of them!
-                                // FIXME: We need to call `f` for all of them as well though!
-                                res = res.or(process_expansion_for_token(&mut stack, *derive));
-                            }
-                            res
+                            self.with_ctx(|ctx| {
+                                for (.., derive) in
+                                    helpers.iter().filter(|(helper, ..)| *helper == attr_name)
+                                {
+                                    // as there may be multiple derives registering the same helper
+                                    // name, we gotta make sure to call this for all of them!
+                                    // FIXME: We need to call `f` for all of them as well though!
+                                    res = res
+                                        .or(process_expansion_for_token(ctx, &mut stack, *derive));
+                                }
+                                res
+                            })
                         }
                     }
                 })()
                 .is_none();
-
                 if was_not_remapped {
                     if let ControlFlow::Break(b) = f(InFile::new(expansion, token), ctx) {
                         return Some(b);
@@ -1380,25 +1471,31 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     /// Iterates the ancestors of the given node, climbing up macro expansions while doing so.
+    // FIXME: Replace with `ancestors_with_macros_file` when all usages are updated.
     pub fn ancestors_with_macros(
         &self,
         node: SyntaxNode,
     ) -> impl Iterator<Item = SyntaxNode> + Clone + '_ {
         let node = self.find_file(&node);
-        iter::successors(Some(node.cloned()), move |&InFile { file_id, ref value }| {
-            match value.parent() {
-                Some(parent) => Some(InFile::new(file_id, parent)),
-                None => {
-                    let macro_file = file_id.macro_file()?;
-
-                    self.with_ctx(|ctx| {
-                        let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file);
-                        expansion_info.arg().map(|node| node?.parent()).transpose()
-                    })
-                }
+        self.ancestors_with_macros_file(node.cloned()).map(|it| it.value)
+    }
+
+    /// Iterates the ancestors of the given node, climbing up macro expansions while doing so.
+    pub fn ancestors_with_macros_file(
+        &self,
+        node: InFile<SyntaxNode>,
+    ) -> impl Iterator<Item = InFile<SyntaxNode>> + Clone + '_ {
+        iter::successors(Some(node), move |&InFile { file_id, ref value }| match value.parent() {
+            Some(parent) => Some(InFile::new(file_id, parent)),
+            None => {
+                let macro_file = file_id.macro_file()?;
+
+                self.with_ctx(|ctx| {
+                    let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file);
+                    expansion_info.arg().map(|node| node?.parent()).transpose()
+                })
             }
         })
-        .map(|it| it.value)
     }
 
     pub fn ancestors_at_offset_with_macros(
@@ -1851,18 +1948,12 @@ impl<'db> SemanticsImpl<'db> {
             ChildContainer::TraitId(it) => {
                 return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset));
             }
-            ChildContainer::TraitAliasId(it) => {
-                return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset));
-            }
             ChildContainer::ImplId(it) => {
                 return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset));
             }
             ChildContainer::EnumId(it) => {
                 return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset));
             }
-            ChildContainer::TypeAliasId(it) => {
-                return Some(SourceAnalyzer::new_generic_def(self.db, it.into(), node, offset));
-            }
             ChildContainer::GenericDefId(it) => {
                 return Some(SourceAnalyzer::new_generic_def(self.db, it, node, offset));
             }
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs
index 6accf9b2e9c..1a6d63c88c6 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs
@@ -17,6 +17,7 @@ use hir_def::{
         DynMap,
         keys::{self, Key},
     },
+    hir::generics::GenericParams,
     item_scope::ItemScope,
     item_tree::ItemTreeNode,
     nameres::DefMap,
@@ -49,6 +50,12 @@ impl ChildBySource for TraitId {
         data.items.iter().for_each(|&(_, item)| {
             add_assoc_item(db, res, file_id, item);
         });
+        let (_, source_map) = db.trait_signature_with_source_map(*self);
+        source_map.expansions().filter(|(ast, _)| ast.file_id == file_id).for_each(
+            |(ast, &exp_id)| {
+                res[keys::MACRO_CALL].insert(ast.value, exp_id);
+            },
+        );
     }
 }
 
@@ -68,6 +75,12 @@ impl ChildBySource for ImplId {
         data.items.iter().for_each(|&(_, item)| {
             add_assoc_item(db, res, file_id, item);
         });
+        let (_, source_map) = db.impl_signature_with_source_map(*self);
+        source_map.expansions().filter(|(ast, _)| ast.file_id == file_id).for_each(
+            |(ast, &exp_id)| {
+                res[keys::MACRO_CALL].insert(ast.value, exp_id);
+            },
+        );
     }
 }
 
@@ -178,6 +191,8 @@ impl ChildBySource for VariantId {
                 Either::Right(source) => res[keys::RECORD_FIELD].insert(AstPtr::new(&source), id),
             }
         }
+        let (_, sm) = db.variant_fields_with_source_map(*self);
+        sm.expansions().for_each(|(ast, &exp_id)| res[keys::MACRO_CALL].insert(ast.value, exp_id));
     }
 }
 
@@ -195,6 +210,11 @@ impl ChildBySource for EnumId {
             res[keys::ENUM_VARIANT]
                 .insert(ast_id_map.get(tree[variant.lookup(db).id.value].ast_id), variant);
         });
+        let (_, source_map) = db.enum_signature_with_source_map(*self);
+        source_map
+            .expansions()
+            .filter(|(ast, _)| ast.file_id == file_id)
+            .for_each(|(ast, &exp_id)| res[keys::MACRO_CALL].insert(ast.value, exp_id));
     }
 }
 
@@ -225,7 +245,8 @@ impl ChildBySource for GenericDefId {
             return;
         }
 
-        let generic_params = db.generic_params(*self);
+        let (generic_params, _, source_map) =
+            GenericParams::generic_params_and_store_and_source_map(db, *self);
         let mut toc_idx_iter = generic_params.iter_type_or_consts().map(|(idx, _)| idx);
         let lts_idx_iter = generic_params.iter_lt().map(|(idx, _)| idx);
 
@@ -253,6 +274,11 @@ impl ChildBySource for GenericDefId {
                 res[keys::LIFETIME_PARAM].insert(AstPtr::new(&ast_param), id);
             }
         }
+
+        source_map
+            .expansions()
+            .filter(|(ast, _)| ast.file_id == file_id)
+            .for_each(|(ast, &exp_id)| res[keys::MACRO_CALL].insert(ast.value, exp_id));
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
index 7f6c9af4740..71ee0f69389 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
@@ -108,7 +108,7 @@ use span::FileId;
 use stdx::impl_from;
 use syntax::{
     AstNode, AstPtr, SyntaxNode,
-    ast::{self, HasName},
+    ast::{self, HasAttrs, HasName},
 };
 use tt::TextRange;
 
@@ -411,10 +411,25 @@ impl SourceToDefCtx<'_, '_> {
             .map(|&(attr_id, call_id, ref ids)| (attr_id, call_id, &**ids))
     }
 
-    pub(super) fn has_derives(&mut self, adt: InFile<&ast::Adt>) -> bool {
+    // FIXME: Make this more fine grained! This should be a `adt_has_derives`!
+    pub(super) fn file_of_adt_has_derives(&mut self, adt: InFile<&ast::Adt>) -> bool {
         self.dyn_map(adt).as_ref().is_some_and(|map| !map[keys::DERIVE_MACRO_CALL].is_empty())
     }
 
+    pub(super) fn derive_macro_calls<'slf>(
+        &'slf mut self,
+        adt: InFile<&ast::Adt>,
+    ) -> Option<impl Iterator<Item = (AttrId, MacroCallId, &'slf [Option<MacroCallId>])> + use<'slf>>
+    {
+        self.dyn_map(adt).as_ref().map(|&map| {
+            let dyn_map = &map[keys::DERIVE_MACRO_CALL];
+            adt.value
+                .attrs()
+                .filter_map(move |attr| dyn_map.get(&AstPtr::new(&attr)))
+                .map(|&(attr_id, call_id, ref ids)| (attr_id, call_id, &**ids))
+        })
+    }
+
     fn to_def<Ast: AstNode + 'static, ID: Copy + 'static>(
         &mut self,
         src: InFile<&Ast>,
@@ -616,14 +631,14 @@ impl SourceToDefCtx<'_, '_> {
             match &item {
                 ast::Item::Module(it) => self.module_to_def(container.with_value(it))?.into(),
                 ast::Item::Trait(it) => self.trait_to_def(container.with_value(it))?.into(),
-                ast::Item::TraitAlias(it) => {
-                    self.trait_alias_to_def(container.with_value(it))?.into()
-                }
                 ast::Item::Impl(it) => self.impl_to_def(container.with_value(it))?.into(),
                 ast::Item::Enum(it) => self.enum_to_def(container.with_value(it))?.into(),
-                ast::Item::TypeAlias(it) => {
-                    self.type_alias_to_def(container.with_value(it))?.into()
-                }
+                ast::Item::TypeAlias(it) => ChildContainer::GenericDefId(
+                    self.type_alias_to_def(container.with_value(it))?.into(),
+                ),
+                ast::Item::TraitAlias(it) => ChildContainer::GenericDefId(
+                    self.trait_alias_to_def(container.with_value(it))?.into(),
+                ),
                 ast::Item::Struct(it) => {
                     let def = self.struct_to_def(container.with_value(it))?;
                     let is_in_body = it.field_list().is_some_and(|it| {
@@ -723,11 +738,9 @@ pub(crate) enum ChildContainer {
     DefWithBodyId(DefWithBodyId),
     ModuleId(ModuleId),
     TraitId(TraitId),
-    TraitAliasId(TraitAliasId),
     ImplId(ImplId),
     EnumId(EnumId),
     VariantId(VariantId),
-    TypeAliasId(TypeAliasId),
     /// XXX: this might be the same def as, for example an `EnumId`. However,
     /// here the children are generic parameters, and not, eg enum variants.
     GenericDefId(GenericDefId),
@@ -736,11 +749,9 @@ impl_from! {
     DefWithBodyId,
     ModuleId,
     TraitId,
-    TraitAliasId,
     ImplId,
     EnumId,
     VariantId,
-    TypeAliasId,
     GenericDefId
     for ChildContainer
 }
@@ -752,11 +763,9 @@ impl ChildContainer {
             ChildContainer::DefWithBodyId(it) => it.child_by_source(db, file_id),
             ChildContainer::ModuleId(it) => it.child_by_source(db, file_id),
             ChildContainer::TraitId(it) => it.child_by_source(db, file_id),
-            ChildContainer::TraitAliasId(_) => DynMap::default(),
             ChildContainer::ImplId(it) => it.child_by_source(db, file_id),
             ChildContainer::EnumId(it) => it.child_by_source(db, file_id),
             ChildContainer::VariantId(it) => it.child_by_source(db, file_id),
-            ChildContainer::TypeAliasId(_) => DynMap::default(),
             ChildContainer::GenericDefId(it) => it.child_by_source(db, file_id),
         }
     }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
index 5d75e445861..32c4ae2e869 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
@@ -56,14 +56,22 @@ pub(crate) fn convert_named_struct_to_tuple_struct(
     // XXX: We don't currently provide this assist for struct definitions inside macros, but if we
     // are to lift this limitation, don't forget to make `edit_struct_def()` consider macro files
     // too.
-    let name = ctx.find_node_at_offset::<ast::Name>()?;
-    let strukt = name.syntax().parent().and_then(<Either<ast::Struct, ast::Variant>>::cast)?;
-    let field_list = strukt.as_ref().either(|s| s.field_list(), |v| v.field_list())?;
+    let strukt_or_variant = ctx
+        .find_node_at_offset::<ast::Struct>()
+        .map(Either::Left)
+        .or_else(|| ctx.find_node_at_offset::<ast::Variant>().map(Either::Right))?;
+    let field_list = strukt_or_variant.as_ref().either(|s| s.field_list(), |v| v.field_list())?;
+
+    if ctx.offset() > field_list.syntax().text_range().start() {
+        // Assist could be distracting after the braces
+        return None;
+    }
+
     let record_fields = match field_list {
         ast::FieldList::RecordFieldList(it) => it,
         ast::FieldList::TupleFieldList(_) => return None,
     };
-    let strukt_def = match &strukt {
+    let strukt_def = match &strukt_or_variant {
         Either::Left(s) => Either::Left(ctx.sema.to_def(s)?),
         Either::Right(v) => Either::Right(ctx.sema.to_def(v)?),
     };
@@ -71,11 +79,11 @@ pub(crate) fn convert_named_struct_to_tuple_struct(
     acc.add(
         AssistId::refactor_rewrite("convert_named_struct_to_tuple_struct"),
         "Convert to tuple struct",
-        strukt.syntax().text_range(),
+        strukt_or_variant.syntax().text_range(),
         |edit| {
             edit_field_references(ctx, edit, record_fields.fields());
             edit_struct_references(ctx, edit, strukt_def);
-            edit_struct_def(ctx, edit, &strukt, record_fields);
+            edit_struct_def(ctx, edit, &strukt_or_variant, record_fields);
         },
     )
 }
@@ -294,6 +302,88 @@ impl A {
     }
 
     #[test]
+    fn convert_simple_struct_cursor_on_struct_keyword() {
+        check_assist(
+            convert_named_struct_to_tuple_struct,
+            r#"
+struct Inner;
+struct$0 A { inner: Inner }
+
+impl A {
+    fn new(inner: Inner) -> A {
+        A { inner }
+    }
+
+    fn new_with_default() -> A {
+        A::new(Inner)
+    }
+
+    fn into_inner(self) -> Inner {
+        self.inner
+    }
+}"#,
+            r#"
+struct Inner;
+struct A(Inner);
+
+impl A {
+    fn new(inner: Inner) -> A {
+        A(inner)
+    }
+
+    fn new_with_default() -> A {
+        A::new(Inner)
+    }
+
+    fn into_inner(self) -> Inner {
+        self.0
+    }
+}"#,
+        );
+    }
+
+    #[test]
+    fn convert_simple_struct_cursor_on_visibility_keyword() {
+        check_assist(
+            convert_named_struct_to_tuple_struct,
+            r#"
+struct Inner;
+pub$0 struct A { inner: Inner }
+
+impl A {
+    fn new(inner: Inner) -> A {
+        A { inner }
+    }
+
+    fn new_with_default() -> A {
+        A::new(Inner)
+    }
+
+    fn into_inner(self) -> Inner {
+        self.inner
+    }
+}"#,
+            r#"
+struct Inner;
+pub struct A(Inner);
+
+impl A {
+    fn new(inner: Inner) -> A {
+        A(inner)
+    }
+
+    fn new_with_default() -> A {
+        A::new(Inner)
+    }
+
+    fn into_inner(self) -> Inner {
+        self.0
+    }
+}"#,
+        );
+    }
+
+    #[test]
     fn convert_struct_referenced_via_self_kw() {
         check_assist(
             convert_named_struct_to_tuple_struct,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
index 0c0b93bcfbc..80756197fb7 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
@@ -51,18 +51,26 @@ pub(crate) fn convert_tuple_struct_to_named_struct(
     acc: &mut Assists,
     ctx: &AssistContext<'_>,
 ) -> Option<()> {
-    let name = ctx.find_node_at_offset::<ast::Name>()?;
-    let strukt = name.syntax().parent().and_then(<Either<ast::Struct, ast::Variant>>::cast)?;
-    let field_list = strukt.as_ref().either(|s| s.field_list(), |v| v.field_list())?;
+    let strukt_or_variant = ctx
+        .find_node_at_offset::<ast::Struct>()
+        .map(Either::Left)
+        .or_else(|| ctx.find_node_at_offset::<ast::Variant>().map(Either::Right))?;
+    let field_list = strukt_or_variant.as_ref().either(|s| s.field_list(), |v| v.field_list())?;
+
+    if ctx.offset() > field_list.syntax().text_range().start() {
+        // Assist could be distracting after the braces
+        return None;
+    }
+
     let tuple_fields = match field_list {
         ast::FieldList::TupleFieldList(it) => it,
         ast::FieldList::RecordFieldList(_) => return None,
     };
-    let strukt_def = match &strukt {
+    let strukt_def = match &strukt_or_variant {
         Either::Left(s) => Either::Left(ctx.sema.to_def(s)?),
         Either::Right(v) => Either::Right(ctx.sema.to_def(v)?),
     };
-    let target = strukt.as_ref().either(|s| s.syntax(), |v| v.syntax()).text_range();
+    let target = strukt_or_variant.as_ref().either(|s| s.syntax(), |v| v.syntax()).text_range();
 
     acc.add(
         AssistId::refactor_rewrite("convert_tuple_struct_to_named_struct"),
@@ -72,7 +80,7 @@ pub(crate) fn convert_tuple_struct_to_named_struct(
             let names = generate_names(tuple_fields.fields());
             edit_field_references(ctx, edit, tuple_fields.fields(), &names);
             edit_struct_references(ctx, edit, strukt_def, &names);
-            edit_struct_def(ctx, edit, &strukt, tuple_fields, names);
+            edit_struct_def(ctx, edit, &strukt_or_variant, tuple_fields, names);
         },
     )
 }
@@ -317,6 +325,88 @@ impl A {
     }
 
     #[test]
+    fn convert_simple_struct_cursor_on_struct_keyword() {
+        check_assist(
+            convert_tuple_struct_to_named_struct,
+            r#"
+struct Inner;
+struct$0 A(Inner);
+
+impl A {
+    fn new(inner: Inner) -> A {
+        A(inner)
+    }
+
+    fn new_with_default() -> A {
+        A::new(Inner)
+    }
+
+    fn into_inner(self) -> Inner {
+        self.0
+    }
+}"#,
+            r#"
+struct Inner;
+struct A { field1: Inner }
+
+impl A {
+    fn new(inner: Inner) -> A {
+        A { field1: inner }
+    }
+
+    fn new_with_default() -> A {
+        A::new(Inner)
+    }
+
+    fn into_inner(self) -> Inner {
+        self.field1
+    }
+}"#,
+        );
+    }
+
+    #[test]
+    fn convert_simple_struct_cursor_on_visibility_keyword() {
+        check_assist(
+            convert_tuple_struct_to_named_struct,
+            r#"
+struct Inner;
+pub$0 struct A(Inner);
+
+impl A {
+    fn new(inner: Inner) -> A {
+        A(inner)
+    }
+
+    fn new_with_default() -> A {
+        A::new(Inner)
+    }
+
+    fn into_inner(self) -> Inner {
+        self.0
+    }
+}"#,
+            r#"
+struct Inner;
+pub struct A { field1: Inner }
+
+impl A {
+    fn new(inner: Inner) -> A {
+        A { field1: inner }
+    }
+
+    fn new_with_default() -> A {
+        A::new(Inner)
+    }
+
+    fn into_inner(self) -> Inner {
+        self.field1
+    }
+}"#,
+        );
+    }
+
+    #[test]
     fn convert_struct_referenced_via_self_kw() {
         check_assist(
             convert_tuple_struct_to_named_struct,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs
index 19e0a73f333..3badc17d01a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs
@@ -7,10 +7,10 @@ use syntax::{
 
 use crate::{AssistContext, AssistId, Assists};
 
-// FIXME: this really should be a fix for diagnostic, rather than an assist.
-
 // Assist: fix_visibility
 //
+// Note that there is some duplication between this and the no_such_field diagnostic.
+//
 // Makes inaccessible item public.
 //
 // ```
@@ -32,7 +32,6 @@ use crate::{AssistContext, AssistId, Assists};
 // ```
 pub(crate) fn fix_visibility(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     add_vis_to_referenced_module_def(acc, ctx)
-        .or_else(|| add_vis_to_referenced_record_field(acc, ctx))
 }
 
 fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
@@ -88,59 +87,6 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>)
     })
 }
 
-fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
-    let record_field: ast::RecordExprField = ctx.find_node_at_offset()?;
-    let (record_field_def, _, _) = ctx.sema.resolve_record_field(&record_field)?;
-
-    let current_module = ctx.sema.scope(record_field.syntax())?.module();
-    let current_edition = current_module.krate().edition(ctx.db());
-    let visibility = record_field_def.visibility(ctx.db());
-    if visibility.is_visible_from(ctx.db(), current_module.into()) {
-        return None;
-    }
-
-    let parent = record_field_def.parent_def(ctx.db());
-    let parent_name = parent.name(ctx.db());
-    let target_module = parent.module(ctx.db());
-
-    let in_file_source = record_field_def.source(ctx.db())?;
-    let (vis_owner, target) = match in_file_source.value {
-        hir::FieldSource::Named(it) => {
-            let range = it.syntax().text_range();
-            (ast::AnyHasVisibility::new(it), range)
-        }
-        hir::FieldSource::Pos(it) => {
-            let range = it.syntax().text_range();
-            (ast::AnyHasVisibility::new(it), range)
-        }
-    };
-
-    let missing_visibility = if current_module.krate() == target_module.krate() {
-        make::visibility_pub_crate()
-    } else {
-        make::visibility_pub()
-    };
-    let target_file = in_file_source.file_id.original_file(ctx.db());
-
-    let target_name = record_field_def.name(ctx.db());
-    let assist_label = format!(
-        "Change visibility of {}.{} to {missing_visibility}",
-        parent_name.display(ctx.db(), current_edition),
-        target_name.display(ctx.db(), current_edition)
-    );
-
-    acc.add(AssistId::quick_fix("fix_visibility"), assist_label, target, |edit| {
-        edit.edit_file(target_file.file_id(ctx.db()));
-
-        let vis_owner = edit.make_mut(vis_owner);
-        vis_owner.set_visibility(Some(missing_visibility.clone_for_update()));
-
-        if let Some((cap, vis)) = ctx.config.snippet_cap.zip(vis_owner.visibility()) {
-            edit.add_tabstop_before(cap, vis);
-        }
-    })
-}
-
 fn target_data_for_def(
     db: &dyn HirDatabase,
     def: hir::ModuleDef,
@@ -294,44 +240,6 @@ struct Foo;
     }
 
     #[test]
-    fn fix_visibility_of_struct_field() {
-        check_assist(
-            fix_visibility,
-            r"mod foo { pub struct Foo { bar: (), } }
-              fn main() { foo::Foo { $0bar: () }; } ",
-            r"mod foo { pub struct Foo { $0pub(crate) bar: (), } }
-              fn main() { foo::Foo { bar: () }; } ",
-        );
-        check_assist(
-            fix_visibility,
-            r"
-//- /lib.rs
-mod foo;
-fn main() { foo::Foo { $0bar: () }; }
-//- /foo.rs
-pub struct Foo { bar: () }
-",
-            r"pub struct Foo { $0pub(crate) bar: () }
-",
-        );
-        check_assist_not_applicable(
-            fix_visibility,
-            r"mod foo { pub struct Foo { pub bar: (), } }
-              fn main() { foo::Foo { $0bar: () }; } ",
-        );
-        check_assist_not_applicable(
-            fix_visibility,
-            r"
-//- /lib.rs
-mod foo;
-fn main() { foo::Foo { $0bar: () }; }
-//- /foo.rs
-pub struct Foo { pub bar: () }
-",
-        );
-    }
-
-    #[test]
     fn fix_visibility_of_enum_variant_field() {
         // Enum variants, as well as their fields, always get the enum's visibility. In fact, rustc
         // rejects any visibility specifiers on them, so this assist should never fire on them.
@@ -368,44 +276,6 @@ pub struct Foo { pub bar: () }
     }
 
     #[test]
-    fn fix_visibility_of_union_field() {
-        check_assist(
-            fix_visibility,
-            r"mod foo { pub union Foo { bar: (), } }
-              fn main() { foo::Foo { $0bar: () }; } ",
-            r"mod foo { pub union Foo { $0pub(crate) bar: (), } }
-              fn main() { foo::Foo { bar: () }; } ",
-        );
-        check_assist(
-            fix_visibility,
-            r"
-//- /lib.rs
-mod foo;
-fn main() { foo::Foo { $0bar: () }; }
-//- /foo.rs
-pub union Foo { bar: () }
-",
-            r"pub union Foo { $0pub(crate) bar: () }
-",
-        );
-        check_assist_not_applicable(
-            fix_visibility,
-            r"mod foo { pub union Foo { pub bar: (), } }
-              fn main() { foo::Foo { $0bar: () }; } ",
-        );
-        check_assist_not_applicable(
-            fix_visibility,
-            r"
-//- /lib.rs
-mod foo;
-fn main() { foo::Foo { $0bar: () }; }
-//- /foo.rs
-pub union Foo { pub bar: () }
-",
-        );
-    }
-
-    #[test]
     fn fix_visibility_of_const() {
         check_assist(
             fix_visibility,
@@ -572,19 +442,6 @@ pub(crate) struct Bar;
             r"$0pub struct Bar;
 ",
         );
-        check_assist(
-            fix_visibility,
-            r"
-//- /main.rs crate:a deps:foo
-fn main() {
-    foo::Foo { $0bar: () };
-}
-//- /lib.rs crate:foo
-pub struct Foo { pub(crate) bar: () }
-",
-            r"pub struct Foo { $0pub bar: () }
-",
-        );
     }
 
     #[test]
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_underscore.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_underscore.rs
index 912e1936b59..a8e27416d5c 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_underscore.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_underscore.rs
@@ -1,6 +1,7 @@
 use ide_db::{
     assists::AssistId,
     defs::{Definition, NameClass, NameRefClass},
+    rename::RenameDefinition,
 };
 use syntax::{AstNode, ast};
 
@@ -61,7 +62,7 @@ pub(crate) fn remove_underscore(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
         "Remove underscore from a used variable",
         text_range,
         |builder| {
-            let changes = def.rename(&ctx.sema, new_name).unwrap();
+            let changes = def.rename(&ctx.sema, new_name, RenameDefinition::Yes).unwrap();
             builder.source_change = changes;
         },
     )
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs
index 3c195f80fea..705402c785a 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute.rs
@@ -25,6 +25,7 @@ use crate::{
 
 mod cfg;
 mod derive;
+mod diagnostic;
 mod lint;
 mod macro_use;
 mod repr;
@@ -40,23 +41,22 @@ pub(crate) fn complete_known_attribute_input(
     extern_crate: Option<&ast::ExternCrate>,
 ) -> Option<()> {
     let attribute = fake_attribute_under_caret;
-    let name_ref = match attribute.path() {
-        Some(p) => Some(p.as_single_name_ref()?),
-        None => None,
-    };
-    let (path, tt) = name_ref.zip(attribute.token_tree())?;
-    tt.l_paren_token()?;
+    let path = attribute.path()?;
+    let segments = path.segments().map(|s| s.name_ref()).collect::<Option<Vec<_>>>()?;
+    let segments = segments.iter().map(|n| n.text()).collect::<Vec<_>>();
+    let segments = segments.iter().map(|t| t.as_str()).collect::<Vec<_>>();
+    let tt = attribute.token_tree()?;
 
-    match path.text().as_str() {
-        "repr" => repr::complete_repr(acc, ctx, tt),
-        "feature" => lint::complete_lint(
+    match segments.as_slice() {
+        ["repr"] => repr::complete_repr(acc, ctx, tt),
+        ["feature"] => lint::complete_lint(
             acc,
             ctx,
             colon_prefix,
             &parse_tt_as_comma_sep_paths(tt, ctx.edition)?,
             FEATURES,
         ),
-        "allow" | "expect" | "deny" | "forbid" | "warn" => {
+        ["allow"] | ["expect"] | ["deny"] | ["forbid"] | ["warn"] => {
             let existing_lints = parse_tt_as_comma_sep_paths(tt, ctx.edition)?;
 
             let lints: Vec<Lint> = CLIPPY_LINT_GROUPS
@@ -70,13 +70,14 @@ pub(crate) fn complete_known_attribute_input(
 
             lint::complete_lint(acc, ctx, colon_prefix, &existing_lints, &lints);
         }
-        "cfg" => cfg::complete_cfg(acc, ctx),
-        "macro_use" => macro_use::complete_macro_use(
+        ["cfg"] => cfg::complete_cfg(acc, ctx),
+        ["macro_use"] => macro_use::complete_macro_use(
             acc,
             ctx,
             extern_crate,
             &parse_tt_as_comma_sep_paths(tt, ctx.edition)?,
         ),
+        ["diagnostic", "on_unimplemented"] => diagnostic::complete_on_unimplemented(acc, ctx, tt),
         _ => (),
     }
     Some(())
@@ -139,6 +140,8 @@ pub(crate) fn complete_attribute_path(
         }
         Qualified::TypeAnchor { .. } | Qualified::With { .. } => {}
     }
+    let qualifier_path =
+        if let Qualified::With { path, .. } = qualified { Some(path) } else { None };
 
     let attributes = annotated_item_kind.and_then(|kind| {
         if ast::Expr::can_cast(kind) {
@@ -149,18 +152,33 @@ pub(crate) fn complete_attribute_path(
     });
 
     let add_completion = |attr_completion: &AttrCompletion| {
-        let mut item = CompletionItem::new(
-            SymbolKind::Attribute,
-            ctx.source_range(),
-            attr_completion.label,
-            ctx.edition,
-        );
+        // if we don't already have the qualifiers of the completion, then
+        // add the missing parts to the label and snippet
+        let mut label = attr_completion.label.to_owned();
+        let mut snippet = attr_completion.snippet.map(|s| s.to_owned());
+        let segments = qualifier_path.iter().flat_map(|q| q.segments()).collect::<Vec<_>>();
+        let qualifiers = attr_completion.qualifiers;
+        let matching_qualifiers = segments
+            .iter()
+            .zip(qualifiers)
+            .take_while(|(s, q)| s.name_ref().is_some_and(|t| t.text() == **q))
+            .count();
+        if matching_qualifiers != qualifiers.len() {
+            let prefix = qualifiers[matching_qualifiers..].join("::");
+            label = format!("{prefix}::{label}");
+            if let Some(s) = snippet.as_mut() {
+                *s = format!("{prefix}::{s}");
+            }
+        }
+
+        let mut item =
+            CompletionItem::new(SymbolKind::Attribute, ctx.source_range(), label, ctx.edition);
 
         if let Some(lookup) = attr_completion.lookup {
             item.lookup_by(lookup);
         }
 
-        if let Some((snippet, cap)) = attr_completion.snippet.zip(ctx.config.snippet_cap) {
+        if let Some((snippet, cap)) = snippet.zip(ctx.config.snippet_cap) {
             item.insert_snippet(cap, snippet);
         }
 
@@ -184,6 +202,7 @@ struct AttrCompletion {
     label: &'static str,
     lookup: Option<&'static str>,
     snippet: Option<&'static str>,
+    qualifiers: &'static [&'static str],
     prefer_inner: bool,
 }
 
@@ -192,6 +211,10 @@ impl AttrCompletion {
         self.lookup.unwrap_or(self.label)
     }
 
+    const fn qualifiers(self, qualifiers: &'static [&'static str]) -> AttrCompletion {
+        AttrCompletion { qualifiers, ..self }
+    }
+
     const fn prefer_inner(self) -> AttrCompletion {
         AttrCompletion { prefer_inner: true, ..self }
     }
@@ -202,7 +225,7 @@ const fn attr(
     lookup: Option<&'static str>,
     snippet: Option<&'static str>,
 ) -> AttrCompletion {
-    AttrCompletion { label, lookup, snippet, prefer_inner: false }
+    AttrCompletion { label, lookup, snippet, qualifiers: &[], prefer_inner: false }
 }
 
 macro_rules! attrs {
@@ -264,14 +287,14 @@ static KIND_TO_ATTRIBUTES: LazyLock<FxHashMap<SyntaxKind, &[&str]>> = LazyLock::
             FN,
             attrs!(
                 item, linkable,
-                "cold", "ignore", "inline", "must_use", "panic_handler", "proc_macro",
+                "cold", "ignore", "inline", "panic_handler", "proc_macro",
                 "proc_macro_derive", "proc_macro_attribute", "should_panic", "target_feature",
                 "test", "track_caller"
             ),
         ),
         (STATIC, attrs!(item, linkable, "global_allocator", "used")),
-        (TRAIT, attrs!(item, "must_use")),
-        (IMPL, attrs!(item, "automatically_derived")),
+        (TRAIT, attrs!(item, "diagnostic::on_unimplemented")),
+        (IMPL, attrs!(item, "automatically_derived", "diagnostic::do_not_recommend")),
         (ASSOC_ITEM_LIST, attrs!(item)),
         (EXTERN_BLOCK, attrs!(item, "link")),
         (EXTERN_ITEM_LIST, attrs!(item, "link")),
@@ -311,6 +334,14 @@ const ATTRIBUTES: &[AttrCompletion] = &[
     attr("deny(…)", Some("deny"), Some("deny(${0:lint})")),
     attr(r#"deprecated"#, Some("deprecated"), Some(r#"deprecated"#)),
     attr("derive(…)", Some("derive"), Some(r#"derive(${0:Debug})"#)),
+    attr("do_not_recommend", Some("diagnostic::do_not_recommend"), None)
+        .qualifiers(&["diagnostic"]),
+    attr(
+        "on_unimplemented",
+        Some("diagnostic::on_unimplemented"),
+        Some(r#"on_unimplemented(${0:keys})"#),
+    )
+    .qualifiers(&["diagnostic"]),
     attr(r#"doc = "…""#, Some("doc"), Some(r#"doc = "${0:docs}""#)),
     attr(r#"doc(alias = "…")"#, Some("docalias"), Some(r#"doc(alias = "${0:docs}")"#)),
     attr(r#"doc(hidden)"#, Some("dochidden"), Some(r#"doc(hidden)"#)),
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/diagnostic.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/diagnostic.rs
new file mode 100644
index 00000000000..8adc9742390
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/diagnostic.rs
@@ -0,0 +1,60 @@
+//! Completion for diagnostic attributes.
+
+use ide_db::SymbolKind;
+use syntax::ast;
+
+use crate::{CompletionItem, Completions, context::CompletionContext};
+
+use super::AttrCompletion;
+
+pub(super) fn complete_on_unimplemented(
+    acc: &mut Completions,
+    ctx: &CompletionContext<'_>,
+    input: ast::TokenTree,
+) {
+    if let Some(existing_keys) = super::parse_comma_sep_expr(input) {
+        for attr in ATTRIBUTE_ARGS {
+            let already_annotated = existing_keys
+                .iter()
+                .filter_map(|expr| match expr {
+                    ast::Expr::PathExpr(path) => path.path()?.as_single_name_ref(),
+                    ast::Expr::BinExpr(bin)
+                        if bin.op_kind() == Some(ast::BinaryOp::Assignment { op: None }) =>
+                    {
+                        match bin.lhs()? {
+                            ast::Expr::PathExpr(path) => path.path()?.as_single_name_ref(),
+                            _ => None,
+                        }
+                    }
+                    _ => None,
+                })
+                .any(|it| {
+                    let text = it.text();
+                    attr.key() == text && text != "note"
+                });
+            if already_annotated {
+                continue;
+            }
+
+            let mut item = CompletionItem::new(
+                SymbolKind::BuiltinAttr,
+                ctx.source_range(),
+                attr.label,
+                ctx.edition,
+            );
+            if let Some(lookup) = attr.lookup {
+                item.lookup_by(lookup);
+            }
+            if let Some((snippet, cap)) = attr.snippet.zip(ctx.config.snippet_cap) {
+                item.insert_snippet(cap, snippet);
+            }
+            item.add_to(acc, ctx.db);
+        }
+    }
+}
+
+const ATTRIBUTE_ARGS: &[AttrCompletion] = &[
+    super::attr(r#"label = "…""#, Some("label"), Some(r#"label = "${0:label}""#)),
+    super::attr(r#"message = "…""#, Some("message"), Some(r#"message = "${0:message}""#)),
+    super::attr(r#"note = "…""#, Some("note"), Some(r#"note = "${0:note}""#)),
+];
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs
index 32d3b50f237..411902f1117 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs
@@ -30,6 +30,8 @@ pub struct Foo(#[m$0] i32);
             at deprecated
             at derive                                  macro derive
             at derive(…)
+            at diagnostic::do_not_recommend
+            at diagnostic::on_unimplemented
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
@@ -472,13 +474,13 @@ fn attr_on_trait() {
             at cfg_attr(…)
             at deny(…)
             at deprecated
+            at diagnostic::on_unimplemented
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
             at expect(…)
             at forbid(…)
             at must_use
-            at must_use
             at no_mangle
             at warn(…)
             kw crate::
@@ -498,6 +500,7 @@ fn attr_on_impl() {
             at cfg_attr(…)
             at deny(…)
             at deprecated
+            at diagnostic::do_not_recommend
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
@@ -533,6 +536,76 @@ fn attr_on_impl() {
 }
 
 #[test]
+fn attr_with_qualifier() {
+    check(
+        r#"#[diagnostic::$0] impl () {}"#,
+        expect![[r#"
+            at allow(…)
+            at automatically_derived
+            at cfg(…)
+            at cfg_attr(…)
+            at deny(…)
+            at deprecated
+            at do_not_recommend
+            at doc = "…"
+            at doc(alias = "…")
+            at doc(hidden)
+            at expect(…)
+            at forbid(…)
+            at must_use
+            at no_mangle
+            at warn(…)
+        "#]],
+    );
+    check(
+        r#"#[diagnostic::$0] trait Foo {}"#,
+        expect![[r#"
+            at allow(…)
+            at cfg(…)
+            at cfg_attr(…)
+            at deny(…)
+            at deprecated
+            at doc = "…"
+            at doc(alias = "…")
+            at doc(hidden)
+            at expect(…)
+            at forbid(…)
+            at must_use
+            at no_mangle
+            at on_unimplemented
+            at warn(…)
+        "#]],
+    );
+}
+
+#[test]
+fn attr_diagnostic_on_unimplemented() {
+    check(
+        r#"#[diagnostic::on_unimplemented($0)] trait Foo {}"#,
+        expect![[r#"
+            ba label = "…"
+            ba message = "…"
+            ba note = "…"
+        "#]],
+    );
+    check(
+        r#"#[diagnostic::on_unimplemented(message = "foo", $0)] trait Foo {}"#,
+        expect![[r#"
+            ba label = "…"
+            ba note = "…"
+        "#]],
+    );
+    check(
+        r#"#[diagnostic::on_unimplemented(note = "foo", $0)] trait Foo {}"#,
+        expect![[r#"
+            ba label = "…"
+            ba message = "…"
+            ba note = "…"
+        "#]],
+    );
+}
+
+#[test]
 fn attr_on_extern_block() {
     check(
         r#"#[$0] extern {}"#,
@@ -619,7 +692,6 @@ fn attr_on_fn() {
             at link_name = "…"
             at link_section = "…"
             at must_use
-            at must_use
             at no_mangle
             at panic_handler
             at proc_macro
@@ -649,6 +721,8 @@ fn attr_in_source_file_end() {
             at deny(…)
             at deprecated
             at derive(…)
+            at diagnostic::do_not_recommend
+            at diagnostic::on_unimplemented
             at doc = "…"
             at doc(alias = "…")
             at doc(hidden)
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
index fa2a46a0f7c..4e737e27f05 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
@@ -20,7 +20,7 @@
 //!
 //! The correct behavior in such cases is probably to show a dialog to the user.
 //! Our current behavior is ¯\_(ツ)_/¯.
-use std::fmt;
+use std::fmt::{self, Display};
 
 use crate::{
     source_change::ChangeAnnotation,
@@ -28,13 +28,12 @@ use crate::{
 };
 use base_db::AnchoredPathBuf;
 use either::Either;
-use hir::{EditionedFileId, FieldSource, FileRange, InFile, ModuleSource, Semantics};
+use hir::{FieldSource, FileRange, InFile, ModuleSource, Name, Semantics, sym};
 use span::{Edition, FileId, SyntaxContext};
 use stdx::{TupleExt, never};
 use syntax::{
     AstNode, SyntaxKind, T, TextRange,
     ast::{self, HasName},
-    utils::is_raw_identifier,
 };
 
 use crate::{
@@ -70,26 +69,33 @@ macro_rules! _bail {
 }
 pub use _bail as bail;
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum RenameDefinition {
+    Yes,
+    No,
+}
+
 impl Definition {
     pub fn rename(
         &self,
         sema: &Semantics<'_, RootDatabase>,
         new_name: &str,
+        rename_definition: RenameDefinition,
     ) -> Result<SourceChange> {
-        // We append `r#` if needed.
-        let new_name = new_name.trim_start_matches("r#");
-
         // self.krate() returns None if
         // self is a built-in attr, built-in type or tool module.
         // it is not allowed for these defs to be renamed.
         // cases where self.krate() is None is handled below.
-        if let Some(krate) = self.krate(sema.db) {
+        let edition = if let Some(krate) = self.krate(sema.db) {
             // Can we not rename non-local items?
             // Then bail if non-local
             if !krate.origin(sema.db).is_local() {
                 bail!("Cannot rename a non-local definition")
             }
-        }
+            krate.edition(sema.db)
+        } else {
+            Edition::LATEST
+        };
 
         match *self {
             Definition::Module(module) => rename_mod(sema, module, new_name),
@@ -103,8 +109,10 @@ impl Definition {
                 bail!("Cannot rename a builtin attr.")
             }
             Definition::SelfType(_) => bail!("Cannot rename `Self`"),
-            Definition::Macro(mac) => rename_reference(sema, Definition::Macro(mac), new_name),
-            def => rename_reference(sema, def, new_name),
+            Definition::Macro(mac) => {
+                rename_reference(sema, Definition::Macro(mac), new_name, rename_definition, edition)
+            }
+            def => rename_reference(sema, def, new_name, rename_definition, edition),
         }
     }
 
@@ -237,10 +245,6 @@ fn rename_mod(
     module: hir::Module,
     new_name: &str,
 ) -> Result<SourceChange> {
-    if IdentifierKind::classify(new_name)? != IdentifierKind::Ident {
-        bail!("Invalid name `{0}`: cannot rename module to {0}", new_name);
-    }
-
     let mut source_change = SourceChange::default();
 
     if module.is_crate_root() {
@@ -248,6 +252,14 @@ fn rename_mod(
     }
 
     let InFile { file_id, value: def_source } = module.definition_source(sema.db);
+    let edition = file_id.edition(sema.db);
+    let (new_name, kind) = IdentifierKind::classify(edition, new_name)?;
+    if kind != IdentifierKind::Ident {
+        bail!(
+            "Invalid name `{0}`: cannot rename module to {0}",
+            new_name.display(sema.db, edition)
+        );
+    }
     if let ModuleSource::SourceFile(..) = def_source {
         let anchor = file_id.original_file(sema.db).file_id(sema.db);
 
@@ -256,7 +268,7 @@ fn rename_mod(
 
         // Module exists in a named file
         if !is_mod_rs {
-            let path = format!("{new_name}.rs");
+            let path = format!("{}.rs", new_name.as_str());
             let dst = AnchoredPathBuf { anchor, path };
             source_change.push_file_system_edit(FileSystemEdit::MoveFile { src: anchor, dst })
         }
@@ -267,11 +279,11 @@ fn rename_mod(
         let dir_paths = match (is_mod_rs, has_detached_child, module.name(sema.db)) {
             // Go up one level since the anchor is inside the dir we're trying to rename
             (true, _, Some(mod_name)) => {
-                Some((format!("../{}", mod_name.as_str()), format!("../{new_name}")))
+                Some((format!("../{}", mod_name.as_str()), format!("../{}", new_name.as_str())))
             }
             // The anchor is on the same level as target dir
             (false, true, Some(mod_name)) => {
-                Some((mod_name.as_str().to_owned(), new_name.to_owned()))
+                Some((mod_name.as_str().to_owned(), new_name.as_str().to_owned()))
             }
             _ => None,
         };
@@ -296,11 +308,7 @@ fn rename_mod(
                     .original_file_range_opt(sema.db)
                     .map(TupleExt::head)
                 {
-                    let new_name = if is_raw_identifier(new_name, file_id.edition(sema.db)) {
-                        format!("r#{new_name}")
-                    } else {
-                        new_name.to_owned()
-                    };
+                    let new_name = new_name.display(sema.db, edition).to_string();
                     source_change.insert_source_edit(
                         file_id.file_id(sema.db),
                         TextEdit::replace(file_range.range, new_name),
@@ -314,9 +322,10 @@ fn rename_mod(
     let def = Definition::Module(module);
     let usages = def.usages(sema).all();
     let ref_edits = usages.iter().map(|(file_id, references)| {
+        let edition = file_id.edition(sema.db);
         (
             file_id.file_id(sema.db),
-            source_edit_from_references(references, def, new_name, file_id.edition(sema.db)),
+            source_edit_from_references(sema.db, references, def, &new_name, edition),
         )
     });
     source_change.extend(ref_edits);
@@ -328,8 +337,10 @@ fn rename_reference(
     sema: &Semantics<'_, RootDatabase>,
     def: Definition,
     new_name: &str,
+    rename_definition: RenameDefinition,
+    edition: Edition,
 ) -> Result<SourceChange> {
-    let ident_kind = IdentifierKind::classify(new_name)?;
+    let (mut new_name, ident_kind) = IdentifierKind::classify(edition, new_name)?;
 
     if matches!(
         def,
@@ -337,18 +348,34 @@ fn rename_reference(
     ) {
         match ident_kind {
             IdentifierKind::Underscore => {
-                bail!("Invalid name `{}`: not a lifetime identifier", new_name);
+                bail!(
+                    "Invalid name `{}`: not a lifetime identifier",
+                    new_name.display(sema.db, edition)
+                );
+            }
+            IdentifierKind::Ident => {
+                new_name = Name::new_lifetime(&format!("'{}", new_name.as_str()))
             }
-            _ => cov_mark::hit!(rename_lifetime),
+            IdentifierKind::Lifetime => (),
+            IdentifierKind::LowercaseSelf => bail!(
+                "Invalid name `{}`: not a lifetime identifier",
+                new_name.display(sema.db, edition)
+            ),
         }
     } else {
         match ident_kind {
             IdentifierKind::Lifetime => {
                 cov_mark::hit!(rename_not_an_ident_ref);
-                bail!("Invalid name `{}`: not an identifier", new_name);
+                bail!("Invalid name `{}`: not an identifier", new_name.display(sema.db, edition));
             }
             IdentifierKind::Ident => cov_mark::hit!(rename_non_local),
             IdentifierKind::Underscore => (),
+            IdentifierKind::LowercaseSelf => {
+                bail!(
+                    "Invalid name `{}`: cannot rename to `self`",
+                    new_name.display(sema.db, edition)
+                );
+            }
         }
     }
 
@@ -361,30 +388,29 @@ fn rename_reference(
     }
     let mut source_change = SourceChange::default();
     source_change.extend(usages.iter().map(|(file_id, references)| {
+        let edition = file_id.edition(sema.db);
         (
             file_id.file_id(sema.db),
-            source_edit_from_references(references, def, new_name, file_id.edition(sema.db)),
+            source_edit_from_references(sema.db, references, def, &new_name, edition),
         )
     }));
-
-    // This needs to come after the references edits, because we change the annotation of existing edits
-    // if a conflict is detected.
-    let (file_id, edit) = source_edit_from_def(sema, def, new_name, &mut source_change)?;
-    source_change.insert_source_edit(file_id, edit);
+    if rename_definition == RenameDefinition::Yes {
+        // This needs to come after the references edits, because we change the annotation of existing edits
+        // if a conflict is detected.
+        let (file_id, edit) = source_edit_from_def(sema, def, &new_name, &mut source_change)?;
+        source_change.insert_source_edit(file_id, edit);
+    }
     Ok(source_change)
 }
 
 pub fn source_edit_from_references(
+    db: &RootDatabase,
     references: &[FileReference],
     def: Definition,
-    new_name: &str,
+    new_name: &Name,
     edition: Edition,
 ) -> TextEdit {
-    let new_name = if is_raw_identifier(new_name, edition) {
-        format!("r#{new_name}")
-    } else {
-        new_name.to_owned()
-    };
+    let name_display = new_name.display(db, edition);
     let mut edit = TextEdit::builder();
     // macros can cause multiple refs to occur for the same text range, so keep track of what we have edited so far
     let mut edited_ranges = Vec::new();
@@ -395,23 +421,15 @@ pub fn source_edit_from_references(
             // to make special rewrites like shorthand syntax and such, so just rename the node in
             // the macro input
             FileReferenceNode::NameRef(name_ref) if name_range == range => {
-                source_edit_from_name_ref(&mut edit, name_ref, &new_name, def)
+                source_edit_from_name_ref(&mut edit, name_ref, &name_display, def)
             }
             FileReferenceNode::Name(name) if name_range == range => {
-                source_edit_from_name(&mut edit, name, &new_name)
+                source_edit_from_name(&mut edit, name, &name_display)
             }
             _ => false,
         };
         if !has_emitted_edit && !edited_ranges.contains(&range.start()) {
-            let (range, new_name) = match name {
-                FileReferenceNode::Lifetime(_) => (
-                    TextRange::new(range.start() + syntax::TextSize::from(1), range.end()),
-                    new_name.strip_prefix('\'').unwrap_or(&new_name).to_owned(),
-                ),
-                _ => (range, new_name.to_owned()),
-            };
-
-            edit.replace(range, new_name);
+            edit.replace(range, name_display.to_string());
             edited_ranges.push(range.start());
         }
     }
@@ -419,7 +437,11 @@ pub fn source_edit_from_references(
     edit.finish()
 }
 
-fn source_edit_from_name(edit: &mut TextEditBuilder, name: &ast::Name, new_name: &str) -> bool {
+fn source_edit_from_name(
+    edit: &mut TextEditBuilder,
+    name: &ast::Name,
+    new_name: &dyn Display,
+) -> bool {
     if ast::RecordPatField::for_field_name(name).is_some() {
         if let Some(ident_pat) = name.syntax().parent().and_then(ast::IdentPat::cast) {
             cov_mark::hit!(rename_record_pat_field_name_split);
@@ -439,7 +461,7 @@ fn source_edit_from_name(edit: &mut TextEditBuilder, name: &ast::Name, new_name:
 fn source_edit_from_name_ref(
     edit: &mut TextEditBuilder,
     name_ref: &ast::NameRef,
-    new_name: &str,
+    new_name: &dyn Display,
     def: Definition,
 ) -> bool {
     if name_ref.super_token().is_some() {
@@ -452,6 +474,7 @@ fn source_edit_from_name_ref(
         match &(rcf_name_ref, rcf_expr.and_then(|it| expr_as_name_ref(&it))) {
             // field: init-expr, check if we can use a field init shorthand
             (Some(field_name), Some(init)) => {
+                let new_name = new_name.to_string();
                 if field_name == name_ref {
                     if init.text() == new_name {
                         cov_mark::hit!(test_rename_field_put_init_shorthand);
@@ -507,6 +530,7 @@ fn source_edit_from_name_ref(
             {
                 // field name is being renamed
                 if let Some(name) = pat.name() {
+                    let new_name = new_name.to_string();
                     if name.text() == new_name {
                         cov_mark::hit!(test_rename_field_put_init_shorthand_pat);
                         // Foo { field: ref mut local } -> Foo { ref mut field }
@@ -518,7 +542,7 @@ fn source_edit_from_name_ref(
                         let s = field_name.syntax().text_range().start();
                         let e = pat.syntax().text_range().start();
                         edit.delete(TextRange::new(s, e));
-                        edit.replace(name.syntax().text_range(), new_name.to_owned());
+                        edit.replace(name.syntax().text_range(), new_name);
                         return true;
                     }
                 }
@@ -532,16 +556,9 @@ fn source_edit_from_name_ref(
 fn source_edit_from_def(
     sema: &Semantics<'_, RootDatabase>,
     def: Definition,
-    new_name: &str,
+    new_name: &Name,
     source_change: &mut SourceChange,
 ) -> Result<(FileId, TextEdit)> {
-    let new_name_edition_aware = |new_name: &str, file_id: EditionedFileId| {
-        if is_raw_identifier(new_name, file_id.edition(sema.db)) {
-            format!("r#{new_name}")
-        } else {
-            new_name.to_owned()
-        }
-    };
     let mut edit = TextEdit::builder();
     if let Definition::Local(local) = def {
         let mut file_id = None;
@@ -573,7 +590,10 @@ fn source_edit_from_def(
                 {
                     Some(FileRange { file_id: file_id2, range }) => {
                         file_id = Some(file_id2);
-                        edit.replace(range, new_name_edition_aware(new_name, file_id2));
+                        edit.replace(
+                            range,
+                            new_name.display(sema.db, file_id2.edition(sema.db)).to_string(),
+                        );
                         continue;
                     }
                     None => {
@@ -587,7 +607,7 @@ fn source_edit_from_def(
                 // special cases required for renaming fields/locals in Record patterns
                 if let Some(pat_field) = pat.syntax().parent().and_then(ast::RecordPatField::cast) {
                     if let Some(name_ref) = pat_field.name_ref() {
-                        if new_name == name_ref.text().as_str().trim_start_matches("r#")
+                        if new_name.as_str() == name_ref.text().as_str().trim_start_matches("r#")
                             && pat.at_token().is_none()
                         {
                             // Foo { field: ref mut local } -> Foo { ref mut field }
@@ -607,7 +627,9 @@ fn source_edit_from_def(
                             //                      ^^^^^ replace this with `new_name`
                             edit.replace(
                                 name_range,
-                                new_name_edition_aware(new_name, source.file_id),
+                                new_name
+                                    .display(sema.db, source.file_id.edition(sema.db))
+                                    .to_string(),
                             );
                         }
                     } else {
@@ -618,10 +640,16 @@ fn source_edit_from_def(
                             pat.syntax().text_range().start(),
                             format!("{}: ", pat_field.field_name().unwrap()),
                         );
-                        edit.replace(name_range, new_name_edition_aware(new_name, source.file_id));
+                        edit.replace(
+                            name_range,
+                            new_name.display(sema.db, source.file_id.edition(sema.db)).to_string(),
+                        );
                     }
                 } else {
-                    edit.replace(name_range, new_name_edition_aware(new_name, source.file_id));
+                    edit.replace(
+                        name_range,
+                        new_name.display(sema.db, source.file_id.edition(sema.db)).to_string(),
+                    );
                 }
             }
         }
@@ -639,16 +667,13 @@ fn source_edit_from_def(
         .range_for_rename(sema)
         .ok_or_else(|| format_err!("No identifier available to rename"))?;
     let (range, new_name) = match def {
-        Definition::GenericParam(hir::GenericParam::LifetimeParam(_)) | Definition::Label(_) => (
-            TextRange::new(range.start() + syntax::TextSize::from(1), range.end()),
-            new_name.strip_prefix('\'').unwrap_or(new_name).to_owned(),
+        Definition::ExternCrateDecl(decl) if decl.alias(sema.db).is_none() => (
+            TextRange::empty(range.end()),
+            format!(" as {}", new_name.display(sema.db, file_id.edition(sema.db)),),
         ),
-        Definition::ExternCrateDecl(decl) if decl.alias(sema.db).is_none() => {
-            (TextRange::empty(range.end()), format!(" as {new_name}"))
-        }
-        _ => (range, new_name.to_owned()),
+        _ => (range, new_name.display(sema.db, file_id.edition(sema.db)).to_string()),
     };
-    edit.replace(range, new_name_edition_aware(&new_name, file_id));
+    edit.replace(range, new_name);
     Ok((file_id.file_id(sema.db), edit.finish()))
 }
 
@@ -657,26 +682,27 @@ pub enum IdentifierKind {
     Ident,
     Lifetime,
     Underscore,
+    LowercaseSelf,
 }
 
 impl IdentifierKind {
-    pub fn classify(new_name: &str) -> Result<IdentifierKind> {
-        let new_name = new_name.trim_start_matches("r#");
-        match parser::LexedStr::single_token(Edition::LATEST, new_name) {
+    pub fn classify(edition: Edition, new_name: &str) -> Result<(Name, IdentifierKind)> {
+        match parser::LexedStr::single_token(edition, new_name) {
             Some(res) => match res {
-                (SyntaxKind::IDENT, _) => {
-                    if let Some(inner) = new_name.strip_prefix("r#") {
-                        if matches!(inner, "self" | "crate" | "super" | "Self") {
-                            bail!("Invalid name: `{}` cannot be a raw identifier", inner);
-                        }
-                    }
-                    Ok(IdentifierKind::Ident)
+                (SyntaxKind::IDENT, _) => Ok((Name::new_root(new_name), IdentifierKind::Ident)),
+                (T![_], _) => {
+                    Ok((Name::new_symbol_root(sym::underscore), IdentifierKind::Underscore))
                 }
-                (T![_], _) => Ok(IdentifierKind::Underscore),
                 (SyntaxKind::LIFETIME_IDENT, _) if new_name != "'static" && new_name != "'_" => {
-                    Ok(IdentifierKind::Lifetime)
+                    Ok((Name::new_lifetime(new_name), IdentifierKind::Lifetime))
                 }
-                _ if is_raw_identifier(new_name, Edition::LATEST) => Ok(IdentifierKind::Ident),
+                _ if SyntaxKind::from_keyword(new_name, edition).is_some() => match new_name {
+                    "self" => Ok((Name::new_root(new_name), IdentifierKind::LowercaseSelf)),
+                    "crate" | "super" | "Self" => {
+                        bail!("Invalid name `{}`: cannot rename to a keyword", new_name)
+                    }
+                    _ => Ok((Name::new_root(new_name), IdentifierKind::Ident)),
+                },
                 (_, Some(syntax_error)) => bail!("Invalid name `{}`: {}", new_name, syntax_error),
                 (_, None) => bail!("Invalid name `{}`: not an identifier", new_name),
             },
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
index 38f10c778d6..519ff192799 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
@@ -1,5 +1,5 @@
 use hir::{CaseType, InFile, db::ExpandDatabase};
-use ide_db::{assists::Assist, defs::NameClass};
+use ide_db::{assists::Assist, defs::NameClass, rename::RenameDefinition};
 use syntax::AstNode;
 
 use crate::{
@@ -44,7 +44,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Option<Vec<Ass
     let label = format!("Rename to {}", d.suggested_text);
     let mut res = unresolved_fix("change_case", &label, frange.range);
     if ctx.resolve.should_resolve(&res.id) {
-        let source_change = def.rename(&ctx.sema, &d.suggested_text);
+        let source_change = def.rename(&ctx.sema, &d.suggested_text, RenameDefinition::Yes);
         res.source_change = Some(source_change.ok().unwrap_or_default());
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
index 87c9397fb77..bf7dddacd8c 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
@@ -135,6 +135,7 @@ pub(crate) fn json_in_items(
                         "JSON syntax is not valid as a Rust item",
                         FileRange { file_id: vfs_file_id, range },
                     )
+                    .stable()
                     .with_fixes(Some(vec![{
                         let mut scb = SourceChangeBuilder::new(vfs_file_id);
                         let scope = scb.make_import_scope_mut(import_scope);
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
index 84fb467a5ce..ef42f2dc744 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
@@ -1,4 +1,5 @@
 use either::Either;
+use hir::{Field, HasCrate};
 use hir::{HasSource, HirDisplay, Semantics, VariantId, db::ExpandDatabase};
 use ide_db::text_edit::TextEdit;
 use ide_db::{EditionedFileId, RootDatabase, source_change::SourceChange};
@@ -13,44 +14,69 @@ use crate::{Assist, Diagnostic, DiagnosticCode, DiagnosticsContext, fix};
 //
 // This diagnostic is triggered if created structure does not have field provided in record.
 pub(crate) fn no_such_field(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Diagnostic {
-    let node = d.field.map(Into::into);
-    if d.private {
-        // FIXME: quickfix to add required visibility
-        Diagnostic::new_with_syntax_node_ptr(
-            ctx,
-            DiagnosticCode::RustcHardError("E0451"),
-            "field is private",
-            node,
-        )
-        .stable()
+    let (code, message) = if d.private.is_some() {
+        ("E0451", "field is private")
+    } else if let VariantId::EnumVariantId(_) = d.variant {
+        ("E0559", "no such field")
     } else {
-        Diagnostic::new_with_syntax_node_ptr(
-            ctx,
-            match d.variant {
-                VariantId::EnumVariantId(_) => DiagnosticCode::RustcHardError("E0559"),
-                _ => DiagnosticCode::RustcHardError("E0560"),
-            },
-            "no such field",
-            node,
-        )
+        ("E0560", "no such field")
+    };
+
+    let node = d.field.map(Into::into);
+    Diagnostic::new_with_syntax_node_ptr(ctx, DiagnosticCode::RustcHardError(code), message, node)
         .stable()
         .with_fixes(fixes(ctx, d))
-    }
 }
 
 fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::NoSuchField) -> Option<Vec<Assist>> {
     // FIXME: quickfix for pattern
     let root = ctx.sema.db.parse_or_expand(d.field.file_id);
     match &d.field.value.to_node(&root) {
-        Either::Left(node) => missing_record_expr_field_fixes(
-            &ctx.sema,
-            d.field.file_id.original_file(ctx.sema.db),
-            node,
-        ),
+        Either::Left(node) => {
+            if let Some(private_field) = d.private {
+                field_is_private_fixes(
+                    &ctx.sema,
+                    d.field.file_id.original_file(ctx.sema.db),
+                    node,
+                    private_field,
+                )
+            } else {
+                missing_record_expr_field_fixes(
+                    &ctx.sema,
+                    d.field.file_id.original_file(ctx.sema.db),
+                    node,
+                )
+            }
+        }
         _ => None,
     }
 }
 
+fn field_is_private_fixes(
+    sema: &Semantics<'_, RootDatabase>,
+    usage_file_id: EditionedFileId,
+    record_expr_field: &ast::RecordExprField,
+    private_field: Field,
+) -> Option<Vec<Assist>> {
+    let def_crate = private_field.krate(sema.db);
+    let usage_crate = sema.file_to_module_def(usage_file_id.file_id(sema.db))?.krate();
+    let visibility = if usage_crate == def_crate { "pub(crate) " } else { "pub " };
+
+    let source = private_field.source(sema.db)?;
+    let (range, _) = source.syntax().original_file_range_opt(sema.db)?;
+    let source_change = SourceChange::from_text_edit(
+        range.file_id.file_id(sema.db),
+        TextEdit::insert(range.range.start(), visibility.into()),
+    );
+
+    Some(vec![fix(
+        "increase_field_visibility",
+        "Increase field visibility",
+        source_change,
+        sema.original_range(record_expr_field.syntax()).range,
+    )])
+}
+
 fn missing_record_expr_field_fixes(
     sema: &Semantics<'_, RootDatabase>,
     usage_file_id: EditionedFileId,
@@ -118,7 +144,7 @@ fn missing_record_expr_field_fixes(
         "create_field",
         "Create field",
         source_change,
-        record_expr_field.syntax().text_range(),
+        sema.original_range(record_expr_field.syntax()).range,
     )]);
 
     fn record_field_list(field_def_list: ast::FieldList) -> Option<ast::RecordFieldList> {
@@ -387,15 +413,15 @@ fn f(s@m::Struct {
     // assignee expression
     m::Struct {
         field: 0,
-      //^^^^^^^^ error: field is private
+      //^^^^^^^^ 💡 error: field is private
         field2
-      //^^^^^^ error: field is private
+      //^^^^^^ 💡 error: field is private
     } = s;
     m::Struct {
         field: 0,
-      //^^^^^^^^ error: field is private
+      //^^^^^^^^ 💡 error: field is private
         field2
-      //^^^^^^ error: field is private
+      //^^^^^^ 💡 error: field is private
     };
 }
 "#,
@@ -403,6 +429,77 @@ fn f(s@m::Struct {
     }
 
     #[test]
+    fn test_struct_field_private_same_crate_fix() {
+        check_diagnostics(
+            r#"
+mod m {
+    pub struct Struct {
+        field: u32,
+    }
+}
+fn f() {
+    let _ = m::Struct {
+        field: 0,
+      //^^^^^^^^ 💡 error: field is private
+    };
+}
+"#,
+        );
+
+        check_fix(
+            r#"
+mod m {
+    pub struct Struct {
+        field: u32,
+    }
+}
+fn f() {
+    let _ = m::Struct {
+        field$0: 0,
+    };
+}
+"#,
+            r#"
+mod m {
+    pub struct Struct {
+        pub(crate) field: u32,
+    }
+}
+fn f() {
+    let _ = m::Struct {
+        field: 0,
+    };
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_struct_field_private_other_crate_fix() {
+        check_fix(
+            r#"
+//- /lib.rs crate:another_crate
+pub struct Struct {
+    field: u32,
+}
+//- /lib.rs crate:this_crate deps:another_crate
+use another_crate;
+
+fn f() {
+    let _ = another_crate::Struct {
+        field$0: 0,
+    };
+}
+"#,
+            r#"
+pub struct Struct {
+    pub field: u32,
+}
+"#,
+        );
+    }
+
+    #[test]
     fn editions_between_macros() {
         check_diagnostics(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
index af9126c8933..d96c658d7b0 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
@@ -69,6 +69,7 @@ pub(crate) fn unlinked_file(
             FileRange { file_id, range },
         )
         .with_unused(unused)
+        .stable()
         .with_fixes(fixes),
     );
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
index 7c396339c14..f31886b9697 100644
--- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
@@ -800,4 +800,65 @@ foo();
                 foo();"#]],
         );
     }
+
+    #[test]
+    fn works_in_sig() {
+        check(
+            r#"
+macro_rules! foo {
+    () => { u32 };
+}
+fn foo() -> foo$0!() {
+    42
+}
+"#,
+            expect![[r#"
+                foo!
+                u32"#]],
+        );
+        check(
+            r#"
+macro_rules! foo {
+    () => { u32 };
+}
+fn foo(_: foo$0!() ) {}
+"#,
+            expect![[r#"
+                foo!
+                u32"#]],
+        );
+    }
+
+    #[test]
+    fn works_in_generics() {
+        check(
+            r#"
+trait Trait {}
+macro_rules! foo {
+    () => { Trait };
+}
+impl<const C: foo$0!()> Trait for () {}
+"#,
+            expect![[r#"
+                foo!
+                Trait"#]],
+        );
+    }
+
+    #[test]
+    fn works_in_fields() {
+        check(
+            r#"
+macro_rules! foo {
+    () => { u32 };
+}
+struct S {
+    field: foo$0!(),
+}
+"#,
+            expect![[r#"
+                foo!
+                u32"#]],
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
index 82704af647d..b094b098462 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -6,7 +6,7 @@ use std::{
 use either::Either;
 use hir::{
     ClosureStyle, DisplayTarget, EditionedFileId, HasVisibility, HirDisplay, HirDisplayError,
-    HirWrite, ModuleDef, ModuleDefId, Semantics, sym,
+    HirWrite, InRealFile, ModuleDef, ModuleDefId, Semantics, sym,
 };
 use ide_db::{FileRange, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder};
 use ide_db::{FxHashSet, text_edit::TextEdit};
@@ -34,6 +34,7 @@ mod extern_block;
 mod generic_param;
 mod implicit_drop;
 mod implicit_static;
+mod implied_dyn_trait;
 mod lifetime;
 mod param_name;
 mod range_exclusive;
@@ -95,16 +96,16 @@ pub(crate) fn inlay_hints(
         return acc;
     };
     let famous_defs = FamousDefs(&sema, scope.krate());
+    let display_target = famous_defs.1.to_display_target(sema.db);
 
     let ctx = &mut InlayHintCtx::default();
     let mut hints = |event| {
         if let Some(node) = handle_event(ctx, event) {
-            hints(&mut acc, ctx, &famous_defs, config, file_id, node);
+            hints(&mut acc, ctx, &famous_defs, config, file_id, display_target, node);
         }
     };
     let mut preorder = file.preorder();
     while let Some(event) = preorder.next() {
-        // FIXME: This can miss some hints that require the parent of the range to calculate
         if matches!((&event, range_limit), (WalkEvent::Enter(node), Some(range)) if range.intersect(node.text_range()).is_none())
         {
             preorder.skip_subtree();
@@ -144,10 +145,12 @@ pub(crate) fn inlay_hints_resolve(
     let famous_defs = FamousDefs(&sema, scope.krate());
     let mut acc = Vec::new();
 
+    let display_target = famous_defs.1.to_display_target(sema.db);
+
     let ctx = &mut InlayHintCtx::default();
     let mut hints = |event| {
         if let Some(node) = handle_event(ctx, event) {
-            hints(&mut acc, ctx, &famous_defs, config, file_id, node);
+            hints(&mut acc, ctx, &famous_defs, config, file_id, display_target, node);
         }
     };
 
@@ -202,17 +205,19 @@ fn handle_event(ctx: &mut InlayHintCtx, node: WalkEvent<SyntaxNode>) -> Option<S
 fn hints(
     hints: &mut Vec<InlayHint>,
     ctx: &mut InlayHintCtx,
-    famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
+    famous_defs @ FamousDefs(sema, _krate): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
     file_id: EditionedFileId,
+    display_target: DisplayTarget,
     node: SyntaxNode,
 ) {
-    let file_id = file_id.editioned_file_id(sema.db);
-    let Some(krate) = sema.first_crate(file_id.file_id()) else {
-        return;
-    };
-    let display_target = krate.to_display_target(sema.db);
-    closing_brace::hints(hints, sema, config, file_id, display_target, node.clone());
+    closing_brace::hints(
+        hints,
+        sema,
+        config,
+        display_target,
+        InRealFile { file_id, value: node.clone() },
+    );
     if let Some(any_has_generic_args) = ast::AnyHasGenericArgs::cast(node.clone()) {
         generic_param::hints(hints, famous_defs, config, any_has_generic_args);
     }
@@ -231,18 +236,18 @@ fn hints(
                         closure_captures::hints(hints, famous_defs, config, it.clone());
                         closure_ret::hints(hints, famous_defs, config, display_target, it)
                     },
-                    ast::Expr::RangeExpr(it) => range_exclusive::hints(hints, famous_defs, config, file_id,  it),
+                    ast::Expr::RangeExpr(it) => range_exclusive::hints(hints, famous_defs, config, it),
                     _ => Some(()),
                 }
             },
             ast::Pat(it) => {
-                binding_mode::hints(hints, famous_defs, config, file_id,  &it);
+                binding_mode::hints(hints, famous_defs, config, &it);
                 match it {
                     ast::Pat::IdentPat(it) => {
                         bind_pat::hints(hints, famous_defs, config, display_target, &it);
                     }
                     ast::Pat::RangePat(it) => {
-                        range_exclusive::hints(hints, famous_defs, config, file_id, it);
+                        range_exclusive::hints(hints, famous_defs, config, it);
                     }
                     _ => {}
                 }
@@ -250,30 +255,38 @@ fn hints(
             },
             ast::Item(it) => match it {
                 ast::Item::Fn(it) => {
-                    implicit_drop::hints(hints, famous_defs, config, file_id, &it);
+                    implicit_drop::hints(hints, famous_defs, config, display_target, &it);
                     if let Some(extern_block) = &ctx.extern_block_parent {
-                        extern_block::fn_hints(hints, famous_defs, config, file_id, &it, extern_block);
+                        extern_block::fn_hints(hints, famous_defs, config, &it, extern_block);
                     }
-                    lifetime::fn_hints(hints, ctx, famous_defs, config, file_id, it)
+                    lifetime::fn_hints(hints, ctx, famous_defs, config,  it)
                 },
                 ast::Item::Static(it) => {
                     if let Some(extern_block) = &ctx.extern_block_parent {
-                        extern_block::static_hints(hints, famous_defs, config, file_id, &it, extern_block);
+                        extern_block::static_hints(hints, famous_defs, config, &it, extern_block);
                     }
-                    implicit_static::hints(hints, famous_defs, config, file_id, Either::Left(it))
+                    implicit_static::hints(hints, famous_defs, config,  Either::Left(it))
                 },
-                ast::Item::Const(it) => implicit_static::hints(hints, famous_defs, config, file_id, Either::Right(it)),
-                ast::Item::Enum(it) => discriminant::enum_hints(hints, famous_defs, config, file_id, it),
-                ast::Item::ExternBlock(it) => extern_block::extern_block_hints(hints, famous_defs, config, file_id, it),
+                ast::Item::Const(it) => implicit_static::hints(hints, famous_defs, config, Either::Right(it)),
+                ast::Item::Enum(it) => discriminant::enum_hints(hints, famous_defs, config, it),
+                ast::Item::ExternBlock(it) => extern_block::extern_block_hints(hints, famous_defs, config, it),
                 _ => None,
             },
             // FIXME: trait object type elisions
             ast::Type(ty) => match ty {
-                ast::Type::FnPtrType(ptr) => lifetime::fn_ptr_hints(hints, ctx, famous_defs, config, file_id, ptr),
-                ast::Type::PathType(path) => lifetime::fn_path_hints(hints, ctx, famous_defs, config, file_id, path),
+                ast::Type::FnPtrType(ptr) => lifetime::fn_ptr_hints(hints, ctx, famous_defs, config,  ptr),
+                ast::Type::PathType(path) => {
+                    lifetime::fn_path_hints(hints, ctx, famous_defs, config, &path);
+                    implied_dyn_trait::hints(hints, famous_defs, config, Either::Left(path));
+                    Some(())
+                },
+                ast::Type::DynTraitType(dyn_) => {
+                    implied_dyn_trait::hints(hints, famous_defs, config, Either::Right(dyn_));
+                    Some(())
+                },
                 _ => Some(()),
             },
-            ast::GenericParamList(it) => bounds::hints(hints, famous_defs, config, file_id, it),
+            ast::GenericParamList(it) => bounds::hints(hints, famous_defs, config,  it),
             _ => Some(()),
         }
     };
@@ -438,6 +451,7 @@ pub enum InlayKind {
     Parameter,
     GenericParameter,
     Type,
+    Dyn,
     Drop,
     RangeExclusive,
     ExternUnsafety,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
index d2917320688..169ab92342b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs
@@ -8,7 +8,6 @@ use hir::Mutability;
 use ide_db::famous_defs::FamousDefs;
 
 use ide_db::text_edit::TextEditBuilder;
-use span::EditionedFileId;
 use syntax::ast::{self, AstNode};
 
 use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind};
@@ -17,7 +16,6 @@ pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    _file_id: EditionedFileId,
     pat: &ast::Pat,
 ) -> Option<()> {
     if !config.binding_mode_hints {
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs
index 8ddbfaeffe8..b9a98f88be7 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs
@@ -3,7 +3,6 @@
 //! Currently this renders the implied `Sized` bound.
 use ide_db::{FileRange, famous_defs::FamousDefs};
 
-use span::EditionedFileId;
 use syntax::ast::{self, AstNode, HasTypeBounds};
 
 use crate::{
@@ -15,7 +14,6 @@ pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    _file_id: EditionedFileId,
     params: ast::GenericParamList,
 ) -> Option<()> {
     if !config.sized_bound {
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
index 2ec85da4a42..ca3a982760f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
@@ -3,9 +3,8 @@
 //! fn g() {
 //! } /* fn g */
 //! ```
-use hir::{DisplayTarget, HirDisplay, Semantics};
+use hir::{DisplayTarget, HirDisplay, InRealFile, Semantics};
 use ide_db::{FileRange, RootDatabase};
-use span::EditionedFileId;
 use syntax::{
     SyntaxKind, SyntaxNode, T,
     ast::{self, AstNode, HasLoopBody, HasName},
@@ -21,15 +20,14 @@ pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     sema: &Semantics<'_, RootDatabase>,
     config: &InlayHintsConfig,
-    file_id: EditionedFileId,
     display_target: DisplayTarget,
-    original_node: SyntaxNode,
+    InRealFile { file_id, value: node }: InRealFile<SyntaxNode>,
 ) -> Option<()> {
     let min_lines = config.closing_brace_hints_min_lines?;
 
     let name = |it: ast::Name| it.syntax().text_range();
 
-    let mut node = original_node.clone();
+    let mut node = node.clone();
     let mut closing_token;
     let (label, name_range) = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) {
         closing_token = item_list.r_curly_token()?;
@@ -44,7 +42,7 @@ pub(super) fn hints(
                     let hint_text = match trait_ {
                         Some(tr) => format!(
                             "impl {} for {}",
-                            tr.name(sema.db).display(sema.db, file_id.edition()),
+                            tr.name(sema.db).display(sema.db, display_target.edition),
                             ty.display_truncated(sema.db, config.max_length, display_target,
                         )),
                         None => format!("impl {}", ty.display_truncated(sema.db, config.max_length, display_target)),
@@ -142,7 +140,8 @@ pub(super) fn hints(
         return None;
     }
 
-    let linked_location = name_range.map(|range| FileRange { file_id: file_id.into(), range });
+    let linked_location =
+        name_range.map(|range| FileRange { file_id: file_id.file_id(sema.db), range });
     acc.push(InlayHint {
         range: closing_token.text_range(),
         kind: InlayKind::ClosingBrace,
@@ -151,7 +150,7 @@ pub(super) fn hints(
         position: InlayHintPosition::After,
         pad_left: true,
         pad_right: false,
-        resolve_parent: Some(original_node.text_range()),
+        resolve_parent: Some(node.text_range()),
     });
 
     None
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
index 827a0438dd0..a2a702835a7 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs
@@ -7,7 +7,6 @@
 use hir::Semantics;
 use ide_db::text_edit::TextEdit;
 use ide_db::{RootDatabase, famous_defs::FamousDefs};
-use span::EditionedFileId;
 use syntax::ast::{self, AstNode, HasName};
 
 use crate::{
@@ -19,7 +18,6 @@ pub(super) fn enum_hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    _: EditionedFileId,
     enum_: ast::Enum,
 ) -> Option<()> {
     if let DiscriminantHints::Never = config.discriminant_hints {
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs
index 20f54b2cd19..88152bf3e38 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs
@@ -1,6 +1,5 @@
 //! Extern block hints
 use ide_db::{famous_defs::FamousDefs, text_edit::TextEdit};
-use span::EditionedFileId;
 use syntax::{AstNode, SyntaxToken, ast};
 
 use crate::{InlayHint, InlayHintsConfig};
@@ -9,7 +8,6 @@ pub(super) fn extern_block_hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    _file_id: EditionedFileId,
     extern_block: ast::ExternBlock,
 ) -> Option<()> {
     if extern_block.unsafe_token().is_some() {
@@ -36,7 +34,6 @@ pub(super) fn fn_hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    _file_id: EditionedFileId,
     fn_: &ast::Fn,
     extern_block: &ast::ExternBlock,
 ) -> Option<()> {
@@ -55,7 +52,6 @@ pub(super) fn static_hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    _file_id: EditionedFileId,
     static_: &ast::Static,
     extern_block: &ast::ExternBlock,
 ) -> Option<()> {
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
index f52e27946ff..bf4688e9d82 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
@@ -12,7 +12,6 @@ use hir::{
 };
 use ide_db::{FileRange, famous_defs::FamousDefs};
 
-use span::EditionedFileId;
 use syntax::{
     ToSmolStr,
     ast::{self, AstNode},
@@ -25,7 +24,7 @@ pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    file_id: EditionedFileId,
+    display_target: hir::DisplayTarget,
     node: &ast::Fn,
 ) -> Option<()> {
     if !config.implicit_drop_hints {
@@ -94,7 +93,7 @@ pub(super) fn hints(
                 MirSpan::Unknown => continue,
             };
             let binding = &hir.bindings[binding_idx];
-            let name = binding.name.display_no_db(file_id.edition()).to_smolstr();
+            let name = binding.name.display_no_db(display_target.edition).to_smolstr();
             if name.starts_with("<ra@") {
                 continue; // Ignore desugared variables
             }
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
index f3be09f30a1..7212efd954e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs
@@ -5,7 +5,6 @@
 use either::Either;
 use ide_db::famous_defs::FamousDefs;
 use ide_db::text_edit::TextEdit;
-use span::EditionedFileId;
 use syntax::{
     SyntaxKind,
     ast::{self, AstNode},
@@ -17,7 +16,6 @@ pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(_sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    _file_id: EditionedFileId,
     statik_or_const: Either<ast::Static, ast::Const>,
 ) -> Option<()> {
     if config.lifetime_elision_hints != LifetimeElisionHints::Always {
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implied_dyn_trait.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implied_dyn_trait.rs
new file mode 100644
index 00000000000..32d130503a4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implied_dyn_trait.rs
@@ -0,0 +1,133 @@
+//! Implementation of trait bound hints.
+//!
+//! Currently this renders the implied `Sized` bound.
+use either::Either;
+use ide_db::{famous_defs::FamousDefs, text_edit::TextEdit};
+
+use syntax::ast::{self, AstNode};
+
+use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind};
+
+pub(super) fn hints(
+    acc: &mut Vec<InlayHint>,
+    FamousDefs(sema, _): &FamousDefs<'_, '_>,
+    config: &InlayHintsConfig,
+    path: Either<ast::PathType, ast::DynTraitType>,
+) -> Option<()> {
+    let parent = path.syntax().parent()?;
+    let range = match path {
+        Either::Left(path) => {
+            let paren =
+                parent.ancestors().take_while(|it| ast::ParenType::can_cast(it.kind())).last();
+            let parent = paren.as_ref().and_then(|it| it.parent()).unwrap_or(parent);
+            if ast::TypeBound::can_cast(parent.kind())
+                || ast::TypeAnchor::can_cast(parent.kind())
+                || ast::Impl::cast(parent)
+                    .and_then(|it| it.trait_())
+                    .is_some_and(|it| it.syntax() == path.syntax())
+            {
+                return None;
+            }
+            sema.resolve_trait(&path.path()?)?;
+            paren.map_or_else(|| path.syntax().text_range(), |it| it.text_range())
+        }
+        Either::Right(dyn_) => {
+            if dyn_.dyn_token().is_some() {
+                return None;
+            }
+
+            dyn_.syntax().text_range()
+        }
+    };
+
+    acc.push(InlayHint {
+        range,
+        kind: InlayKind::Dyn,
+        label: InlayHintLabel::simple("dyn", None, None),
+        text_edit: Some(
+            config.lazy_text_edit(|| TextEdit::insert(range.start(), "dyn ".to_owned())),
+        ),
+        position: InlayHintPosition::Before,
+        pad_left: false,
+        pad_right: true,
+        resolve_parent: Some(range),
+    });
+
+    Some(())
+}
+
+#[cfg(test)]
+mod tests {
+
+    use expect_test::expect;
+
+    use crate::inlay_hints::InlayHintsConfig;
+
+    use crate::inlay_hints::tests::{DISABLED_CONFIG, check_edit, check_with_config};
+
+    #[track_caller]
+    fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
+        check_with_config(InlayHintsConfig { sized_bound: true, ..DISABLED_CONFIG }, ra_fixture);
+    }
+
+    #[test]
+    fn path_works() {
+        check(
+            r#"
+struct S {}
+trait T {}
+fn foo(_: T,  _: dyn T, _: S) {}
+       // ^ dyn
+fn foo(_: &T,  _: for<'a> T) {}
+        // ^ dyn
+                       // ^ dyn
+impl T {}
+  // ^ dyn
+impl T for (T) {}
+        // ^^^ dyn
+"#,
+        );
+    }
+
+    #[test]
+    fn missing_dyn_bounds() {
+        check(
+            r#"
+trait T {}
+fn foo(
+    _: T + T,
+    // ^^^^^ dyn
+    _: T + 'a,
+    // ^^^^^^ dyn
+    _: 'a + T,
+    // ^^^^^^ dyn
+    _: &(T + T)
+    //   ^^^^^ dyn
+    _: &mut (T + T)
+    //       ^^^^^ dyn
+    _: *mut (T),
+    //      ^^^ dyn
+) {}
+"#,
+        );
+    }
+
+    #[test]
+    fn edit() {
+        check_edit(
+            DISABLED_CONFIG,
+            r#"
+trait T {}
+fn foo(
+    _: &mut T
+) {}
+"#,
+            expect![[r#"
+                trait T {}
+                fn foo(
+                    _: &mut dyn T
+                ) {}
+            "#]],
+        );
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs
index baba49a427d..0069452e7b9 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/lifetime.rs
@@ -6,7 +6,6 @@ use std::iter;
 
 use ide_db::{FxHashMap, famous_defs::FamousDefs, syntax_helpers::node_ext::walk_ty};
 use itertools::Itertools;
-use span::EditionedFileId;
 use syntax::{SmolStr, format_smolstr};
 use syntax::{
     SyntaxKind, SyntaxToken,
@@ -23,7 +22,6 @@ pub(super) fn fn_hints(
     ctx: &mut InlayHintCtx,
     fd: &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    file_id: EditionedFileId,
     func: ast::Fn,
 ) -> Option<()> {
     if config.lifetime_elision_hints == LifetimeElisionHints::Never {
@@ -40,7 +38,6 @@ pub(super) fn fn_hints(
         ctx,
         fd,
         config,
-        file_id,
         param_list.params().filter_map(|it| {
             Some((
                 it.pat().and_then(|it| match it {
@@ -74,7 +71,6 @@ pub(super) fn fn_ptr_hints(
     ctx: &mut InlayHintCtx,
     fd: &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    file_id: EditionedFileId,
     func: ast::FnPtrType,
 ) -> Option<()> {
     if config.lifetime_elision_hints == LifetimeElisionHints::Never {
@@ -97,7 +93,6 @@ pub(super) fn fn_ptr_hints(
         ctx,
         fd,
         config,
-        file_id,
         param_list.params().filter_map(|it| {
             Some((
                 it.pat().and_then(|it| match it {
@@ -140,8 +135,7 @@ pub(super) fn fn_path_hints(
     ctx: &mut InlayHintCtx,
     fd: &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    file_id: EditionedFileId,
-    func: ast::PathType,
+    func: &ast::PathType,
 ) -> Option<()> {
     if config.lifetime_elision_hints == LifetimeElisionHints::Never {
         return None;
@@ -163,7 +157,6 @@ pub(super) fn fn_path_hints(
         ctx,
         fd,
         config,
-        file_id,
         param_list.type_args().filter_map(|it| Some((None, it.ty()?))),
         generic_param_list,
         ret_type,
@@ -202,7 +195,6 @@ fn hints_(
     ctx: &mut InlayHintCtx,
     FamousDefs(_, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    _file_id: EditionedFileId,
     params: impl Iterator<Item = (Option<ast::Name>, ast::Type)>,
     generic_param_list: Option<ast::GenericParamList>,
     ret_type: Option<ast::RetType>,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs
index d67d8458840..47bd6d737f8 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs
@@ -4,7 +4,6 @@
 //! if let ../* < */100 = 50 {}
 //! ```
 use ide_db::famous_defs::FamousDefs;
-use span::EditionedFileId;
 use syntax::{SyntaxToken, T, ast};
 
 use crate::{InlayHint, InlayHintsConfig};
@@ -13,7 +12,6 @@ pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
     FamousDefs(_sema, _): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
-    _file_id: EditionedFileId,
     range: impl ast::RangeItem,
 ) -> Option<()> {
     (config.range_exclusive_hints && range.end().is_some())
diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs
index 0423e3da2c8..fb84e8e6b47 100644
--- a/src/tools/rust-analyzer/crates/ide/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs
@@ -4,11 +4,11 @@
 //! tests. This module also implements a couple of magic tricks, like renaming
 //! `self` and to `self` (to switch between associated function and method).
 
-use hir::{AsAssocItem, InFile, Semantics};
+use hir::{AsAssocItem, InFile, Name, Semantics, sym};
 use ide_db::{
     FileId, FileRange, RootDatabase,
     defs::{Definition, NameClass, NameRefClass},
-    rename::{IdentifierKind, bail, format_err, source_edit_from_references},
+    rename::{IdentifierKind, RenameDefinition, bail, format_err, source_edit_from_references},
     source_change::SourceChangeBuilder,
 };
 use itertools::Itertools;
@@ -33,8 +33,8 @@ pub(crate) fn prepare_rename(
     let source_file = sema.parse_guess_edition(position.file_id);
     let syntax = source_file.syntax();
 
-    let res = find_definitions(&sema, syntax, position)?
-        .map(|(frange, kind, def)| {
+    let res = find_definitions(&sema, syntax, position, &Name::new_symbol_root(sym::underscore))?
+        .map(|(frange, kind, def, _, _)| {
             // ensure all ranges are valid
 
             if def.range_for_rename(&sema).is_none() {
@@ -88,22 +88,28 @@ pub(crate) fn rename(
     let source_file = sema.parse(file_id);
     let syntax = source_file.syntax();
 
-    let defs = find_definitions(&sema, syntax, position)?;
-    let alias_fallback = alias_fallback(syntax, position, new_name);
+    let edition = file_id.edition(db);
+    let (new_name, kind) = IdentifierKind::classify(edition, new_name)?;
+
+    let defs = find_definitions(&sema, syntax, position, &new_name)?;
+    let alias_fallback =
+        alias_fallback(syntax, position, &new_name.display(db, edition).to_string());
 
     let ops: RenameResult<Vec<SourceChange>> = match alias_fallback {
         Some(_) => defs
             // FIXME: This can use the `ide_db::rename_reference` (or def.rename) method once we can
             // properly find "direct" usages/references.
-            .map(|(.., def)| {
-                match IdentifierKind::classify(new_name)? {
+            .map(|(.., def, new_name, _)| {
+                match kind {
                     IdentifierKind::Ident => (),
                     IdentifierKind::Lifetime => {
                         bail!("Cannot alias reference to a lifetime identifier")
                     }
                     IdentifierKind::Underscore => bail!("Cannot alias reference to `_`"),
+                    IdentifierKind::LowercaseSelf => {
+                        bail!("Cannot rename alias reference to `self`")
+                    }
                 };
-
                 let mut usages = def.usages(&sema).all();
 
                 // FIXME: hack - removes the usage that triggered this rename operation.
@@ -120,7 +126,7 @@ pub(crate) fn rename(
                 source_change.extend(usages.references.get_mut(&file_id).iter().map(|refs| {
                     (
                         position.file_id,
-                        source_edit_from_references(refs, def, new_name, file_id.edition(db)),
+                        source_edit_from_references(db, refs, def, &new_name, edition),
                     )
                 }));
 
@@ -128,18 +134,18 @@ pub(crate) fn rename(
             })
             .collect(),
         None => defs
-            .map(|(.., def)| {
+            .map(|(.., def, new_name, rename_def)| {
                 if let Definition::Local(local) = def {
                     if let Some(self_param) = local.as_self_param(sema.db) {
                         cov_mark::hit!(rename_self_to_param);
-                        return rename_self_to_param(&sema, local, self_param, new_name);
+                        return rename_self_to_param(&sema, local, self_param, &new_name, kind);
                     }
-                    if new_name == "self" {
+                    if kind == IdentifierKind::LowercaseSelf {
                         cov_mark::hit!(rename_to_self);
                         return rename_to_self(&sema, local);
                     }
                 }
-                def.rename(&sema, new_name)
+                def.rename(&sema, new_name.as_str(), rename_def)
             })
             .collect(),
     };
@@ -159,7 +165,7 @@ pub(crate) fn will_rename_file(
     let sema = Semantics::new(db);
     let module = sema.file_to_module_def(file_id)?;
     let def = Definition::Module(module);
-    let mut change = def.rename(&sema, new_name_stem).ok()?;
+    let mut change = def.rename(&sema, new_name_stem, RenameDefinition::Yes).ok()?;
     change.file_system_edits.clear();
     Some(change)
 }
@@ -200,22 +206,40 @@ fn find_definitions(
     sema: &Semantics<'_, RootDatabase>,
     syntax: &SyntaxNode,
     FilePosition { file_id, offset }: FilePosition,
-) -> RenameResult<impl Iterator<Item = (FileRange, SyntaxKind, Definition)>> {
-    let token = syntax.token_at_offset(offset).find(|t| matches!(t.kind(), SyntaxKind::STRING));
+    new_name: &Name,
+) -> RenameResult<impl Iterator<Item = (FileRange, SyntaxKind, Definition, Name, RenameDefinition)>>
+{
+    let maybe_format_args =
+        syntax.token_at_offset(offset).find(|t| matches!(t.kind(), SyntaxKind::STRING));
 
     if let Some((range, _, _, Some(resolution))) =
-        token.and_then(|token| sema.check_for_format_args_template(token, offset))
+        maybe_format_args.and_then(|token| sema.check_for_format_args_template(token, offset))
     {
         return Ok(vec![(
             FileRange { file_id, range },
             SyntaxKind::STRING,
             Definition::from(resolution),
+            new_name.clone(),
+            RenameDefinition::Yes,
         )]
         .into_iter());
     }
 
+    let original_ident = syntax
+        .token_at_offset(offset)
+        .max_by_key(|t| {
+            t.kind().is_any_identifier() || matches!(t.kind(), SyntaxKind::LIFETIME_IDENT)
+        })
+        .map(|t| {
+            if t.kind() == SyntaxKind::LIFETIME_IDENT {
+                Name::new_lifetime(t.text())
+            } else {
+                Name::new_root(t.text())
+            }
+        })
+        .ok_or_else(|| format_err!("No references found at position"))?;
     let symbols =
-        sema.find_nodes_at_offset_with_descend::<ast::NameLike>(syntax, offset).map(|name_like| {
+        sema.find_namelike_at_offset_with_descend(syntax, offset).map(|name_like| {
             let kind = name_like.syntax().kind();
             let range = sema
                 .original_range_opt(name_like.syntax())
@@ -284,23 +308,28 @@ fn find_definitions(
                         .ok_or_else(|| format_err!("No references found at position"))
                 }
             };
-            res.map(|def| (range, kind, def))
+            res.map(|def| {
+                let n = def.name(sema.db)?;
+                if n == original_ident {
+                    Some((range, kind, def, new_name.clone(), RenameDefinition::Yes))
+                } else if let Some(suffix) =  n.as_str().strip_prefix(original_ident.as_str()) {
+                    Some((range, kind, def, Name::new_root(&format!("{}{suffix}", new_name.as_str())), RenameDefinition::No))
+                } else {
+                     n.as_str().strip_suffix(original_ident.as_str().trim_start_matches('\''))
+                        .map(|prefix| (range, kind, def, Name::new_root(&format!("{prefix}{}", new_name.as_str())), RenameDefinition::No))
+                }
+            })
         });
 
-    let res: RenameResult<Vec<_>> = symbols.collect();
+    let res: RenameResult<Vec<_>> = symbols.filter_map(Result::transpose).collect();
     match res {
         Ok(v) => {
-            if v.is_empty() {
-                // FIXME: some semantic duplication between "empty vec" and "Err()"
-                Err(format_err!("No references found at position"))
-            } else {
-                // remove duplicates, comparing `Definition`s
-                Ok(v.into_iter()
-                    .unique_by(|&(.., def)| def)
-                    .map(|(a, b, c)| (a.into_file_id(sema.db), b, c))
-                    .collect::<Vec<_>>()
-                    .into_iter())
-            }
+            // remove duplicates, comparing `Definition`s
+            Ok(v.into_iter()
+                .unique_by(|&(.., def, _, _)| def)
+                .map(|(a, b, c, d, e)| (a.into_file_id(sema.db), b, c, d, e))
+                .collect::<Vec<_>>()
+                .into_iter())
         }
         Err(e) => Err(e),
     }
@@ -370,7 +399,13 @@ fn rename_to_self(
     source_change.extend(usages.iter().map(|(file_id, references)| {
         (
             file_id.file_id(sema.db),
-            source_edit_from_references(references, def, "self", file_id.edition(sema.db)),
+            source_edit_from_references(
+                sema.db,
+                references,
+                def,
+                &Name::new_symbol_root(sym::self_),
+                file_id.edition(sema.db),
+            ),
         )
     }));
     source_change.insert_source_edit(
@@ -384,23 +419,25 @@ fn rename_self_to_param(
     sema: &Semantics<'_, RootDatabase>,
     local: hir::Local,
     self_param: hir::SelfParam,
-    new_name: &str,
+    new_name: &Name,
+    identifier_kind: IdentifierKind,
 ) -> RenameResult<SourceChange> {
-    if new_name == "self" {
+    if identifier_kind == IdentifierKind::LowercaseSelf {
         // Let's do nothing rather than complain.
         cov_mark::hit!(rename_self_to_self);
         return Ok(SourceChange::default());
     }
 
-    let identifier_kind = IdentifierKind::classify(new_name)?;
-
     let InFile { file_id, value: self_param } =
         sema.source(self_param).ok_or_else(|| format_err!("cannot find function source"))?;
 
     let def = Definition::Local(local);
     let usages = def.usages(sema).all();
-    let edit = text_edit_from_self_param(&self_param, new_name)
-        .ok_or_else(|| format_err!("No target type found"))?;
+    let edit = text_edit_from_self_param(
+        &self_param,
+        new_name.display(sema.db, file_id.edition(sema.db)).to_string(),
+    )
+    .ok_or_else(|| format_err!("No target type found"))?;
     if usages.len() > 1 && identifier_kind == IdentifierKind::Underscore {
         bail!("Cannot rename reference to `_` as it is being referenced multiple times");
     }
@@ -409,13 +446,19 @@ fn rename_self_to_param(
     source_change.extend(usages.iter().map(|(file_id, references)| {
         (
             file_id.file_id(sema.db),
-            source_edit_from_references(references, def, new_name, file_id.edition(sema.db)),
+            source_edit_from_references(
+                sema.db,
+                references,
+                def,
+                new_name,
+                file_id.edition(sema.db),
+            ),
         )
     }));
     Ok(source_change)
 }
 
-fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: &str) -> Option<TextEdit> {
+fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: String) -> Option<TextEdit> {
     fn target_type_name(impl_def: &ast::Impl) -> Option<String> {
         if let Some(ast::Type::PathType(p)) = impl_def.self_ty() {
             return Some(p.path()?.segment()?.name_ref()?.text().to_string());
@@ -427,7 +470,7 @@ fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: &str) -> Opt
         Some(impl_def) => {
             let type_name = target_type_name(&impl_def)?;
 
-            let mut replacement_text = String::from(new_name);
+            let mut replacement_text = new_name;
             replacement_text.push_str(": ");
             match (self_param.amp_token(), self_param.mut_token()) {
                 (Some(_), None) => replacement_text.push('&'),
@@ -440,7 +483,7 @@ fn text_edit_from_self_param(self_param: &ast::SelfParam, new_name: &str) -> Opt
         }
         None => {
             cov_mark::hit!(rename_self_outside_of_methods);
-            let mut replacement_text = String::from(new_name);
+            let mut replacement_text = new_name;
             replacement_text.push_str(": _");
             Some(TextEdit::replace(self_param.syntax().text_range(), replacement_text))
         }
@@ -710,7 +753,7 @@ impl Foo {
         check(
             "super",
             r#"fn main() { let i$0 = 1; }"#,
-            "error: Invalid name `super`: not an identifier",
+            "error: Invalid name `super`: cannot rename to a keyword",
         );
     }
 
@@ -759,7 +802,11 @@ impl Foo {
 
     #[test]
     fn test_rename_mod_invalid_raw_ident() {
-        check("r#self", r#"mod foo$0 {}"#, "error: Invalid name `self`: not an identifier");
+        check(
+            "r#self",
+            r#"mod foo$0 {}"#,
+            "error: Invalid name `self`: cannot rename module to self",
+        );
     }
 
     #[test]
@@ -2359,7 +2406,6 @@ fn foo(foo: Foo) {
 
     #[test]
     fn test_rename_lifetimes() {
-        cov_mark::check!(rename_lifetime);
         check(
             "'yeeee",
             r#"
@@ -2536,7 +2582,7 @@ fn baz() {
     x.0$0 = 5;
 }
 "#,
-            "error: No identifier available to rename",
+            "error: No references found at position",
         );
     }
 
@@ -2566,7 +2612,7 @@ impl Foo {
     }
 }
 "#,
-            "error: Cannot rename `Self`",
+            "error: No references found at position",
         );
     }
 
@@ -3262,4 +3308,100 @@ trait Trait<U> {
 "#,
         );
     }
+
+    #[test]
+    fn rename_macro_generated_type_from_type_with_a_suffix() {
+        check(
+            "Bar",
+            r#"
+//- proc_macros: generate_suffixed_type
+#[proc_macros::generate_suffixed_type]
+struct Foo$0;
+fn usage(_: FooSuffix) {}
+usage(FooSuffix);
+"#,
+            r#"
+#[proc_macros::generate_suffixed_type]
+struct Bar;
+fn usage(_: BarSuffix) {}
+usage(BarSuffix);
+"#,
+        );
+    }
+
+    #[test]
+    // FIXME
+    #[should_panic]
+    fn rename_macro_generated_type_from_type_usage_with_a_suffix() {
+        check(
+            "Bar",
+            r#"
+//- proc_macros: generate_suffixed_type
+#[proc_macros::generate_suffixed_type]
+struct Foo;
+fn usage(_: FooSuffix) {}
+usage(FooSuffix);
+fn other_place() { Foo$0; }
+"#,
+            r#"
+#[proc_macros::generate_suffixed_type]
+struct Bar;
+fn usage(_: BarSuffix) {}
+usage(BarSuffix);
+fn other_place() { Bar; }
+"#,
+        );
+    }
+
+    #[test]
+    fn rename_macro_generated_type_from_variant_with_a_suffix() {
+        check(
+            "Bar",
+            r#"
+//- proc_macros: generate_suffixed_type
+#[proc_macros::generate_suffixed_type]
+enum Quux {
+    Foo$0,
+}
+fn usage(_: FooSuffix) {}
+usage(FooSuffix);
+"#,
+            r#"
+#[proc_macros::generate_suffixed_type]
+enum Quux {
+    Bar,
+}
+fn usage(_: BarSuffix) {}
+usage(BarSuffix);
+"#,
+        );
+    }
+
+    #[test]
+    // FIXME
+    #[should_panic]
+    fn rename_macro_generated_type_from_variant_usage_with_a_suffix() {
+        check(
+            "Bar",
+            r#"
+//- proc_macros: generate_suffixed_type
+#[proc_macros::generate_suffixed_type]
+enum Quux {
+    Foo,
+}
+fn usage(_: FooSuffix) {}
+usage(FooSuffix);
+fn other_place() { Quux::Foo$0; }
+"#,
+            r#"
+#[proc_macros::generate_suffixed_type]
+enum Quux {
+    Bar,
+}
+fn usage(_: BarSuffix) {}
+usage(BartSuffix);
+fn other_place() { Quux::Bar$0; }
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
index 8cc332d4633..8ed0fc6729f 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs
@@ -562,8 +562,12 @@ fn closure_expr(p: &mut Parser<'_>) -> CompletedMarker {
 
     let m = p.start();
 
+    // test closure_binder
+    // fn main() { for<'a> || (); }
     if p.at(T![for]) {
+        let b = p.start();
         types::for_binder(p);
+        b.complete(p, CLOSURE_BINDER);
     }
     // test const_closure
     // fn main() { let cl = const || _ = 0; }
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
index 9d4fdbfaf2e..ea5a3bc8593 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
@@ -201,6 +201,17 @@ fn type_bound(p: &mut Parser<'_>) -> bool {
             }
             if paths::is_use_path_start(p) {
                 types::path_type_bounds(p, false);
+                // test_err type_bounds_macro_call_recovery
+                // fn foo<T: T![], T: T!, T: T!{}>() -> Box<T! + T!{}> {}
+                if p.at(T![!]) {
+                    let m = p.start();
+                    p.bump(T![!]);
+                    p.error("unexpected `!` in type path, macro calls are not allowed here");
+                    if p.at_ts(TokenSet::new(&[T!['{'], T!['['], T!['(']])) {
+                        items::token_tree(p);
+                    }
+                    m.complete(p, ERROR);
+                }
             } else {
                 m.abandon(p);
                 return false;
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs
index 770827c6b0d..dfe7cb57d24 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/paths.rs
@@ -89,19 +89,22 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) -> Option<Completed
     // test qual_paths
     // type X = <A as B>::Output;
     // fn foo() { <usize as Default>::default(); }
-    if first && p.eat(T![<]) {
+    if first && p.at(T![<]) {
+        let m = p.start();
+        p.bump(T![<]);
         // test_err angled_path_without_qual
         // type X = <()>;
         // type Y = <A as B>;
         types::type_(p);
         if p.eat(T![as]) {
             if is_use_path_start(p) {
-                types::path_type(p);
+                types::path_type_bounds(p, true);
             } else {
                 p.error("expected a trait");
             }
         }
         p.expect(T![>]);
+        m.complete(p, TYPE_ANCHOR);
         if !p.at(T![::]) {
             p.error("expected `::`");
         }
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs
index 9d31e435cf9..908440b5d05 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/types.rs
@@ -330,15 +330,6 @@ fn bare_dyn_trait_type(p: &mut Parser<'_>) {
     m.complete(p, DYN_TRAIT_TYPE);
 }
 
-// test path_type
-// type A = Foo;
-// type B = ::Foo;
-// type C = self::Foo;
-// type D = super::Foo;
-pub(super) fn path_type(p: &mut Parser<'_>) {
-    path_type_bounds(p, true);
-}
-
 // test macro_call_type
 // type A = foo!();
 // type B = crate::foo!();
@@ -365,6 +356,11 @@ fn path_or_macro_type(p: &mut Parser<'_>, allow_bounds: bool) {
     }
 }
 
+// test path_type
+// type A = Foo;
+// type B = ::Foo;
+// type C = self::Foo;
+// type D = super::Foo;
 pub(super) fn path_type_bounds(p: &mut Parser<'_>, allow_bounds: bool) {
     assert!(paths::is_path_start(p));
     let m = p.start();
diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
index b1727509b13..f534546ea07 100644
--- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
@@ -291,6 +291,7 @@ pub enum SyntaxKind {
     TUPLE_STRUCT_PAT,
     TUPLE_TYPE,
     TYPE_ALIAS,
+    TYPE_ANCHOR,
     TYPE_ARG,
     TYPE_BOUND,
     TYPE_BOUND_LIST,
@@ -463,6 +464,7 @@ impl SyntaxKind {
             | TUPLE_STRUCT_PAT
             | TUPLE_TYPE
             | TYPE_ALIAS
+            | TYPE_ANCHOR
             | TYPE_ARG
             | TYPE_BOUND
             | TYPE_BOUND_LIST
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
index 030d8e0f04d..6ec4192830b 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
+++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
@@ -83,6 +83,10 @@ mod ok {
     #[test]
     fn cast_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/cast_expr.rs"); }
     #[test]
+    fn closure_binder() {
+        run_and_expect_no_errors("test_data/parser/inline/ok/closure_binder.rs");
+    }
+    #[test]
     fn closure_body_underscore_assignment() {
         run_and_expect_no_errors(
             "test_data/parser/inline/ok/closure_body_underscore_assignment.rs",
@@ -872,6 +876,10 @@ mod err {
         run_and_expect_errors("test_data/parser/inline/err/tuple_pat_leading_comma.rs");
     }
     #[test]
+    fn type_bounds_macro_call_recovery() {
+        run_and_expect_errors("test_data/parser/inline/err/type_bounds_macro_call_recovery.rs");
+    }
+    #[test]
     fn type_in_array_recover() {
         run_and_expect_errors("test_data/parser/inline/err/type_in_array_recover.rs");
     }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rast
index f0dbc9b1027..025c12e4c2a 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0024_many_type_parens.rast
@@ -186,13 +186,14 @@ SOURCE_FILE
               TUPLE_EXPR
                 L_PAREN "("
                 CLOSURE_EXPR
-                  FOR_KW "for"
-                  GENERIC_PARAM_LIST
-                    L_ANGLE "<"
-                    LIFETIME_PARAM
-                      LIFETIME
-                        LIFETIME_IDENT "'a"
-                    R_ANGLE ">"
+                  CLOSURE_BINDER
+                    FOR_KW "for"
+                    GENERIC_PARAM_LIST
+                      L_ANGLE "<"
+                      LIFETIME_PARAM
+                        LIFETIME
+                          LIFETIME_IDENT "'a"
+                      R_ANGLE ">"
                 WHITESPACE " "
                 BIN_EXPR
                   BIN_EXPR
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/angled_path_without_qual.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/angled_path_without_qual.rast
index 0529e9750e7..53fbe0b615e 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/angled_path_without_qual.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/angled_path_without_qual.rast
@@ -10,11 +10,12 @@ SOURCE_FILE
     PATH_TYPE
       PATH
         PATH_SEGMENT
-          L_ANGLE "<"
-          TUPLE_TYPE
-            L_PAREN "("
-            R_PAREN ")"
-          R_ANGLE ">"
+          TYPE_ANCHOR
+            L_ANGLE "<"
+            TUPLE_TYPE
+              L_PAREN "("
+              R_PAREN ")"
+            R_ANGLE ">"
     SEMICOLON ";"
   WHITESPACE "\n"
   TYPE_ALIAS
@@ -28,21 +29,22 @@ SOURCE_FILE
     PATH_TYPE
       PATH
         PATH_SEGMENT
-          L_ANGLE "<"
-          PATH_TYPE
-            PATH
-              PATH_SEGMENT
-                NAME_REF
-                  IDENT "A"
-          WHITESPACE " "
-          AS_KW "as"
-          WHITESPACE " "
-          PATH_TYPE
-            PATH
-              PATH_SEGMENT
-                NAME_REF
-                  IDENT "B"
-          R_ANGLE ">"
+          TYPE_ANCHOR
+            L_ANGLE "<"
+            PATH_TYPE
+              PATH
+                PATH_SEGMENT
+                  NAME_REF
+                    IDENT "A"
+            WHITESPACE " "
+            AS_KW "as"
+            WHITESPACE " "
+            PATH_TYPE
+              PATH
+                PATH_SEGMENT
+                  NAME_REF
+                    IDENT "B"
+            R_ANGLE ">"
     SEMICOLON ";"
   WHITESPACE "\n"
 error 13: expected `::`
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_bounds_macro_call_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_bounds_macro_call_recovery.rast
new file mode 100644
index 00000000000..4722beb6192
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_bounds_macro_call_recovery.rast
@@ -0,0 +1,112 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "foo"
+    GENERIC_PARAM_LIST
+      L_ANGLE "<"
+      TYPE_PARAM
+        NAME
+          IDENT "T"
+        COLON ":"
+        WHITESPACE " "
+        TYPE_BOUND_LIST
+          TYPE_BOUND
+            PATH_TYPE
+              PATH
+                PATH_SEGMENT
+                  NAME_REF
+                    IDENT "T"
+            ERROR
+              BANG "!"
+              TOKEN_TREE
+                L_BRACK "["
+                R_BRACK "]"
+      COMMA ","
+      WHITESPACE " "
+      TYPE_PARAM
+        NAME
+          IDENT "T"
+        COLON ":"
+        WHITESPACE " "
+        TYPE_BOUND_LIST
+          TYPE_BOUND
+            PATH_TYPE
+              PATH
+                PATH_SEGMENT
+                  NAME_REF
+                    IDENT "T"
+            ERROR
+              BANG "!"
+      COMMA ","
+      WHITESPACE " "
+      TYPE_PARAM
+        NAME
+          IDENT "T"
+        COLON ":"
+        WHITESPACE " "
+        TYPE_BOUND_LIST
+          TYPE_BOUND
+            PATH_TYPE
+              PATH
+                PATH_SEGMENT
+                  NAME_REF
+                    IDENT "T"
+            ERROR
+              BANG "!"
+              TOKEN_TREE
+                L_CURLY "{"
+                R_CURLY "}"
+      R_ANGLE ">"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    RET_TYPE
+      THIN_ARROW "->"
+      WHITESPACE " "
+      PATH_TYPE
+        PATH
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "Box"
+            GENERIC_ARG_LIST
+              L_ANGLE "<"
+              TYPE_ARG
+                DYN_TRAIT_TYPE
+                  TYPE_BOUND_LIST
+                    TYPE_BOUND
+                      MACRO_TYPE
+                        MACRO_CALL
+                          PATH
+                            PATH_SEGMENT
+                              NAME_REF
+                                IDENT "T"
+                          BANG "!"
+                    WHITESPACE " "
+                    PLUS "+"
+                    WHITESPACE " "
+                    TYPE_BOUND
+                      PATH_TYPE
+                        PATH
+                          PATH_SEGMENT
+                            NAME_REF
+                              IDENT "T"
+                      ERROR
+                        BANG "!"
+                        TOKEN_TREE
+                          L_CURLY "{"
+                          R_CURLY "}"
+              R_ANGLE ">"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        R_CURLY "}"
+  WHITESPACE "\n"
+error 12: unexpected `!` in type path, macro calls are not allowed here
+error 21: unexpected `!` in type path, macro calls are not allowed here
+error 28: unexpected `!` in type path, macro calls are not allowed here
+error 43: expected `{`, `[`, `(`
+error 48: unexpected `!` in type path, macro calls are not allowed here
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_bounds_macro_call_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_bounds_macro_call_recovery.rs
new file mode 100644
index 00000000000..517404fdb0e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/type_bounds_macro_call_recovery.rs
@@ -0,0 +1 @@
+fn foo<T: T![], T: T!, T: T!{}>() -> Box<T! + T!{}> {}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/call_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/call_expr.rast
index 19cc8d5ac7c..7c1d894f7e4 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/call_expr.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/call_expr.rast
@@ -88,13 +88,14 @@ SOURCE_FILE
                   PATH
                     PATH
                       PATH_SEGMENT
-                        L_ANGLE "<"
-                        PATH_TYPE
-                          PATH
-                            PATH_SEGMENT
-                              NAME_REF
-                                IDENT "Foo"
-                        R_ANGLE ">"
+                        TYPE_ANCHOR
+                          L_ANGLE "<"
+                          PATH_TYPE
+                            PATH
+                              PATH_SEGMENT
+                                NAME_REF
+                                  IDENT "Foo"
+                          R_ANGLE ">"
                     COLON2 "::"
                     PATH_SEGMENT
                       NAME_REF
@@ -119,21 +120,22 @@ SOURCE_FILE
                   PATH
                     PATH
                       PATH_SEGMENT
-                        L_ANGLE "<"
-                        PATH_TYPE
-                          PATH
-                            PATH_SEGMENT
-                              NAME_REF
-                                IDENT "Foo"
-                        WHITESPACE " "
-                        AS_KW "as"
-                        WHITESPACE " "
-                        PATH_TYPE
-                          PATH
-                            PATH_SEGMENT
-                              NAME_REF
-                                IDENT "Trait"
-                        R_ANGLE ">"
+                        TYPE_ANCHOR
+                          L_ANGLE "<"
+                          PATH_TYPE
+                            PATH
+                              PATH_SEGMENT
+                                NAME_REF
+                                  IDENT "Foo"
+                          WHITESPACE " "
+                          AS_KW "as"
+                          WHITESPACE " "
+                          PATH_TYPE
+                            PATH
+                              PATH_SEGMENT
+                                NAME_REF
+                                  IDENT "Trait"
+                          R_ANGLE ">"
                     COLON2 "::"
                     PATH_SEGMENT
                       NAME_REF
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/closure_binder.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/closure_binder.rast
new file mode 100644
index 00000000000..c04dbe1ea0a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/closure_binder.rast
@@ -0,0 +1,36 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "main"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE " "
+        EXPR_STMT
+          CLOSURE_EXPR
+            CLOSURE_BINDER
+              FOR_KW "for"
+              GENERIC_PARAM_LIST
+                L_ANGLE "<"
+                LIFETIME_PARAM
+                  LIFETIME
+                    LIFETIME_IDENT "'a"
+                R_ANGLE ">"
+            WHITESPACE " "
+            PARAM_LIST
+              PIPE "|"
+              PIPE "|"
+            WHITESPACE " "
+            TUPLE_EXPR
+              L_PAREN "("
+              R_PAREN ")"
+          SEMICOLON ";"
+        WHITESPACE " "
+        R_CURLY "}"
+  WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/closure_binder.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/closure_binder.rs
new file mode 100644
index 00000000000..a6d8aafb08a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/closure_binder.rs
@@ -0,0 +1 @@
+fn main() { for<'a> || (); }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lambda_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lambda_expr.rast
index c25ad8430d0..ea401d224e6 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lambda_expr.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/lambda_expr.rast
@@ -202,13 +202,14 @@ SOURCE_FILE
         WHITESPACE "\n    "
         EXPR_STMT
           CLOSURE_EXPR
-            FOR_KW "for"
-            GENERIC_PARAM_LIST
-              L_ANGLE "<"
-              LIFETIME_PARAM
-                LIFETIME
-                  LIFETIME_IDENT "'a"
-              R_ANGLE ">"
+            CLOSURE_BINDER
+              FOR_KW "for"
+              GENERIC_PARAM_LIST
+                L_ANGLE "<"
+                LIFETIME_PARAM
+                  LIFETIME
+                    LIFETIME_IDENT "'a"
+                R_ANGLE ">"
             WHITESPACE " "
             PARAM_LIST
               PIPE "|"
@@ -222,13 +223,14 @@ SOURCE_FILE
         WHITESPACE "\n    "
         EXPR_STMT
           CLOSURE_EXPR
-            FOR_KW "for"
-            GENERIC_PARAM_LIST
-              L_ANGLE "<"
-              LIFETIME_PARAM
-                LIFETIME
-                  LIFETIME_IDENT "'a"
-              R_ANGLE ">"
+            CLOSURE_BINDER
+              FOR_KW "for"
+              GENERIC_PARAM_LIST
+                L_ANGLE "<"
+                LIFETIME_PARAM
+                  LIFETIME
+                    LIFETIME_IDENT "'a"
+                R_ANGLE ">"
             WHITESPACE " "
             MOVE_KW "move"
             WHITESPACE " "
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/qual_paths.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/qual_paths.rast
index 8c66cfe599f..10f8a6a7516 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/qual_paths.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/qual_paths.rast
@@ -11,21 +11,22 @@ SOURCE_FILE
       PATH
         PATH
           PATH_SEGMENT
-            L_ANGLE "<"
-            PATH_TYPE
-              PATH
-                PATH_SEGMENT
-                  NAME_REF
-                    IDENT "A"
-            WHITESPACE " "
-            AS_KW "as"
-            WHITESPACE " "
-            PATH_TYPE
-              PATH
-                PATH_SEGMENT
-                  NAME_REF
-                    IDENT "B"
-            R_ANGLE ">"
+            TYPE_ANCHOR
+              L_ANGLE "<"
+              PATH_TYPE
+                PATH
+                  PATH_SEGMENT
+                    NAME_REF
+                      IDENT "A"
+              WHITESPACE " "
+              AS_KW "as"
+              WHITESPACE " "
+              PATH_TYPE
+                PATH
+                  PATH_SEGMENT
+                    NAME_REF
+                      IDENT "B"
+              R_ANGLE ">"
         COLON2 "::"
         PATH_SEGMENT
           NAME_REF
@@ -51,21 +52,22 @@ SOURCE_FILE
               PATH
                 PATH
                   PATH_SEGMENT
-                    L_ANGLE "<"
-                    PATH_TYPE
-                      PATH
-                        PATH_SEGMENT
-                          NAME_REF
-                            IDENT "usize"
-                    WHITESPACE " "
-                    AS_KW "as"
-                    WHITESPACE " "
-                    PATH_TYPE
-                      PATH
-                        PATH_SEGMENT
-                          NAME_REF
-                            IDENT "Default"
-                    R_ANGLE ">"
+                    TYPE_ANCHOR
+                      L_ANGLE "<"
+                      PATH_TYPE
+                        PATH
+                          PATH_SEGMENT
+                            NAME_REF
+                              IDENT "usize"
+                      WHITESPACE " "
+                      AS_KW "as"
+                      WHITESPACE " "
+                      PATH_TYPE
+                        PATH
+                          PATH_SEGMENT
+                            NAME_REF
+                              IDENT "Default"
+                      R_ANGLE ">"
                 COLON2 "::"
                 PATH_SEGMENT
                   NAME_REF
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_path_in_pattern.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_path_in_pattern.rast
index 297f7575ca6..3d27afa5ecd 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_path_in_pattern.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/type_path_in_pattern.rast
@@ -19,10 +19,11 @@ SOURCE_FILE
             PATH
               PATH
                 PATH_SEGMENT
-                  L_ANGLE "<"
-                  INFER_TYPE
-                    UNDERSCORE "_"
-                  R_ANGLE ">"
+                  TYPE_ANCHOR
+                    L_ANGLE "<"
+                    INFER_TYPE
+                      UNDERSCORE "_"
+                    R_ANGLE ">"
               COLON2 "::"
               PATH_SEGMENT
                 NAME_REF
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_clause.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_clause.rast
index a3cbe457e1a..9adfe2caa73 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_clause.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/where_clause.rast
@@ -84,21 +84,22 @@ SOURCE_FILE
           PATH
             PATH
               PATH_SEGMENT
-                L_ANGLE "<"
-                PATH_TYPE
-                  PATH
-                    PATH_SEGMENT
-                      NAME_REF
-                        IDENT "T"
-                WHITESPACE " "
-                AS_KW "as"
-                WHITESPACE " "
-                PATH_TYPE
-                  PATH
-                    PATH_SEGMENT
-                      NAME_REF
-                        IDENT "Iterator"
-                R_ANGLE ">"
+                TYPE_ANCHOR
+                  L_ANGLE "<"
+                  PATH_TYPE
+                    PATH
+                      PATH_SEGMENT
+                        NAME_REF
+                          IDENT "T"
+                  WHITESPACE " "
+                  AS_KW "as"
+                  WHITESPACE " "
+                  PATH_TYPE
+                    PATH
+                      PATH_SEGMENT
+                        NAME_REF
+                          IDENT "Iterator"
+                  R_ANGLE ">"
             COLON2 "::"
             PATH_SEGMENT
               NAME_REF
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0036_fully_qualified.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0036_fully_qualified.rast
index 9382020e2f6..2fecb1cc47d 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0036_fully_qualified.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0036_fully_qualified.rast
@@ -45,21 +45,22 @@ SOURCE_FILE
           PATH
             PATH
               PATH_SEGMENT
-                L_ANGLE "<"
-                PATH_TYPE
-                  PATH
-                    PATH_SEGMENT
-                      NAME_REF
-                        IDENT "S"
-                WHITESPACE " "
-                AS_KW "as"
-                WHITESPACE " "
-                PATH_TYPE
-                  PATH
-                    PATH_SEGMENT
-                      NAME_REF
-                        IDENT "Iterator"
-                R_ANGLE ">"
+                TYPE_ANCHOR
+                  L_ANGLE "<"
+                  PATH_TYPE
+                    PATH
+                      PATH_SEGMENT
+                        NAME_REF
+                          IDENT "S"
+                  WHITESPACE " "
+                  AS_KW "as"
+                  WHITESPACE " "
+                  PATH_TYPE
+                    PATH
+                      PATH_SEGMENT
+                        NAME_REF
+                          IDENT "Iterator"
+                  R_ANGLE ">"
             COLON2 "::"
             PATH_SEGMENT
               NAME_REF
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0042_ufcs_call_list.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0042_ufcs_call_list.rast
index a536b0e881f..d1d1ffacf0d 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0042_ufcs_call_list.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0042_ufcs_call_list.rast
@@ -107,13 +107,14 @@ SOURCE_FILE
                 PATH
                   PATH
                     PATH_SEGMENT
-                      L_ANGLE "<"
-                      PATH_TYPE
-                        PATH
-                          PATH_SEGMENT
-                            NAME_REF
-                              IDENT "Foo"
-                      R_ANGLE ">"
+                      TYPE_ANCHOR
+                        L_ANGLE "<"
+                        PATH_TYPE
+                          PATH
+                            PATH_SEGMENT
+                              NAME_REF
+                                IDENT "Foo"
+                        R_ANGLE ">"
                   COLON2 "::"
                   PATH_SEGMENT
                     NAME_REF
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast
index cd3b21ae94f..8bf1090f9cf 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/ok/0067_where_for_pred.rast
@@ -288,26 +288,27 @@ SOURCE_FILE
           PATH
             PATH
               PATH_SEGMENT
-                L_ANGLE "<"
-                REF_TYPE
-                  AMP "&"
-                  LIFETIME
-                    LIFETIME_IDENT "'a"
+                TYPE_ANCHOR
+                  L_ANGLE "<"
+                  REF_TYPE
+                    AMP "&"
+                    LIFETIME
+                      LIFETIME_IDENT "'a"
+                    WHITESPACE " "
+                    PATH_TYPE
+                      PATH
+                        PATH_SEGMENT
+                          NAME_REF
+                            IDENT "T"
+                  WHITESPACE " "
+                  AS_KW "as"
                   WHITESPACE " "
                   PATH_TYPE
                     PATH
                       PATH_SEGMENT
                         NAME_REF
-                          IDENT "T"
-                WHITESPACE " "
-                AS_KW "as"
-                WHITESPACE " "
-                PATH_TYPE
-                  PATH
-                    PATH_SEGMENT
-                      NAME_REF
-                        IDENT "Baz"
-                R_ANGLE ">"
+                          IDENT "Baz"
+                  R_ANGLE ">"
             COLON2 "::"
             PATH_SEGMENT
               NAME_REF
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs
index 11dbd920091..ad285990334 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs
@@ -10,6 +10,7 @@
 
 use std::fmt;
 
+use intern::Symbol;
 use proc_macro::bridge;
 
 mod token_stream;
@@ -112,3 +113,135 @@ fn literal_kind_to_internal(kind: bridge::LitKind) -> tt::LitKind {
         bridge::LitKind::ErrWithGuar => tt::LitKind::Err(()),
     }
 }
+
+pub(super) fn literal_from_str<Span: Copy>(
+    s: &str,
+    span: Span,
+) -> Result<bridge::Literal<Span, Symbol>, ()> {
+    use proc_macro::bridge::LitKind;
+    use rustc_lexer::{LiteralKind, Token, TokenKind};
+
+    let mut tokens = rustc_lexer::tokenize(s);
+    let minus_or_lit = tokens.next().unwrap_or(Token { kind: TokenKind::Eof, len: 0 });
+
+    let lit = if minus_or_lit.kind == TokenKind::Minus {
+        let lit = tokens.next().ok_or(())?;
+        if !matches!(
+            lit.kind,
+            TokenKind::Literal { kind: LiteralKind::Int { .. } | LiteralKind::Float { .. }, .. }
+        ) {
+            return Err(());
+        }
+        lit
+    } else {
+        minus_or_lit
+    };
+
+    if tokens.next().is_some() {
+        return Err(());
+    }
+
+    let TokenKind::Literal { kind, suffix_start } = lit.kind else { return Err(()) };
+    let (kind, start_offset, end_offset) = match kind {
+        LiteralKind::Int { .. } => (LitKind::Integer, 0, 0),
+        LiteralKind::Float { .. } => (LitKind::Float, 0, 0),
+        LiteralKind::Char { terminated } => (LitKind::Char, 1, terminated as usize),
+        LiteralKind::Byte { terminated } => (LitKind::Byte, 2, terminated as usize),
+        LiteralKind::Str { terminated } => (LitKind::Str, 1, terminated as usize),
+        LiteralKind::ByteStr { terminated } => (LitKind::ByteStr, 2, terminated as usize),
+        LiteralKind::CStr { terminated } => (LitKind::CStr, 2, terminated as usize),
+        LiteralKind::RawStr { n_hashes } => (
+            LitKind::StrRaw(n_hashes.unwrap_or_default()),
+            2 + n_hashes.unwrap_or_default() as usize,
+            1 + n_hashes.unwrap_or_default() as usize,
+        ),
+        LiteralKind::RawByteStr { n_hashes } => (
+            LitKind::ByteStrRaw(n_hashes.unwrap_or_default()),
+            3 + n_hashes.unwrap_or_default() as usize,
+            1 + n_hashes.unwrap_or_default() as usize,
+        ),
+        LiteralKind::RawCStr { n_hashes } => (
+            LitKind::CStrRaw(n_hashes.unwrap_or_default()),
+            3 + n_hashes.unwrap_or_default() as usize,
+            1 + n_hashes.unwrap_or_default() as usize,
+        ),
+    };
+
+    let (lit, suffix) = s.split_at(suffix_start as usize);
+    let lit = &lit[start_offset..lit.len() - end_offset];
+    let suffix = match suffix {
+        "" | "_" => None,
+        suffix => Some(Symbol::intern(suffix)),
+    };
+
+    Ok(bridge::Literal { kind, symbol: Symbol::intern(lit), suffix, span })
+}
+
+pub(super) fn from_token_tree<Span: Copy>(
+    tree: bridge::TokenTree<TokenStream<Span>, Span, Symbol>,
+) -> TokenStream<Span> {
+    match tree {
+        bridge::TokenTree::Group(group) => {
+            let group = TopSubtree::from_bridge(group);
+            TokenStream { token_trees: group.0 }
+        }
+
+        bridge::TokenTree::Ident(ident) => {
+            let text = ident.sym;
+            let ident: tt::Ident<Span> = tt::Ident {
+                sym: text,
+                span: ident.span,
+                is_raw: if ident.is_raw { tt::IdentIsRaw::Yes } else { tt::IdentIsRaw::No },
+            };
+            let leaf = tt::Leaf::from(ident);
+            let tree = tt::TokenTree::from(leaf);
+            TokenStream { token_trees: vec![tree] }
+        }
+
+        bridge::TokenTree::Literal(literal) => {
+            let token_trees =
+                if let Some((_minus, symbol)) = literal.symbol.as_str().split_once('-') {
+                    let punct = tt::Punct {
+                        spacing: tt::Spacing::Alone,
+                        span: literal.span,
+                        char: '-' as char,
+                    };
+                    let leaf: tt::Leaf<Span> = tt::Leaf::from(punct);
+                    let minus_tree = tt::TokenTree::from(leaf);
+
+                    let literal = tt::Literal {
+                        symbol: Symbol::intern(symbol),
+                        suffix: literal.suffix,
+                        span: literal.span,
+                        kind: literal_kind_to_internal(literal.kind),
+                    };
+                    let leaf: tt::Leaf<Span> = tt::Leaf::from(literal);
+                    let tree = tt::TokenTree::from(leaf);
+                    vec![minus_tree, tree]
+                } else {
+                    let literal = tt::Literal {
+                        symbol: literal.symbol,
+                        suffix: literal.suffix,
+                        span: literal.span,
+                        kind: literal_kind_to_internal(literal.kind),
+                    };
+
+                    let leaf: tt::Leaf<Span> = tt::Leaf::from(literal);
+                    let tree = tt::TokenTree::from(leaf);
+                    vec![tree]
+                };
+            TokenStream { token_trees }
+        }
+
+        bridge::TokenTree::Punct(p) => {
+            let punct = tt::Punct {
+                char: p.ch as char,
+                spacing: if p.joint { tt::Spacing::Joint } else { tt::Spacing::Alone },
+                span: p.span,
+            };
+            let leaf = tt::Leaf::from(punct);
+            let tree = tt::TokenTree::from(leaf);
+            TokenStream { token_trees: vec![tree] }
+        }
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
index e0c6e68f803..5d1271ba81e 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
@@ -14,16 +14,7 @@ use proc_macro::bridge::{self, server};
 use span::{FIXUP_ERASED_FILE_AST_ID_MARKER, Span};
 use tt::{TextRange, TextSize};
 
-use crate::server_impl::{TopSubtree, literal_kind_to_internal, token_stream::TokenStreamBuilder};
-mod tt {
-    pub use tt::*;
-
-    pub type TokenTree = ::tt::TokenTree<super::Span>;
-    pub type Leaf = ::tt::Leaf<super::Span>;
-    pub type Literal = ::tt::Literal<super::Span>;
-    pub type Punct = ::tt::Punct<super::Span>;
-    pub type Ident = ::tt::Ident<super::Span>;
-}
+use crate::server_impl::{from_token_tree, literal_from_str, token_stream::TokenStreamBuilder};
 
 type TokenStream = crate::server_impl::TokenStream<Span>;
 
@@ -62,66 +53,7 @@ impl server::FreeFunctions for RaSpanServer {
         &mut self,
         s: &str,
     ) -> Result<bridge::Literal<Self::Span, Self::Symbol>, ()> {
-        use proc_macro::bridge::LitKind;
-        use rustc_lexer::{LiteralKind, Token, TokenKind};
-
-        let mut tokens = rustc_lexer::tokenize(s);
-        let minus_or_lit = tokens.next().unwrap_or(Token { kind: TokenKind::Eof, len: 0 });
-
-        let lit = if minus_or_lit.kind == TokenKind::Minus {
-            let lit = tokens.next().ok_or(())?;
-            if !matches!(
-                lit.kind,
-                TokenKind::Literal {
-                    kind: LiteralKind::Int { .. } | LiteralKind::Float { .. },
-                    ..
-                }
-            ) {
-                return Err(());
-            }
-            lit
-        } else {
-            minus_or_lit
-        };
-
-        if tokens.next().is_some() {
-            return Err(());
-        }
-
-        let TokenKind::Literal { kind, suffix_start } = lit.kind else { return Err(()) };
-        let (kind, start_offset, end_offset) = match kind {
-            LiteralKind::Int { .. } => (LitKind::Integer, 0, 0),
-            LiteralKind::Float { .. } => (LitKind::Float, 0, 0),
-            LiteralKind::Char { terminated } => (LitKind::Char, 1, terminated as usize),
-            LiteralKind::Byte { terminated } => (LitKind::Byte, 2, terminated as usize),
-            LiteralKind::Str { terminated } => (LitKind::Str, 1, terminated as usize),
-            LiteralKind::ByteStr { terminated } => (LitKind::ByteStr, 2, terminated as usize),
-            LiteralKind::CStr { terminated } => (LitKind::CStr, 2, terminated as usize),
-            LiteralKind::RawStr { n_hashes } => (
-                LitKind::StrRaw(n_hashes.unwrap_or_default()),
-                2 + n_hashes.unwrap_or_default() as usize,
-                1 + n_hashes.unwrap_or_default() as usize,
-            ),
-            LiteralKind::RawByteStr { n_hashes } => (
-                LitKind::ByteStrRaw(n_hashes.unwrap_or_default()),
-                3 + n_hashes.unwrap_or_default() as usize,
-                1 + n_hashes.unwrap_or_default() as usize,
-            ),
-            LiteralKind::RawCStr { n_hashes } => (
-                LitKind::CStrRaw(n_hashes.unwrap_or_default()),
-                3 + n_hashes.unwrap_or_default() as usize,
-                1 + n_hashes.unwrap_or_default() as usize,
-            ),
-        };
-
-        let (lit, suffix) = s.split_at(suffix_start as usize);
-        let lit = &lit[start_offset..lit.len() - end_offset];
-        let suffix = match suffix {
-            "" | "_" => None,
-            suffix => Some(Symbol::intern(suffix)),
-        };
-
-        Ok(bridge::Literal { kind, symbol: Symbol::intern(lit), suffix, span: self.call_site })
+        literal_from_str(s, self.call_site)
     }
 
     fn emit_diagnostic(&mut self, _: bridge::Diagnostic<Self::Span>) {
@@ -149,70 +81,7 @@ impl server::TokenStream for RaSpanServer {
         &mut self,
         tree: bridge::TokenTree<Self::TokenStream, Self::Span, Self::Symbol>,
     ) -> Self::TokenStream {
-        match tree {
-            bridge::TokenTree::Group(group) => {
-                let group = TopSubtree::from_bridge(group);
-                TokenStream { token_trees: group.0 }
-            }
-
-            bridge::TokenTree::Ident(ident) => {
-                let text = ident.sym;
-                let ident: tt::Ident = tt::Ident {
-                    sym: text,
-                    span: ident.span,
-                    is_raw: if ident.is_raw { tt::IdentIsRaw::Yes } else { tt::IdentIsRaw::No },
-                };
-                let leaf = tt::Leaf::from(ident);
-                let tree = tt::TokenTree::from(leaf);
-                TokenStream { token_trees: vec![tree] }
-            }
-
-            bridge::TokenTree::Literal(literal) => {
-                let token_trees =
-                    if let Some((_minus, symbol)) = literal.symbol.as_str().split_once('-') {
-                        let punct = tt::Punct {
-                            spacing: tt::Spacing::Alone,
-                            span: literal.span,
-                            char: '-' as char,
-                        };
-                        let leaf: tt::Leaf = tt::Leaf::from(punct);
-                        let minus_tree = tt::TokenTree::from(leaf);
-
-                        let literal = tt::Literal {
-                            symbol: Symbol::intern(symbol),
-                            suffix: literal.suffix,
-                            span: literal.span,
-                            kind: literal_kind_to_internal(literal.kind),
-                        };
-                        let leaf: tt::Leaf = tt::Leaf::from(literal);
-                        let tree = tt::TokenTree::from(leaf);
-                        vec![minus_tree, tree]
-                    } else {
-                        let literal = tt::Literal {
-                            symbol: literal.symbol,
-                            suffix: literal.suffix,
-                            span: literal.span,
-                            kind: literal_kind_to_internal(literal.kind),
-                        };
-
-                        let leaf: tt::Leaf = tt::Leaf::from(literal);
-                        let tree = tt::TokenTree::from(leaf);
-                        vec![tree]
-                    };
-                TokenStream { token_trees }
-            }
-
-            bridge::TokenTree::Punct(p) => {
-                let punct = tt::Punct {
-                    char: p.ch as char,
-                    spacing: if p.joint { tt::Spacing::Joint } else { tt::Spacing::Alone },
-                    span: p.span,
-                };
-                let leaf = tt::Leaf::from(punct);
-                let tree = tt::TokenTree::from(leaf);
-                TokenStream { token_trees: vec![tree] }
-            }
-        }
+        from_token_tree(tree)
     }
 
     fn expand_expr(&mut self, self_: &Self::TokenStream) -> Result<Self::TokenStream, ()> {
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
index d55b269f868..b493b325e83 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
@@ -5,23 +5,9 @@ use std::ops::{Bound, Range};
 use intern::Symbol;
 use proc_macro::bridge::{self, server};
 
-use crate::server_impl::{TopSubtree, literal_kind_to_internal, token_stream::TokenStreamBuilder};
-mod tt {
-    pub use span::TokenId;
+use crate::server_impl::{from_token_tree, literal_from_str, token_stream::TokenStreamBuilder};
 
-    pub use tt::*;
-
-    pub type TokenTree = ::tt::TokenTree<TokenId>;
-    pub type Leaf = ::tt::Leaf<TokenId>;
-    pub type Literal = ::tt::Literal<TokenId>;
-    pub type Punct = ::tt::Punct<TokenId>;
-    pub type Ident = ::tt::Ident<TokenId>;
-}
-type TokenTree = tt::TokenTree;
-type Punct = tt::Punct;
-type Spacing = tt::Spacing;
-type Literal = tt::Literal;
-type Span = tt::TokenId;
+type Span = span::TokenId;
 type TokenStream = crate::server_impl::TokenStream<Span>;
 
 pub struct FreeFunctions;
@@ -49,67 +35,7 @@ impl server::FreeFunctions for TokenIdServer {
         &mut self,
         s: &str,
     ) -> Result<bridge::Literal<Self::Span, Self::Symbol>, ()> {
-        use proc_macro::bridge::LitKind;
-        use rustc_lexer::{LiteralKind, Token, TokenKind};
-
-        let mut tokens = rustc_lexer::tokenize(s);
-        let minus_or_lit = tokens.next().unwrap_or(Token { kind: TokenKind::Eof, len: 0 });
-
-        let lit = if minus_or_lit.kind == TokenKind::Minus {
-            let lit = tokens.next().ok_or(())?;
-            if !matches!(
-                lit.kind,
-                TokenKind::Literal {
-                    kind: LiteralKind::Int { .. } | LiteralKind::Float { .. },
-                    ..
-                }
-            ) {
-                return Err(());
-            }
-            lit
-        } else {
-            minus_or_lit
-        };
-
-        if tokens.next().is_some() {
-            return Err(());
-        }
-
-        let TokenKind::Literal { kind, suffix_start } = lit.kind else { return Err(()) };
-
-        let (kind, start_offset, end_offset) = match kind {
-            LiteralKind::Int { .. } => (LitKind::Integer, 0, 0),
-            LiteralKind::Float { .. } => (LitKind::Float, 0, 0),
-            LiteralKind::Char { terminated } => (LitKind::Char, 1, terminated as usize),
-            LiteralKind::Byte { terminated } => (LitKind::Byte, 2, terminated as usize),
-            LiteralKind::Str { terminated } => (LitKind::Str, 1, terminated as usize),
-            LiteralKind::ByteStr { terminated } => (LitKind::ByteStr, 2, terminated as usize),
-            LiteralKind::CStr { terminated } => (LitKind::CStr, 2, terminated as usize),
-            LiteralKind::RawStr { n_hashes } => (
-                LitKind::StrRaw(n_hashes.unwrap_or_default()),
-                2 + n_hashes.unwrap_or_default() as usize,
-                1 + n_hashes.unwrap_or_default() as usize,
-            ),
-            LiteralKind::RawByteStr { n_hashes } => (
-                LitKind::ByteStrRaw(n_hashes.unwrap_or_default()),
-                3 + n_hashes.unwrap_or_default() as usize,
-                1 + n_hashes.unwrap_or_default() as usize,
-            ),
-            LiteralKind::RawCStr { n_hashes } => (
-                LitKind::CStrRaw(n_hashes.unwrap_or_default()),
-                3 + n_hashes.unwrap_or_default() as usize,
-                1 + n_hashes.unwrap_or_default() as usize,
-            ),
-        };
-
-        let (lit, suffix) = s.split_at(suffix_start as usize);
-        let lit = &lit[start_offset..lit.len() - end_offset];
-        let suffix = match suffix {
-            "" | "_" => None,
-            suffix => Some(Symbol::intern(suffix)),
-        };
-
-        Ok(bridge::Literal { kind, symbol: Symbol::intern(lit), suffix, span: self.call_site })
+        literal_from_str(s, self.call_site)
     }
 
     fn emit_diagnostic(&mut self, _: bridge::Diagnostic<Self::Span>) {}
@@ -135,69 +61,7 @@ impl server::TokenStream for TokenIdServer {
         &mut self,
         tree: bridge::TokenTree<Self::TokenStream, Self::Span, Self::Symbol>,
     ) -> Self::TokenStream {
-        match tree {
-            bridge::TokenTree::Group(group) => {
-                let group = TopSubtree::from_bridge(group);
-                TokenStream { token_trees: group.0 }
-            }
-
-            bridge::TokenTree::Ident(ident) => {
-                let ident: tt::Ident = tt::Ident {
-                    sym: ident.sym,
-                    span: ident.span,
-                    is_raw: if ident.is_raw { tt::IdentIsRaw::Yes } else { tt::IdentIsRaw::No },
-                };
-                let leaf = tt::Leaf::from(ident);
-                let tree = TokenTree::from(leaf);
-                TokenStream { token_trees: vec![tree] }
-            }
-
-            bridge::TokenTree::Literal(literal) => {
-                let token_trees =
-                    if let Some((_minus, symbol)) = literal.symbol.as_str().split_once('-') {
-                        let punct = tt::Punct {
-                            spacing: tt::Spacing::Alone,
-                            span: literal.span,
-                            char: '-' as char,
-                        };
-                        let leaf: tt::Leaf = tt::Leaf::from(punct);
-                        let minus_tree = tt::TokenTree::from(leaf);
-
-                        let literal = Literal {
-                            symbol: Symbol::intern(symbol),
-                            suffix: literal.suffix,
-                            span: literal.span,
-                            kind: literal_kind_to_internal(literal.kind),
-                        };
-                        let leaf: tt::Leaf = tt::Leaf::from(literal);
-                        let tree = tt::TokenTree::from(leaf);
-                        vec![minus_tree, tree]
-                    } else {
-                        let literal = Literal {
-                            symbol: literal.symbol,
-                            suffix: literal.suffix,
-                            span: literal.span,
-                            kind: literal_kind_to_internal(literal.kind),
-                        };
-
-                        let leaf: tt::Leaf = tt::Leaf::from(literal);
-                        let tree = tt::TokenTree::from(leaf);
-                        vec![tree]
-                    };
-                TokenStream { token_trees }
-            }
-
-            bridge::TokenTree::Punct(p) => {
-                let punct = Punct {
-                    char: p.ch as char,
-                    spacing: if p.joint { Spacing::Joint } else { Spacing::Alone },
-                    span: p.span,
-                };
-                let leaf = tt::Leaf::from(punct);
-                let tree = TokenTree::from(leaf);
-                TokenStream { token_trees: vec![tree] }
-            }
-        }
+        from_token_tree(tree)
     }
 
     fn expand_expr(&mut self, self_: &Self::TokenStream) -> Result<Self::TokenStream, ()> {
@@ -337,6 +201,8 @@ impl server::Server for TokenIdServer {
 
 #[cfg(test)]
 mod tests {
+    use span::TokenId;
+
     use super::*;
 
     #[test]
@@ -345,18 +211,18 @@ mod tests {
             token_trees: vec![
                 tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
                     sym: Symbol::intern("struct"),
-                    span: tt::TokenId(0),
+                    span: TokenId(0),
                     is_raw: tt::IdentIsRaw::No,
                 })),
                 tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
                     sym: Symbol::intern("T"),
-                    span: tt::TokenId(0),
+                    span: TokenId(0),
                     is_raw: tt::IdentIsRaw::No,
                 })),
                 tt::TokenTree::Subtree(tt::Subtree {
                     delimiter: tt::Delimiter {
-                        open: tt::TokenId(0),
-                        close: tt::TokenId(0),
+                        open: TokenId(0),
+                        close: TokenId(0),
                         kind: tt::DelimiterKind::Brace,
                     },
                     len: 0,
@@ -372,8 +238,8 @@ mod tests {
         let subtree_paren_a = vec![
             tt::TokenTree::Subtree(tt::Subtree {
                 delimiter: tt::Delimiter {
-                    open: tt::TokenId(0),
-                    close: tt::TokenId(0),
+                    open: TokenId(0),
+                    close: TokenId(0),
                     kind: tt::DelimiterKind::Parenthesis,
                 },
                 len: 1,
@@ -381,24 +247,24 @@ mod tests {
             tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
                 is_raw: tt::IdentIsRaw::No,
                 sym: Symbol::intern("a"),
-                span: tt::TokenId(0),
+                span: TokenId(0),
             })),
         ];
 
-        let t1 = TokenStream::from_str("(a)", tt::TokenId(0)).unwrap();
+        let t1 = TokenStream::from_str("(a)", TokenId(0)).unwrap();
         assert_eq!(t1.token_trees.len(), 2);
         assert!(t1.token_trees[0..2] == subtree_paren_a);
 
-        let t2 = TokenStream::from_str("(a);", tt::TokenId(0)).unwrap();
+        let t2 = TokenStream::from_str("(a);", TokenId(0)).unwrap();
         assert_eq!(t2.token_trees.len(), 3);
         assert!(t2.token_trees[0..2] == subtree_paren_a);
 
-        let underscore = TokenStream::from_str("_", tt::TokenId(0)).unwrap();
+        let underscore = TokenStream::from_str("_", TokenId(0)).unwrap();
         assert!(
             underscore.token_trees[0]
                 == tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
                     sym: Symbol::intern("_"),
-                    span: tt::TokenId(0),
+                    span: TokenId(0),
                     is_raw: tt::IdentIsRaw::No,
                 }))
         );
diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
index 6e730b1aea2..bb02284a513 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
@@ -431,12 +431,6 @@ impl CargoWorkspace {
                 .ok_or(cargo_metadata::Error::NoJson)?;
             Ok((cargo_metadata::MetadataCommand::parse(stdout)?, None))
         })()
-        .map(|(metadata, error)| {
-            (
-                metadata,
-                error.map(|e| e.context(format!("Failed to run `{:?}`", meta.cargo_command()))),
-            )
-        })
         .with_context(|| format!("Failed to run `{:?}`", meta.cargo_command()))
     }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index d1ca8c1a91a..5cbea9c2b3d 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -1192,7 +1192,7 @@ impl ConfigChange {
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub enum LinkedProject {
     ProjectManifest(ProjectManifest),
-    InlineJsonProject(ProjectJson),
+    InlineProjectJson(ProjectJson),
 }
 
 impl From<ProjectManifest> for LinkedProject {
@@ -1203,7 +1203,7 @@ impl From<ProjectManifest> for LinkedProject {
 
 impl From<ProjectJson> for LinkedProject {
     fn from(v: ProjectJson) -> Self {
-        LinkedProject::InlineJsonProject(v)
+        LinkedProject::InlineProjectJson(v)
     }
 }
 
@@ -1597,6 +1597,16 @@ impl Config {
             term_search_borrowck: self.assist_termSearch_borrowcheck(source_root).to_owned(),
         }
     }
+
+    pub fn diagnostic_fixes(&self, source_root: Option<SourceRootId>) -> DiagnosticsConfig {
+        // We always want to show quickfixes for diagnostics, even when diagnostics/experimental diagnostics are disabled.
+        DiagnosticsConfig {
+            enabled: true,
+            disable_experimental: false,
+            ..self.diagnostics(source_root)
+        }
+    }
+
     pub fn expand_proc_attr_macros(&self) -> bool {
         self.procMacro_enable().to_owned() && self.procMacro_attributes_enable().to_owned()
     }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
index 69983a67626..6d46ce68ed4 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
@@ -1439,7 +1439,7 @@ pub(crate) fn handle_code_action(
     };
     let assists = snap.analysis.assists_with_fixes(
         &assists_config,
-        &snap.config.diagnostics(Some(source_root)),
+        &snap.config.diagnostic_fixes(Some(source_root)),
         resolve,
         frange,
     )?;
@@ -1530,7 +1530,7 @@ pub(crate) fn handle_code_action_resolve(
 
     let assists = snap.analysis.assists_with_fixes(
         &assists_config,
-        &snap.config.diagnostics(Some(source_root)),
+        &snap.config.diagnostic_fixes(Some(source_root)),
         AssistResolveStrategy::Single(assist_resolve),
         frange,
     )?;
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs
index 673eaa5952f..5bea7084fdb 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs
@@ -108,8 +108,7 @@ impl GlobalState {
     /// edge users from being upset!
     pub(crate) fn poke_rust_analyzer_developer(&mut self, message: String) {
         let from_source_build = option_env!("POKE_RA_DEVS").is_some();
-        let profiling_enabled = std::env::var("RA_PROFILE").is_ok();
-        if from_source_build || profiling_enabled {
+        if from_source_build {
             self.show_and_log_error(message, None);
         }
     }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index ae9e3e99874..4677880daaf 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -292,7 +292,7 @@ impl GlobalState {
 
                 if let (Some(_command), Some(path)) = (&discover_command, &path) {
                     let build = linked_projects.iter().find_map(|project| match project {
-                        LinkedProject::InlineJsonProject(it) => it.crate_by_buildfile(path),
+                        LinkedProject::InlineProjectJson(it) => it.crate_by_buildfile(path),
                         _ => None,
                     });
 
@@ -318,7 +318,7 @@ impl GlobalState {
                                 &progress,
                             )
                         }
-                        LinkedProject::InlineJsonProject(it) => {
+                        LinkedProject::InlineProjectJson(it) => {
                             let workspace = project_model::ProjectWorkspace::load_inline(
                                 it.clone(),
                                 &cargo_config,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
index f6bcb5642c3..59073af983b 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
@@ -975,10 +975,6 @@ version = \"0.0.0\"
 }
 
 fn out_dirs_check_impl(root_contains_symlink: bool) {
-    if skip_slow_tests() {
-        return;
-    }
-
     let mut server = Project::with_fixture(
         r###"
 //- /Cargo.toml
@@ -1130,12 +1126,18 @@ fn main() {
 
 #[test]
 fn out_dirs_check() {
+    if skip_slow_tests() {
+        return;
+    }
     out_dirs_check_impl(false);
 }
 
 #[test]
 #[cfg(not(windows))] // windows requires elevated permissions to create symlinks
 fn root_contains_symlink_out_dirs_check() {
+    if skip_slow_tests() {
+        return;
+    }
     out_dirs_check_impl(true);
 }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
index 485f32281dd..cac7efd84aa 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/ratoml.rs
@@ -439,6 +439,7 @@ assist.emitMustUse = true"#,
 }
 
 #[test]
+#[ignore = "flaky test that tends to hang"]
 fn ratoml_inherit_config_from_ws_root() {
     if skip_slow_tests() {
         return;
diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram
index 10abca7d35d..c81da06682e 100644
--- a/src/tools/rust-analyzer/crates/syntax/rust.ungram
+++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram
@@ -39,7 +39,10 @@ PathSegment =
 | NameRef GenericArgList?
 | NameRef ParenthesizedArgList RetType?
 | NameRef ReturnTypeSyntax
-| '<' Type ('as' PathType)? '>'
+| TypeAnchor
+
+TypeAnchor =
+  '<' Type ('as' PathType)? '>'
 
 ReturnTypeSyntax =
   '(' '..' ')'
@@ -98,7 +101,7 @@ WhereClause =
   'where' predicates:(WherePred (',' WherePred)* ','?)
 
 WherePred =
-  ('for' GenericParamList)?  (Lifetime | Type) ':' TypeBoundList?
+  ('for' GenericParamList)? (Lifetime | Type) ':' TypeBoundList?
 
 
 //*************************//
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
index cd9f4dba890..04c7e8a578c 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
@@ -1232,21 +1232,13 @@ impl PathSegment {
         support::child(&self.syntax)
     }
     #[inline]
-    pub fn path_type(&self) -> Option<PathType> { support::child(&self.syntax) }
-    #[inline]
     pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) }
     #[inline]
     pub fn return_type_syntax(&self) -> Option<ReturnTypeSyntax> { support::child(&self.syntax) }
     #[inline]
-    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    pub fn type_anchor(&self) -> Option<TypeAnchor> { support::child(&self.syntax) }
     #[inline]
     pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
-    #[inline]
-    pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
-    #[inline]
-    pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
-    #[inline]
-    pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) }
 }
 pub struct PathType {
     pub(crate) syntax: SyntaxNode,
@@ -1739,6 +1731,21 @@ impl TypeAlias {
     #[inline]
     pub fn type_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![type]) }
 }
+pub struct TypeAnchor {
+    pub(crate) syntax: SyntaxNode,
+}
+impl TypeAnchor {
+    #[inline]
+    pub fn path_type(&self) -> Option<PathType> { support::child(&self.syntax) }
+    #[inline]
+    pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
+    #[inline]
+    pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
+    #[inline]
+    pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
+    #[inline]
+    pub fn as_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![as]) }
+}
 pub struct TypeArg {
     pub(crate) syntax: SyntaxNode,
 }
@@ -7108,6 +7115,42 @@ impl fmt::Debug for TypeAlias {
         f.debug_struct("TypeAlias").field("syntax", &self.syntax).finish()
     }
 }
+impl AstNode for TypeAnchor {
+    #[inline]
+    fn kind() -> SyntaxKind
+    where
+        Self: Sized,
+    {
+        TYPE_ANCHOR
+    }
+    #[inline]
+    fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_ANCHOR }
+    #[inline]
+    fn cast(syntax: SyntaxNode) -> Option<Self> {
+        if Self::can_cast(syntax.kind()) {
+            Some(Self { syntax })
+        } else {
+            None
+        }
+    }
+    #[inline]
+    fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
+impl hash::Hash for TypeAnchor {
+    fn hash<H: hash::Hasher>(&self, state: &mut H) { self.syntax.hash(state); }
+}
+impl Eq for TypeAnchor {}
+impl PartialEq for TypeAnchor {
+    fn eq(&self, other: &Self) -> bool { self.syntax == other.syntax }
+}
+impl Clone for TypeAnchor {
+    fn clone(&self) -> Self { Self { syntax: self.syntax.clone() } }
+}
+impl fmt::Debug for TypeAnchor {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("TypeAnchor").field("syntax", &self.syntax).finish()
+    }
+}
 impl AstNode for TypeArg {
     #[inline]
     fn kind() -> SyntaxKind
@@ -10624,6 +10667,11 @@ impl std::fmt::Display for TypeAlias {
         std::fmt::Display::fmt(self.syntax(), f)
     }
 }
+impl std::fmt::Display for TypeAnchor {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        std::fmt::Display::fmt(self.syntax(), f)
+    }
+}
 impl std::fmt::Display for TypeArg {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         std::fmt::Display::fmt(self.syntax(), f)
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
index b9ccd34cff0..dcf853427e5 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
@@ -276,18 +276,15 @@ impl ast::PathSegment {
                 _ => PathSegmentKind::Name(name_ref),
             }
         } else {
-            match self.syntax().first_child_or_token()?.kind() {
-                T![<] => {
-                    // <T> or <T as Trait>
-                    // T is any TypeRef, Trait has to be a PathType
-                    let mut type_refs =
-                        self.syntax().children().filter(|node| ast::Type::can_cast(node.kind()));
-                    let type_ref = type_refs.next().and_then(ast::Type::cast);
-                    let trait_ref = type_refs.next().and_then(ast::PathType::cast);
-                    PathSegmentKind::Type { type_ref, trait_ref }
-                }
-                _ => return None,
-            }
+            let anchor = self.type_anchor()?;
+            // FIXME: Move this over to `ast::TypeAnchor`
+            // <T> or <T as Trait>
+            // T is any TypeRef, Trait has to be a PathType
+            let mut type_refs =
+                anchor.syntax().children().filter(|node| ast::Type::can_cast(node.kind()));
+            let type_ref = type_refs.next().and_then(ast::Type::cast);
+            let trait_ref = type_refs.next().and_then(ast::PathType::cast);
+            PathSegmentKind::Type { type_ref, trait_ref }
         };
         Some(res)
     }
@@ -473,7 +470,7 @@ impl ast::Impl {
 // [#15778](https://github.com/rust-lang/rust-analyzer/issues/15778)
 impl ast::PathSegment {
     pub fn qualifying_trait(&self) -> Option<ast::PathType> {
-        let mut path_types = support::children(self.syntax());
+        let mut path_types = support::children(self.type_anchor()?.syntax());
         let first = path_types.next()?;
         path_types.next().or(Some(first))
     }
diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
index 96e1301f227..8eb48f8d93e 100644
--- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
@@ -538,6 +538,21 @@ pub fn disallow_cfg(_attr: TokenStream, input: TokenStream) -> TokenStream {
                 disabled: false,
             },
         ),
+        (
+            r#"
+#[proc_macro_attribute]
+pub fn generate_suffixed_type(_attr: TokenStream, input: TokenStream) -> TokenStream {
+    input
+}
+"#
+            .into(),
+            ProcMacro {
+                name: Symbol::intern("generate_suffixed_type"),
+                kind: ProcMacroKind::Attr,
+                expander: sync::Arc::new(GenerateSuffixedTypeProcMacroExpander),
+                disabled: false,
+            },
+        ),
     ])
 }
 
@@ -919,3 +934,57 @@ impl ProcMacroExpander for DisallowCfgProcMacroExpander {
         Ok(subtree.clone())
     }
 }
+
+// Generates a new type by adding a suffix to the original name
+#[derive(Debug)]
+struct GenerateSuffixedTypeProcMacroExpander;
+impl ProcMacroExpander for GenerateSuffixedTypeProcMacroExpander {
+    fn expand(
+        &self,
+        subtree: &TopSubtree,
+        _attrs: Option<&TopSubtree>,
+        _env: &Env,
+        _def_site: Span,
+        call_site: Span,
+        _mixed_site: Span,
+        _current_dir: String,
+    ) -> Result<TopSubtree, ProcMacroExpansionError> {
+        let TokenTree::Leaf(Leaf::Ident(ident)) = &subtree.0[1] else {
+            return Err(ProcMacroExpansionError::Panic("incorrect Input".into()));
+        };
+
+        let ident = match ident.sym.as_str() {
+            "struct" => {
+                let TokenTree::Leaf(Leaf::Ident(ident)) = &subtree.0[2] else {
+                    return Err(ProcMacroExpansionError::Panic("incorrect Input".into()));
+                };
+                ident
+            }
+
+            "enum" => {
+                let TokenTree::Leaf(Leaf::Ident(ident)) = &subtree.0[4] else {
+                    return Err(ProcMacroExpansionError::Panic("incorrect Input".into()));
+                };
+                ident
+            }
+
+            _ => {
+                return Err(ProcMacroExpansionError::Panic("incorrect Input".into()));
+            }
+        };
+
+        let generated_ident = tt::Ident {
+            sym: Symbol::intern(&format!("{}Suffix", ident.sym)),
+            span: ident.span,
+            is_raw: tt::IdentIsRaw::No,
+        };
+
+        let ret = quote! { call_site =>
+            #subtree
+
+            struct #generated_ident;
+        };
+
+        Ok(ret)
+    }
+}
diff --git a/src/tools/rust-analyzer/docs/book/src/non_cargo_based_projects.md b/src/tools/rust-analyzer/docs/book/src/non_cargo_based_projects.md
index 151f8758a17..bbdb48bbbc9 100644
--- a/src/tools/rust-analyzer/docs/book/src/non_cargo_based_projects.md
+++ b/src/tools/rust-analyzer/docs/book/src/non_cargo_based_projects.md
@@ -5,7 +5,7 @@ build system, you’ll have to describe the structure of your project for
 rust-analyzer in the `rust-project.json` format:
 
 ```typescript
-interface JsonProject {
+interface ProjectJson {
     /// Path to the sysroot directory.
     ///
     /// The sysroot is where rustc looks for the
diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json
index 18fb097aad7..ab431140c10 100644
--- a/src/tools/rust-analyzer/editors/code/package-lock.json
+++ b/src/tools/rust-analyzer/editors/code/package-lock.json
@@ -5500,9 +5500,9 @@
             }
         },
         "node_modules/tar-fs": {
-            "version": "2.1.2",
-            "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz",
-            "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==",
+            "version": "2.1.3",
+            "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.3.tgz",
+            "integrity": "sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==",
             "dev": true,
             "license": "MIT",
             "optional": true,
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index 5b47d1bbaed..af0dd5c9acd 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-a8e4c68dcb4dc1e48a0db294c5323cab0227fcb9
+7c10378e1fee5ddc6573b916aeb884ab10e0de17
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index 8893846b5fa..ed67fa7d1a9 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -47,9 +47,9 @@ dependencies = [
 
 [[package]]
 name = "anstream"
-version = "0.6.18"
+version = "0.6.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b"
+checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933"
 dependencies = [
  "anstyle",
  "anstyle-parse",
@@ -62,36 +62,36 @@ dependencies = [
 
 [[package]]
 name = "anstyle"
-version = "1.0.10"
+version = "1.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
+checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd"
 
 [[package]]
 name = "anstyle-parse"
-version = "0.2.6"
+version = "0.2.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
+checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2"
 dependencies = [
  "utf8parse",
 ]
 
 [[package]]
 name = "anstyle-query"
-version = "1.1.2"
+version = "1.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
+checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9"
 dependencies = [
  "windows-sys",
 ]
 
 [[package]]
 name = "anstyle-wincon"
-version = "3.0.7"
+version = "3.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
+checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882"
 dependencies = [
  "anstyle",
- "once_cell",
+ "once_cell_polyfill",
  "windows-sys",
 ]
 
@@ -124,9 +124,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bitflags"
-version = "2.9.0"
+version = "2.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
+checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
 
 [[package]]
 name = "block-buffer"
@@ -150,15 +150,15 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.17.0"
+version = "3.18.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
+checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
 
 [[package]]
 name = "cc"
-version = "1.2.22"
+version = "1.2.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1"
+checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac"
 dependencies = [
  "shlex",
 ]
@@ -185,9 +185,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.38"
+version = "4.5.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000"
+checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -195,9 +195,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.38"
+version = "4.5.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120"
+checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51"
 dependencies = [
  "anstream",
  "anstyle",
@@ -208,9 +208,9 @@ dependencies = [
 
 [[package]]
 name = "clap_complete"
-version = "4.5.50"
+version = "4.5.52"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c91d3baa3bcd889d60e6ef28874126a0b384fd225ab83aa6d8a801c519194ce1"
+checksum = "1a554639e42d0c838336fc4fbedb9e2df3ad1fa4acda149f9126b4ccfcd7900f"
 dependencies = [
  "clap",
 ]
@@ -235,9 +235,9 @@ checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
 
 [[package]]
 name = "colorchoice"
-version = "1.0.3"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
+checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
 
 [[package]]
 name = "core-foundation-sys"
@@ -459,9 +459,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
 
 [[package]]
 name = "errno"
-version = "0.3.11"
+version = "0.3.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e"
+checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
 dependencies = [
  "libc",
  "windows-sys",
@@ -482,9 +482,9 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
 
 [[package]]
 name = "flate2"
-version = "1.1.1"
+version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
+checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
 dependencies = [
  "crc32fast",
  "miniz_oxide",
@@ -531,7 +531,7 @@ version = "0.2.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
 dependencies = [
- "unicode-width",
+ "unicode-width 0.1.14",
 ]
 
 [[package]]
@@ -564,9 +564,9 @@ dependencies = [
 
 [[package]]
 name = "hashbrown"
-version = "0.15.3"
+version = "0.15.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
+checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
 
 [[package]]
 name = "heck"
@@ -680,9 +680,9 @@ checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
 
 [[package]]
 name = "icu_properties"
-version = "2.0.0"
+version = "2.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a"
+checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
 dependencies = [
  "displaydoc",
  "icu_collections",
@@ -696,9 +696,9 @@ dependencies = [
 
 [[package]]
 name = "icu_properties_data"
-version = "2.0.0"
+version = "2.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04"
+checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
 
 [[package]]
 name = "icu_provider"
@@ -768,9 +768,9 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
 
 [[package]]
 name = "jiff"
-version = "0.2.13"
+version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f02000660d30638906021176af16b17498bd0d12813dbfe7b276d8bc7f3c0806"
+checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93"
 dependencies = [
  "jiff-static",
  "log",
@@ -781,9 +781,9 @@ dependencies = [
 
 [[package]]
 name = "jiff-static"
-version = "0.2.13"
+version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3c30758ddd7188629c6713fc45d1188af4f44c90582311d0c8d8c9907f60c48"
+checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -835,9 +835,9 @@ checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
 
 [[package]]
 name = "lock_api"
-version = "0.4.12"
+version = "0.4.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
+checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
 dependencies = [
  "autocfg",
  "scopeguard",
@@ -961,7 +961,7 @@ dependencies = [
  "pulldown-cmark-to-cmark 19.0.1",
  "serde_json",
  "thiserror 1.0.69",
- "toml 0.8.22",
+ "toml 0.8.23",
 ]
 
 [[package]]
@@ -1025,12 +1025,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
 
 [[package]]
+name = "once_cell_polyfill"
+version = "1.70.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad"
+
+[[package]]
 name = "onig"
 version = "6.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0"
 dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
  "libc",
  "once_cell",
  "onig_sys",
@@ -1048,9 +1054,9 @@ dependencies = [
 
 [[package]]
 name = "opener"
-version = "0.8.1"
+version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de96cad6ee771be7f68df884d3767460b4684012308d8342ed5623fe62b2628c"
+checksum = "771b9704f8cd8b424ec747a320b30b47517a6966ba2c7da90047c16f4a962223"
 dependencies = [
  "bstr",
  "normpath",
@@ -1059,9 +1065,9 @@ dependencies = [
 
 [[package]]
 name = "parking_lot"
-version = "0.12.3"
+version = "0.12.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
+checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
 dependencies = [
  "lock_api",
  "parking_lot_core",
@@ -1069,9 +1075,9 @@ dependencies = [
 
 [[package]]
 name = "parking_lot_core"
-version = "0.9.10"
+version = "0.9.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
+checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
 dependencies = [
  "cfg-if",
  "libc",
@@ -1206,9 +1212,9 @@ dependencies = [
 
 [[package]]
 name = "portable-atomic"
-version = "1.11.0"
+version = "1.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
+checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
 
 [[package]]
 name = "portable-atomic-util"
@@ -1249,7 +1255,7 @@ version = "0.10.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993"
 dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
  "memchr",
  "pulldown-cmark-escape 0.10.1",
  "unicase",
@@ -1261,7 +1267,7 @@ version = "0.12.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14"
 dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
  "getopts",
  "memchr",
  "pulldown-cmark-escape 0.11.0",
@@ -1315,11 +1321,11 @@ checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
 
 [[package]]
 name = "railroad"
-version = "0.3.2"
+version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0ecedffc46c1b2cb04f4b80e094eae6b3f3f470a9635f1f396dd5206428f6b58"
+checksum = "e6d5b8e8a7c20c600f9b98cbf46b64e63d5c9e69deb98cee1ff264de9f1dda5d"
 dependencies = [
- "unicode-width",
+ "unicode-width 0.2.0",
 ]
 
 [[package]]
@@ -1343,7 +1349,7 @@ version = "0.5.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af"
 dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
 ]
 
 [[package]]
@@ -1393,7 +1399,7 @@ version = "1.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
 dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
  "errno",
  "libc",
  "linux-raw-sys",
@@ -1402,9 +1408,9 @@ dependencies = [
 
 [[package]]
 name = "rustversion"
-version = "1.0.20"
+version = "1.0.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
+checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
 
 [[package]]
 name = "ryu"
@@ -1467,9 +1473,9 @@ dependencies = [
 
 [[package]]
 name = "serde_spanned"
-version = "0.6.8"
+version = "0.6.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
+checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
 dependencies = [
  "serde",
 ]
@@ -1499,9 +1505,9 @@ checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
 
 [[package]]
 name = "smallvec"
-version = "1.15.0"
+version = "1.15.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
 
 [[package]]
 name = "stable_deref_trait"
@@ -1584,9 +1590,9 @@ dependencies = [
 
 [[package]]
 name = "tempfile"
-version = "3.19.1"
+version = "3.20.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf"
+checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
 dependencies = [
  "fastrand",
  "getrandom",
@@ -1683,9 +1689,9 @@ dependencies = [
 
 [[package]]
 name = "toml"
-version = "0.8.22"
+version = "0.8.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae"
+checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
 dependencies = [
  "serde",
  "serde_spanned",
@@ -1695,18 +1701,18 @@ dependencies = [
 
 [[package]]
 name = "toml_datetime"
-version = "0.6.9"
+version = "0.6.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3"
+checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "toml_edit"
-version = "0.22.26"
+version = "0.22.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e"
+checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
 dependencies = [
  "indexmap",
  "serde",
@@ -1718,9 +1724,9 @@ dependencies = [
 
 [[package]]
 name = "toml_write"
-version = "0.1.1"
+version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076"
+checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
 
 [[package]]
 name = "topological-sort"
@@ -1759,6 +1765,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
 
 [[package]]
+name = "unicode-width"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
+
+[[package]]
 name = "url"
 version = "2.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1872,9 +1884,9 @@ dependencies = [
 
 [[package]]
 name = "web_atoms"
-version = "0.1.2"
+version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b9c5f0bc545ea3b20b423e33b9b457764de0b3730cd957f6c6aa6c301785f6e"
+checksum = "57ffde1dc01240bdf9992e3205668b235e59421fd085e8a317ed98da0178d414"
 dependencies = [
  "phf",
  "phf_codegen",
@@ -1893,9 +1905,9 @@ dependencies = [
 
 [[package]]
 name = "windows-core"
-version = "0.61.0"
+version = "0.61.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
+checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
 dependencies = [
  "windows-implement",
  "windows-interface",
@@ -1934,18 +1946,18 @@ checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
 
 [[package]]
 name = "windows-result"
-version = "0.3.2"
+version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
+checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
 dependencies = [
  "windows-link",
 ]
 
 [[package]]
 name = "windows-strings"
-version = "0.4.0"
+version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
+checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
 dependencies = [
  "windows-link",
 ]
@@ -2038,7 +2050,7 @@ version = "0.39.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
 dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
 ]
 
 [[package]]
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index fdca7a7a40e..170dcd626a2 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -441,6 +441,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "windows-strings",
     "windows-sys",
     "windows-targets",
+    "windows-threading",
     "windows_aarch64_gnullvm",
     "windows_aarch64_msvc",
     "windows_i686_gnu",
diff --git a/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs b/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs
new file mode 100644
index 00000000000..c354228acc5
--- /dev/null
+++ b/tests/codegen/autovec/dont-shuffle-bswaps-opt2.rs
@@ -0,0 +1,31 @@
+//@ compile-flags: -Copt-level=2
+
+#![crate_type = "lib"]
+#![no_std]
+
+// This test is paired with the arch-specific -opt3.rs test.
+
+// The code is from https://github.com/rust-lang/rust/issues/122805.
+// Ensure we do not generate the shufflevector instruction
+// to avoid complicating the code.
+
+// CHECK-LABEL: define{{.*}}void @convert(
+// CHECK-NOT: shufflevector
+#[no_mangle]
+pub fn convert(value: [u16; 8]) -> [u8; 16] {
+    #[cfg(target_endian = "little")]
+    let bswap = u16::to_be;
+    #[cfg(target_endian = "big")]
+    let bswap = u16::to_le;
+    let addr16 = [
+        bswap(value[0]),
+        bswap(value[1]),
+        bswap(value[2]),
+        bswap(value[3]),
+        bswap(value[4]),
+        bswap(value[5]),
+        bswap(value[6]),
+        bswap(value[7]),
+    ];
+    unsafe { core::mem::transmute::<_, [u8; 16]>(addr16) }
+}
diff --git a/tests/codegen/dont-shuffle-bswaps.rs b/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs
index c1dab2bc295..203d12005de 100644
--- a/tests/codegen/dont-shuffle-bswaps.rs
+++ b/tests/codegen/autovec/dont-shuffle-bswaps-opt3.rs
@@ -1,29 +1,27 @@
-//@ revisions: OPT2 OPT3 OPT3_S390X
-//@[OPT2] compile-flags: -Copt-level=2
-//@[OPT3] compile-flags: -C opt-level=3
-// some targets don't do the opt we are looking for
-//@[OPT3] only-64bit
-//@[OPT3] ignore-s390x
-//@[OPT3_S390X] compile-flags: -C opt-level=3 -C target-cpu=z13
-//@[OPT3_S390X] only-s390x
+//@ revisions: AARCH64 X86_64 Z13
+//@ compile-flags: -Copt-level=3
+//@[AARCH64] only-aarch64
+//@[X86_64] only-x86_64
+//@[Z13] only-s390x
+//@[Z13] compile-flags: -Ctarget-cpu=z13
 
 #![crate_type = "lib"]
 #![no_std]
 
+// This test is paired with the arch-neutral -opt2.rs test
+
 // The code is from https://github.com/rust-lang/rust/issues/122805.
 // Ensure we do not generate the shufflevector instruction
 // to avoid complicating the code.
+
 // CHECK-LABEL: define{{.*}}void @convert(
 // CHECK-NOT: shufflevector
+
 // On higher opt levels, this should just be a bswap:
-// OPT3: load <8 x i16>
-// OPT3-NEXT: call <8 x i16> @llvm.bswap
-// OPT3-NEXT: store <8 x i16>
-// OPT3-NEXT: ret void
-// OPT3_S390X: load <8 x i16>
-// OPT3_S390X-NEXT: call <8 x i16> @llvm.bswap
-// OPT3_S390X-NEXT: store <8 x i16>
-// OPT3_S390X-NEXT: ret void
+// CHECK: load <8 x i16>
+// CHECK-NEXT: call <8 x i16> @llvm.bswap
+// CHECK-NEXT: store <8 x i16>
+// CHECK-NEXT: ret void
 #[no_mangle]
 pub fn convert(value: [u16; 8]) -> [u8; 16] {
     #[cfg(target_endian = "little")]
diff --git a/tests/codegen/retpoline.rs b/tests/codegen/retpoline.rs
new file mode 100644
index 00000000000..30fdd9c2db2
--- /dev/null
+++ b/tests/codegen/retpoline.rs
@@ -0,0 +1,29 @@
+// ignore-tidy-linelength
+// Test that the
+// `retpoline-external-thunk`, `retpoline-indirect-branches`, `retpoline-indirect-calls`
+// target features are (not) emitted when the `retpoline/retpoline-external-thunk` flag is (not) set.
+
+//@ revisions: disabled enabled_retpoline enabled_retpoline_external_thunk
+//@ needs-llvm-components: x86
+//@ compile-flags: --target x86_64-unknown-linux-gnu
+//@ [enabled_retpoline] compile-flags: -Zretpoline
+//@ [enabled_retpoline_external_thunk] compile-flags: -Zretpoline-external-thunk
+
+#![crate_type = "lib"]
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang = "sized"]
+trait Sized {}
+
+#[no_mangle]
+pub fn foo() {
+    // CHECK: @foo() unnamed_addr #0
+
+    // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-external-thunk{{.*}} }
+    // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-branches{{.*}} }
+    // disabled-NOT: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-calls{{.*}} }
+
+    // enabled_retpoline: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-indirect-branches,+retpoline-indirect-calls{{.*}} }
+    // enabled_retpoline_external_thunk: attributes #0 = { {{.*}}"target-features"="{{[^"]*}}+retpoline-external-thunk,+retpoline-indirect-branches,+retpoline-indirect-calls{{.*}} }
+}
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/debuginfo/type-names.rs b/tests/debuginfo/type-names.rs
index 3c7eab7e8d7..ac61fef48fe 100644
--- a/tests/debuginfo/type-names.rs
+++ b/tests/debuginfo/type-names.rs
@@ -19,7 +19,7 @@
 // gdb-check:type = type_names::GenericStruct<type_names::mod1::Struct2, type_names::mod1::mod2::Struct3>
 
 // gdb-command:whatis generic_struct2
-// gdb-check:type = type_names::GenericStruct<type_names::Struct1, extern "fastcall" fn(isize) -> usize>
+// gdb-check:type = type_names::GenericStruct<type_names::Struct1, extern "system" fn(isize) -> usize>
 
 // gdb-command:whatis mod_struct
 // gdb-check:type = type_names::mod1::Struct2
@@ -379,7 +379,7 @@ fn main() {
     let simple_struct = Struct1;
     let generic_struct1: GenericStruct<mod1::Struct2, mod1::mod2::Struct3> =
         GenericStruct(PhantomData);
-    let generic_struct2: GenericStruct<Struct1, extern "fastcall" fn(isize) -> usize> =
+    let generic_struct2: GenericStruct<Struct1, extern "system" fn(isize) -> usize> =
         GenericStruct(PhantomData);
     let mod_struct = mod1::Struct2;
 
diff --git a/tests/incremental/hashes/trait_defs.rs b/tests/incremental/hashes/trait_defs.rs
index cb8716d90b0..7141ddb0d7e 100644
--- a/tests/incremental/hashes/trait_defs.rs
+++ b/tests/incremental/hashes/trait_defs.rs
@@ -440,7 +440,7 @@ trait TraitAddExternModifier {
 
 // Change extern "C" to extern "stdcall"
 #[cfg(any(cfail1,cfail4))]
-trait TraitChangeExternCToRustIntrinsic {
+trait TraitChangeExternCToExternSystem {
     // --------------------------------------------------------------
     // -------------------------
     // --------------------------------------------------------------
@@ -458,7 +458,7 @@ trait TraitChangeExternCToRustIntrinsic {
     #[rustc_clean(cfg="cfail3")]
     #[rustc_clean(except="opt_hir_owner_nodes,fn_sig", cfg="cfail5")]
     #[rustc_clean(cfg="cfail6")]
-    extern "stdcall" fn method();
+    extern "system" fn method();
 }
 
 
diff --git a/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
index 7b94a4c2bf7..22ebe2f3f29 100644
--- a/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
+++ b/tests/mir-opt/early_otherwise_branch.opt3.EarlyOtherwiseBranch.diff
@@ -32,16 +32,12 @@
           StorageDead(_4);
           _9 = discriminant((_3.0: Option2<u32>));
 -         switchInt(move _9) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb9];
-+         StorageLive(_12);
 +         _12 = discriminant((_3.1: Option2<bool>));
-+         StorageLive(_13);
 +         _13 = Ne(copy _9, move _12);
-+         StorageDead(_12);
 +         switchInt(move _13) -> [0: bb7, otherwise: bb1];
       }
   
       bb1: {
-+         StorageDead(_13);
           _0 = const 1_u32;
 -         goto -> bb8;
 +         goto -> bb5;
@@ -100,7 +96,6 @@
 +     }
 + 
 +     bb7: {
-+         StorageDead(_13);
 +         switchInt(copy _9) -> [0: bb4, 1: bb3, 2: bb2, otherwise: bb6];
       }
   }
diff --git a/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff
index f52795baef8..0da0eb3c53c 100644
--- a/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff
+++ b/tests/mir-opt/early_otherwise_branch.opt4.EarlyOtherwiseBranch.diff
@@ -32,16 +32,12 @@
           StorageDead(_4);
           _9 = discriminant((_3.0: Option2<u32>));
 -         switchInt(move _9) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb9];
-+         StorageLive(_12);
 +         _12 = discriminant((_3.1: Option2<u32>));
-+         StorageLive(_13);
 +         _13 = Ne(copy _9, move _12);
-+         StorageDead(_12);
 +         switchInt(move _13) -> [0: bb7, otherwise: bb1];
       }
   
       bb1: {
-+         StorageDead(_13);
           _0 = const 1_u32;
 -         goto -> bb8;
 +         goto -> bb5;
@@ -100,7 +96,6 @@
 +     }
 + 
 +     bb7: {
-+         StorageDead(_13);
 +         switchInt(copy _9) -> [0: bb4, 1: bb3, 2: bb2, otherwise: bb6];
       }
   }
diff --git a/tests/mir-opt/early_otherwise_branch.opt5.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.opt5.EarlyOtherwiseBranch.diff
index b7447ef0c46..b13d21e2d7a 100644
--- a/tests/mir-opt/early_otherwise_branch.opt5.EarlyOtherwiseBranch.diff
+++ b/tests/mir-opt/early_otherwise_branch.opt5.EarlyOtherwiseBranch.diff
@@ -20,13 +20,11 @@
           StorageDead(_5);
           StorageDead(_4);
 -         switchInt(copy (_3.0: u32)) -> [1: bb2, 2: bb3, 3: bb4, otherwise: bb1];
-+         StorageLive(_6);
 +         _6 = Ne(copy (_3.0: u32), copy (_3.1: u32));
 +         switchInt(move _6) -> [0: bb6, otherwise: bb1];
       }
   
       bb1: {
-+         StorageDead(_6);
           _0 = const 0_u32;
 -         goto -> bb8;
 +         goto -> bb5;
@@ -70,7 +68,6 @@
 -     bb8: {
 -         StorageDead(_3);
 -         return;
-+         StorageDead(_6);
 +         switchInt(copy (_3.0: u32)) -> [1: bb4, 2: bb3, 3: bb2, otherwise: bb1];
       }
   }
diff --git a/tests/mir-opt/early_otherwise_branch.rs b/tests/mir-opt/early_otherwise_branch.rs
index 382c38ceb3a..19a5d25de2d 100644
--- a/tests/mir-opt/early_otherwise_branch.rs
+++ b/tests/mir-opt/early_otherwise_branch.rs
@@ -1,6 +1,10 @@
 //@ test-mir-pass: EarlyOtherwiseBranch
 //@ compile-flags: -Zmir-enable-passes=+UnreachableEnumBranching
 
+#![feature(custom_mir, core_intrinsics)]
+
+use std::intrinsics::mir::*;
+
 enum Option2<T> {
     Some(T),
     None,
@@ -124,6 +128,34 @@ fn opt5_failed_type(x: u32, y: u64) -> u32 {
     }
 }
 
+// EMIT_MIR early_otherwise_branch.target_self.EarlyOtherwiseBranch.diff
+#[custom_mir(dialect = "runtime")]
+fn target_self(val: i32) {
+    // CHECK-LABEL: fn target_self(
+    // CHECK: Ne(
+    // CHECK-NEXT: switchInt
+    mir! {
+        {
+            Goto(bb1)
+        }
+        bb1 = {
+            match val {
+                0 => bb2,
+                _ => bb1,
+            }
+        }
+        bb2 = {
+            match val {
+                0 => bb3,
+                _ => bb1,
+            }
+        }
+        bb3 = {
+            Return()
+        }
+    }
+}
+
 fn main() {
     opt1(None, Some(0));
     opt2(None, Some(0));
@@ -131,4 +163,5 @@ fn main() {
     opt4(Option2::None, Option2::Some(0));
     opt5(0, 0);
     opt5_failed(0, 0);
+    target_self(1);
 }
diff --git a/tests/mir-opt/early_otherwise_branch.target_self.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch.target_self.EarlyOtherwiseBranch.diff
new file mode 100644
index 00000000000..4f70847bcdf
--- /dev/null
+++ b/tests/mir-opt/early_otherwise_branch.target_self.EarlyOtherwiseBranch.diff
@@ -0,0 +1,28 @@
+- // MIR for `target_self` before EarlyOtherwiseBranch
++ // MIR for `target_self` after EarlyOtherwiseBranch
+  
+  fn target_self(_1: i32) -> () {
+      let mut _0: ();
++     let mut _2: bool;
+  
+      bb0: {
+          goto -> bb1;
+      }
+  
+      bb1: {
+-         switchInt(copy _1) -> [0: bb2, otherwise: bb1];
++         _2 = Ne(copy _1, copy _1);
++         switchInt(move _2) -> [0: bb3, otherwise: bb1];
+      }
+  
+      bb2: {
+-         switchInt(copy _1) -> [0: bb3, otherwise: bb1];
++         return;
+      }
+  
+      bb3: {
+-         return;
++         switchInt(copy _1) -> [0: bb2, otherwise: bb1];
+      }
+  }
+  
diff --git a/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff
index 831d8cbb4d6..e0878167e44 100644
--- a/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff
+++ b/tests/mir-opt/early_otherwise_branch_3_element_tuple.opt2.EarlyOtherwiseBranch.diff
@@ -42,16 +42,12 @@
           StorageDead(_5);
           _14 = discriminant((_4.0: Option2<u32>));
 -         switchInt(move _14) -> [0: bb2, 1: bb4, 2: bb6, otherwise: bb12];
-+         StorageLive(_18);
 +         _18 = discriminant((_4.1: Option2<u32>));
-+         StorageLive(_19);
 +         _19 = Ne(copy _14, move _18);
-+         StorageDead(_18);
 +         switchInt(move _19) -> [0: bb10, otherwise: bb1];
       }
   
       bb1: {
-+         StorageDead(_19);
           _0 = const 1_u32;
 -         goto -> bb11;
 +         goto -> bb8;
@@ -134,7 +130,6 @@
 +     }
 + 
 +     bb10: {
-+         StorageDead(_19);
 +         switchInt(copy _14) -> [0: bb2, 1: bb3, 2: bb4, otherwise: bb9];
       }
   }
diff --git a/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-abort.diff
index 8ebd07b9c9c..e61a3e8d738 100644
--- a/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-abort.diff
@@ -5,7 +5,7 @@
       let mut _0: usize;
   
       bb0: {
--         _0 = std::intrinsics::min_align_of::<T>() -> [return: bb1, unwind unreachable];
+-         _0 = std::intrinsics::align_of::<T>() -> [return: bb1, unwind unreachable];
 +         _0 = AlignOf(T);
 +         goto -> bb1;
       }
diff --git a/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-unwind.diff
index 8ebd07b9c9c..e61a3e8d738 100644
--- a/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.align_of.LowerIntrinsics.panic-unwind.diff
@@ -5,7 +5,7 @@
       let mut _0: usize;
   
       bb0: {
--         _0 = std::intrinsics::min_align_of::<T>() -> [return: bb1, unwind unreachable];
+-         _0 = std::intrinsics::align_of::<T>() -> [return: bb1, unwind unreachable];
 +         _0 = AlignOf(T);
 +         goto -> bb1;
       }
diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs
index 1e4f2024194..7729e502ad6 100644
--- a/tests/mir-opt/lower_intrinsics.rs
+++ b/tests/mir-opt/lower_intrinsics.rs
@@ -51,7 +51,7 @@ pub fn size_of<T>() -> usize {
 pub fn align_of<T>() -> usize {
     // CHECK-LABEL: fn align_of(
     // CHECK: {{_.*}} = AlignOf(T);
-    core::intrinsics::min_align_of::<T>()
+    core::intrinsics::align_of::<T>()
 }
 
 // EMIT_MIR lower_intrinsics.forget.LowerIntrinsics.diff
diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir
index 30eafe8594b..2eee8a97db0 100644
--- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir
@@ -39,7 +39,7 @@ fn vec_deref_to_slice(_1: &Vec<u8>) -> &[u8] {
                 }
                 scope 15 (inlined std::mem::size_of::<u8>) {
                 }
-                scope 16 (inlined align_of::<u8>) {
+                scope 16 (inlined std::mem::align_of::<u8>) {
                 }
                 scope 17 (inlined slice_from_raw_parts::<u8>) {
                     debug data => _3;
diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir
index 30eafe8594b..2eee8a97db0 100644
--- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir
@@ -39,7 +39,7 @@ fn vec_deref_to_slice(_1: &Vec<u8>) -> &[u8] {
                 }
                 scope 15 (inlined std::mem::size_of::<u8>) {
                 }
-                scope 16 (inlined align_of::<u8>) {
+                scope 16 (inlined std::mem::align_of::<u8>) {
                 }
                 scope 17 (inlined slice_from_raw_parts::<u8>) {
                     debug data => _3;
diff --git a/tests/pretty/postfix-match/precedence.pp b/tests/pretty/postfix-match/precedence.pp
index 967aa7bc39e..2052b445a2b 100644
--- a/tests/pretty/postfix-match/precedence.pp
+++ b/tests/pretty/postfix-match/precedence.pp
@@ -26,7 +26,7 @@ pub fn main() {
         _ => {}
     };
     (4 as usize).match { _ => {} };
-    (return).match { _ => {} };
+    return.match { _ => {} };
     (a = 42).match { _ => {} };
     (|| {}).match { _ => {} };
     (42..101).match { _ => {} };
diff --git a/tests/run-make/cpp-global-destructors/rmake.rs b/tests/run-make/cpp-global-destructors/rmake.rs
index 9bc5c84e10d..92aeb67c278 100644
--- a/tests/run-make/cpp-global-destructors/rmake.rs
+++ b/tests/run-make/cpp-global-destructors/rmake.rs
@@ -6,15 +6,11 @@
 //@ ignore-cross-compile
 // Reason: the compiled binary is executed
 
-//@ ignore-none
-// Reason: no-std is not supported.
 //@ ignore-wasm32
 //@ ignore-wasm64
 // Reason: compiling C++ to WASM may cause problems.
 
-// Neither of these are tested in full CI.
-//@ ignore-nvptx64-nvidia-cuda
-// Reason: can't find crate "std"
+// Not exercised in full CI, but sgx technically supports std.
 //@ ignore-sgx
 
 use run_make_support::{build_native_static_lib_cxx, run, rustc};
diff --git a/tests/run-make/export-executable-symbols/rmake.rs b/tests/run-make/export-executable-symbols/rmake.rs
index 77f968189b6..dc8c59b9c74 100644
--- a/tests/run-make/export-executable-symbols/rmake.rs
+++ b/tests/run-make/export-executable-symbols/rmake.rs
@@ -10,8 +10,7 @@
 // (See #85673)
 //@ ignore-wasm32
 //@ ignore-wasm64
-//@ ignore-none
-// Reason: no-std is not supported
+//@ needs-target-std
 
 use run_make_support::{bin_name, llvm_readobj, rustc};
 
diff --git a/tests/run-make/incr-foreign-head-span/rmake.rs b/tests/run-make/incr-foreign-head-span/rmake.rs
index 92e2ed5f879..d9841b31464 100644
--- a/tests/run-make/incr-foreign-head-span/rmake.rs
+++ b/tests/run-make/incr-foreign-head-span/rmake.rs
@@ -5,10 +5,7 @@
 // source file from disk during compilation of a downstream crate.
 // See https://github.com/rust-lang/rust/issues/86480
 
-//@ ignore-none
-// Reason: no-std is not supported
-//@ ignore-nvptx64-nvidia-cuda
-// Reason: can't find crate for 'std'
+//@ needs-target-std
 
 use run_make_support::{rfs, rust_lib_name, rustc};
 
diff --git a/tests/run-make/incr-prev-body-beyond-eof/rmake.rs b/tests/run-make/incr-prev-body-beyond-eof/rmake.rs
index 47dce85248a..cfa8d5b46cd 100644
--- a/tests/run-make/incr-prev-body-beyond-eof/rmake.rs
+++ b/tests/run-make/incr-prev-body-beyond-eof/rmake.rs
@@ -7,11 +7,7 @@
 // was hashed by rustc in addition to the span length, and the fix still
 // works.
 
-//@ ignore-none
-// reason: no-std is not supported
-
-//@ ignore-nvptx64-nvidia-cuda
-// FIXME: can't find crate for `std`
+//@ needs-target-std
 
 use run_make_support::{rfs, rustc};
 
diff --git a/tests/run-make/incr-test-moved-file/rmake.rs b/tests/run-make/incr-test-moved-file/rmake.rs
index 0ba1b0d58fe..dfba95d3fed 100644
--- a/tests/run-make/incr-test-moved-file/rmake.rs
+++ b/tests/run-make/incr-test-moved-file/rmake.rs
@@ -9,10 +9,7 @@
 // for successful compilation.
 // See https://github.com/rust-lang/rust/issues/83112
 
-//@ ignore-none
-// Reason: no-std is not supported
-//@ ignore-nvptx64-nvidia-cuda
-// FIXME: can't find crate for 'std'
+//@ needs-target-std
 
 use run_make_support::{rfs, rustc};
 
diff --git a/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs b/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs
index f63146e692a..0d96b40e8a4 100644
--- a/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs
+++ b/tests/run-make/moved-src-dir-fingerprint-ice/rmake.rs
@@ -12,10 +12,7 @@
 // sessions.
 // See https://github.com/rust-lang/rust/issues/85019
 
-//@ ignore-none
-// Reason: no-std is not supported
-//@ ignore-nvptx64-nvidia-cuda
-// FIXME: can't find crate for 'std'
+//@ needs-target-std
 
 use run_make_support::{rfs, rust_lib_name, rustc};
 
diff --git a/tests/rustdoc-json/fn_pointer/abi.rs b/tests/rustdoc-json/fn_pointer/abi.rs
index 34150c0fe89..ec76e0f6636 100644
--- a/tests/rustdoc-json/fn_pointer/abi.rs
+++ b/tests/rustdoc-json/fn_pointer/abi.rs
@@ -1,4 +1,4 @@
-#![feature(abi_vectorcall)]
+#![feature(rust_cold_cc)]
 
 //@ is "$.index[?(@.name=='AbiRust')].inner.type_alias.type.function_pointer.header.abi" \"Rust\"
 pub type AbiRust = fn();
@@ -15,8 +15,5 @@ pub type AbiCUnwind = extern "C-unwind" fn();
 //@ is "$.index[?(@.name=='AbiSystemUnwind')].inner.type_alias.type.function_pointer.header.abi" '{"System": {"unwind": true}}'
 pub type AbiSystemUnwind = extern "system-unwind" fn();
 
-//@ is "$.index[?(@.name=='AbiVecorcall')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall\""'
-pub type AbiVecorcall = extern "vectorcall" fn();
-
-//@ is "$.index[?(@.name=='AbiVecorcallUnwind')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall-unwind\""'
-pub type AbiVecorcallUnwind = extern "vectorcall-unwind" fn();
+//@ is "$.index[?(@.name=='AbiRustCold')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"rust-cold\""'
+pub type AbiRustCold = extern "rust-cold" fn();
diff --git a/tests/rustdoc-json/fns/abi.rs b/tests/rustdoc-json/fns/abi.rs
index 7277bb1f59a..3373d135c89 100644
--- a/tests/rustdoc-json/fns/abi.rs
+++ b/tests/rustdoc-json/fns/abi.rs
@@ -1,4 +1,4 @@
-#![feature(abi_vectorcall)]
+#![feature(rust_cold_cc)]
 
 //@ is "$.index[?(@.name=='abi_rust')].inner.function.header.abi" \"Rust\"
 pub fn abi_rust() {}
@@ -15,8 +15,5 @@ pub extern "C-unwind" fn abi_c_unwind() {}
 //@ is "$.index[?(@.name=='abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}'
 pub extern "system-unwind" fn abi_system_unwind() {}
 
-//@ is "$.index[?(@.name=='abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""'
-pub extern "vectorcall" fn abi_vectorcall() {}
-
-//@ is "$.index[?(@.name=='abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""'
-pub extern "vectorcall-unwind" fn abi_vectorcall_unwind() {}
+//@ is "$.index[?(@.name=='abi_rust_cold')].inner.function.header.abi.Other" '"\"rust-cold\""'
+pub extern "rust-cold" fn abi_rust_cold() {}
diff --git a/tests/rustdoc-json/methods/abi.rs b/tests/rustdoc-json/methods/abi.rs
index fa2387ddf67..be6a11784f5 100644
--- a/tests/rustdoc-json/methods/abi.rs
+++ b/tests/rustdoc-json/methods/abi.rs
@@ -1,5 +1,4 @@
-#![feature(abi_vectorcall)]
-
+#![feature(rust_cold_cc)]
 //@ has "$.index[?(@.name=='Foo')]"
 pub struct Foo;
 
@@ -19,11 +18,8 @@ impl Foo {
     //@ is "$.index[?(@.name=='abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}'
     pub extern "system-unwind" fn abi_system_unwind() {}
 
-    //@ is "$.index[?(@.name=='abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""'
-    pub extern "vectorcall" fn abi_vectorcall() {}
-
-    //@ is "$.index[?(@.name=='abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""'
-    pub extern "vectorcall-unwind" fn abi_vectorcall_unwind() {}
+    //@ is "$.index[?(@.name=='abi_rust_cold')].inner.function.header.abi.Other" '"\"rust-cold\""'
+    pub extern "rust-cold" fn abi_rust_cold() {}
 }
 
 pub trait Bar {
@@ -42,9 +38,6 @@ pub trait Bar {
     //@ is "$.index[?(@.name=='trait_abi_system_unwind')].inner.function.header.abi" '{"System": {"unwind": true}}'
     extern "system-unwind" fn trait_abi_system_unwind() {}
 
-    //@ is "$.index[?(@.name=='trait_abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""'
-    extern "vectorcall" fn trait_abi_vectorcall() {}
-
-    //@ is "$.index[?(@.name=='trait_abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""'
-    extern "vectorcall-unwind" fn trait_abi_vectorcall_unwind() {}
+    //@ is "$.index[?(@.name=='trait_abi_rust_cold')].inner.function.header.abi.Other" '"\"rust-cold\""'
+    extern "rust-cold" fn trait_abi_rust_cold() {}
 }
diff --git a/tests/rustdoc-json/vectorcall.rs b/tests/rustdoc-json/vectorcall.rs
new file mode 100644
index 00000000000..19cac244f42
--- /dev/null
+++ b/tests/rustdoc-json/vectorcall.rs
@@ -0,0 +1,27 @@
+#![feature(abi_vectorcall)]
+//@ only-x86_64
+
+//@ is "$.index[?(@.name=='AbiVectorcall')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall\""'
+pub type AbiVectorcall = extern "vectorcall" fn();
+
+//@ is "$.index[?(@.name=='AbiVectorcallUnwind')].inner.type_alias.type.function_pointer.header.abi.Other" '"\"vectorcall-unwind\""'
+pub type AbiVectorcallUnwind = extern "vectorcall-unwind" fn();
+
+//@ has "$.index[?(@.name=='Foo')]"
+pub struct Foo;
+
+impl Foo {
+    //@ is "$.index[?(@.name=='abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""'
+    pub extern "vectorcall" fn abi_vectorcall() {}
+
+    //@ is "$.index[?(@.name=='abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""'
+    pub extern "vectorcall-unwind" fn abi_vectorcall_unwind() {}
+}
+
+pub trait Bar {
+    //@ is "$.index[?(@.name=='trait_abi_vectorcall')].inner.function.header.abi.Other" '"\"vectorcall\""'
+    extern "vectorcall" fn trait_abi_vectorcall() {}
+
+    //@ is "$.index[?(@.name=='trait_abi_vectorcall_unwind')].inner.function.header.abi.Other" '"\"vectorcall-unwind\""'
+    extern "vectorcall-unwind" fn trait_abi_vectorcall_unwind() {}
+}
diff --git a/tests/rustdoc/cfg-bool.rs b/tests/rustdoc/cfg-bool.rs
index 34fdfbe930e..0aaa132e0b5 100644
--- a/tests/rustdoc/cfg-bool.rs
+++ b/tests/rustdoc/cfg-bool.rs
@@ -3,11 +3,15 @@
 
 // regression test for https://github.com/rust-lang/rust/issues/138112
 
-//@ has 'foo/fn.foo.html' '//div[@class="stab portability"]' 'Available nowhere'
+//@ has 'foo/index.html'
+//@ has - '//*[@class="stab portability"]/@title' 'Available nowhere'
+
+//@ count 'foo/fn.foo.html' '//*[@class="stab portability"]' 1
+//@ has 'foo/fn.foo.html' '//*[@class="stab portability"]' 'Available nowhere'
 #[doc(cfg(false))]
 pub fn foo() {}
 
-// a cfg(true) will simply be ommited, as it is the same as no cfg.
-//@ !has 'foo/fn.bar.html' '//div[@class="stab portability"]' ''
+// a cfg(true) will simply be omitted, as it is the same as no cfg.
+//@ count 'foo/fn.bar.html' '//*[@class="stab portability"]' 0
 #[doc(cfg(true))]
 pub fn bar() {}
diff --git a/tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html b/tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html
index 28f15522a82..4dcc8111c6f 100644
--- a/tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html
+++ b/tests/rustdoc/macro/macro-generated-macro.macro_morestuff_pre.html
@@ -1,7 +1,7 @@
 macro_rules! morestuff {
     (
-        <= "space between most kinds of tokens" : 1 $x + @ :: >>= 'static
-        "no space inside paren or bracket" : (2 a) [2 a] $(2 $a:tt)*
+        <= "space between most kinds of tokens" : 1 $x:ident + @ :: >>=
+        'static "no space inside paren or bracket" : (2 a) [2 a] $(2 $a:tt)*
         "space inside curly brace" : { 2 a }
         "no space inside empty delimiters" : () [] {}
         "no space before comma or semicolon" : a, (a), { a }, a; [T; 0];
diff --git a/tests/rustdoc/macro/macro-generated-macro.rs b/tests/rustdoc/macro/macro-generated-macro.rs
index e77d0cf89e7..dfb152bafb6 100644
--- a/tests/rustdoc/macro/macro-generated-macro.rs
+++ b/tests/rustdoc/macro/macro-generated-macro.rs
@@ -25,7 +25,7 @@ make_macro!(linebreak 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 
 //@ snapshot macro_morestuff_pre macro_generated_macro/macro.morestuff.html //pre/text()
 make_macro!(morestuff
-    "space between most kinds of tokens": 1 $x + @ :: >>= 'static
+    "space between most kinds of tokens": 1 $x:ident + @ :: >>= 'static
     "no space inside paren or bracket": (2 a) [2 a] $(2 $a:tt)*
     "space inside curly brace": { 2 a }
     "no space inside empty delimiters": () [] {}
diff --git a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs
index c566ac459e0..36916e97856 100644
--- a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs
+++ b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs
@@ -63,8 +63,8 @@ static EXPRS: &[&str] = &[
     "(2 += 2) += 2",
     // Return has lower precedence than a binary operator.
     "(return 2) + 2",
-    "2 + (return 2)", // FIXME: no parenthesis needed.
-    "(return) + 2",   // FIXME: no parenthesis needed.
+    "2 + return 2",
+    "return + 2",
     // These mean different things.
     "return - 2",
     "(return) - 2",
diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
index 03fca17aa55..001699b2bc7 100644
--- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
+++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr
@@ -583,18 +583,32 @@ error: cannot find attribute `multipart_suggestion` in this scope
    |
 LL | #[multipart_suggestion(no_crate_suggestion)]
    |   ^^^^^^^^^^^^^^^^^^^^
+   |
+help: `multipart_suggestion` is an attribute that can be used by the derive macro `Subdiagnostic`, you might be missing a `derive` attribute
+   |
+LL + #[derive(Subdiagnostic)]
+LL | struct MultipartSuggestion {
+   |
 
 error: cannot find attribute `multipart_suggestion` in this scope
   --> $DIR/diagnostic-derive.rs:647:3
    |
 LL | #[multipart_suggestion()]
    |   ^^^^^^^^^^^^^^^^^^^^
+   |
+help: `multipart_suggestion` is an attribute that can be used by the derive macro `Subdiagnostic`, you might be missing a `derive` attribute
+   |
+LL + #[derive(Subdiagnostic)]
+LL | struct MultipartSuggestion {
+   |
 
 error: cannot find attribute `multipart_suggestion` in this scope
   --> $DIR/diagnostic-derive.rs:651:7
    |
 LL |     #[multipart_suggestion(no_crate_suggestion)]
    |       ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `multipart_suggestion` is an attribute that can be used by the derive macro `Subdiagnostic`, you might be missing a `derive` attribute
 
 error[E0425]: cannot find value `nonsense` in module `crate::fluent_generated`
   --> $DIR/diagnostic-derive.rs:75:8
diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs
index 71edf813a7b..15ef583709b 100644
--- a/tests/ui-fulldeps/stable-mir/check_abi.rs
+++ b/tests/ui-fulldeps/stable-mir/check_abi.rs
@@ -21,10 +21,13 @@ use stable_mir::abi::{
     ArgAbi, CallConvention, FieldsShape, IntegerLength, PassMode, Primitive, Scalar, ValueAbi,
     VariantsShape,
 };
+use stable_mir::mir::MirVisitor;
 use stable_mir::mir::mono::Instance;
 use stable_mir::target::MachineInfo;
+use stable_mir::ty::{AdtDef, RigidTy, Ty, TyKind};
 use stable_mir::{CrateDef, CrateItem, CrateItems, ItemKind};
 use std::assert_matches::assert_matches;
+use std::collections::HashSet;
 use std::convert::TryFrom;
 use std::io::Write;
 use std::ops::ControlFlow;
@@ -67,6 +70,17 @@ fn test_stable_mir() -> ControlFlow<()> {
     assert!(ptr_variadic_fn_abi.c_variadic);
     assert_eq!(ptr_variadic_fn_abi.args.len(), 1);
 
+    let entry = stable_mir::entry_fn().unwrap();
+    let main_fn = Instance::try_from(entry).unwrap();
+    let mut visitor = AdtDefVisitor::default();
+    visitor.visit_body(&main_fn.body().unwrap());
+    let AdtDefVisitor { adt_defs } = visitor;
+    assert_eq!(adt_defs.len(), 1);
+
+    // Test ADT representation options
+    let repr_c_struct = adt_defs.iter().find(|def| def.trimmed_name() == "ReprCStruct").unwrap();
+    assert!(repr_c_struct.repr().flags.is_c);
+
     ControlFlow::Continue(())
 }
 
@@ -138,6 +152,20 @@ fn get_item<'a>(
     items.iter().find(|crate_item| (item.0 == crate_item.kind()) && crate_item.name() == item.1)
 }
 
+#[derive(Default)]
+struct AdtDefVisitor {
+    adt_defs: HashSet<AdtDef>,
+}
+
+impl MirVisitor for AdtDefVisitor {
+    fn visit_ty(&mut self, ty: &Ty, _location: stable_mir::mir::visit::Location) {
+        if let TyKind::RigidTy(RigidTy::Adt(adt, _)) = ty.kind() {
+            self.adt_defs.insert(adt);
+        }
+        self.super_ty(ty)
+    }
+}
+
 /// This test will generate and analyze a dummy crate using the stable mir.
 /// For that, it will first write the dummy crate into a file.
 /// Then it will create a `StableMir` using custom arguments and then
@@ -147,7 +175,7 @@ fn main() {
     generate_input(&path).unwrap();
     let args = &[
         "rustc".to_string(),
-        "--crate-type=lib".to_string(),
+        "-Cpanic=abort".to_string(),
         "--crate-name".to_string(),
         CRATE_NAME.to_string(),
         path.to_string(),
@@ -185,6 +213,13 @@ fn generate_input(path: &str) -> std::io::Result<()> {
             // We only care about the signature.
             todo!()
         }}
+
+        fn main() {{
+            #[repr(C)]
+            struct ReprCStruct;
+
+            let _s = ReprCStruct;
+        }}
         "#
     )?;
     Ok(())
diff --git a/tests/ui-fulldeps/stable-mir/closure-generic-body.rs b/tests/ui-fulldeps/stable-mir/closure-generic-body.rs
new file mode 100644
index 00000000000..2a23345a9d3
--- /dev/null
+++ b/tests/ui-fulldeps/stable-mir/closure-generic-body.rs
@@ -0,0 +1,90 @@
+//@ run-pass
+//! Tests stable mir API for retrieving the body of a closure.
+
+//@ ignore-stage1
+//@ ignore-cross-compile
+//@ ignore-remote
+//@ edition: 2021
+
+#![feature(rustc_private)]
+#![feature(assert_matches)]
+
+extern crate rustc_middle;
+#[macro_use]
+extern crate rustc_smir;
+extern crate rustc_driver;
+extern crate rustc_interface;
+extern crate stable_mir;
+
+use std::io::Write;
+use std::ops::ControlFlow;
+
+use stable_mir::mir::{Body, ConstOperand, Operand, TerminatorKind};
+use stable_mir::ty::{FnDef, RigidTy, TyKind};
+
+const CRATE_NAME: &str = "crate_closure_body";
+
+fn test_closure_body() -> ControlFlow<()> {
+    let crate_items = stable_mir::all_local_items();
+    for item in crate_items {
+        let item_ty = item.ty();
+        match &item_ty.kind() {
+            TyKind::RigidTy(RigidTy::Closure(closure_def, _)) => {
+                let closure_body = closure_def.body().unwrap();
+                check_incr_closure_body(closure_body);
+            }
+            _ => {}
+        }
+    }
+
+    ControlFlow::Continue(())
+}
+
+fn check_incr_closure_body(body: Body) {
+    let first_block = &body.blocks[0];
+    let TerminatorKind::Call { func: Operand::Constant(ConstOperand { const_, .. }), .. } =
+        &first_block.terminator.kind
+    else {
+        panic!("expected Call Terminator, got: ");
+    };
+
+    let TyKind::RigidTy(RigidTy::FnDef(FnDef(def_id), ..), ..) = const_.ty().kind() else {
+        panic!("expected FnDef");
+    };
+
+    assert_eq!(def_id.name(), "id");
+}
+
+fn main() {
+    let path = "closure_body.rs";
+    generate_input(&path).unwrap();
+    let args = &[
+        "rustc".to_string(),
+        "-Cpanic=abort".to_string(),
+        "--crate-name".to_string(),
+        CRATE_NAME.to_string(),
+        path.to_string(),
+    ];
+    run!(args, test_closure_body).unwrap();
+}
+
+fn generate_input(path: &str) -> std::io::Result<()> {
+    let mut file = std::fs::File::create(path)?;
+    write!(
+        file,
+        r#"
+        fn id<T>(y: T) -> T {{
+            y
+        }}
+
+        fn main() {{
+            let cl_id= |x| {{
+                id(x)
+            }};
+
+            let _= cl_id(5);
+        }}
+    "#
+    )?;
+    Ok(())
+}
diff --git a/tests/ui-fulldeps/stable-mir/closure_body.rs b/tests/ui-fulldeps/stable-mir/closure_body.rs
new file mode 100644
index 00000000000..7ed0dabd2c3
--- /dev/null
+++ b/tests/ui-fulldeps/stable-mir/closure_body.rs
@@ -0,0 +1,90 @@
+//@ run-pass
+//! Tests stable mir API for retrieving the body of a closure.
+
+//@ ignore-stage1
+//@ ignore-cross-compile
+//@ ignore-remote
+//@ edition: 2021
+
+#![feature(rustc_private)]
+#![feature(assert_matches)]
+
+extern crate rustc_middle;
+#[macro_use]
+extern crate rustc_smir;
+extern crate rustc_driver;
+extern crate rustc_interface;
+extern crate stable_mir;
+
+use std::io::Write;
+use std::ops::ControlFlow;
+
+use stable_mir::mir::{Body, ConstOperand, Operand, TerminatorKind};
+use stable_mir::ty::{FnDef, RigidTy, TyKind};
+
+const CRATE_NAME: &str = "crate_closure_body";
+
+fn test_closure_body() -> ControlFlow<()> {
+    let crate_items = stable_mir::all_local_items();
+    for item in crate_items {
+        let item_ty = item.ty();
+        match &item_ty.kind() {
+            TyKind::RigidTy(RigidTy::Closure(closure_def, _)) => {
+                let closure_body = closure_def.body().unwrap();
+                check_incr_closure_body(closure_body);
+            }
+            _ => {}
+        }
+    }
+
+    ControlFlow::Continue(())
+}
+
+fn check_incr_closure_body(body: Body) {
+    let first_block = &body.blocks[0];
+    let TerminatorKind::Call { func: Operand::Constant(ConstOperand { const_, .. }), .. } =
+        &first_block.terminator.kind
+    else {
+        panic!("expected Call Terminator, got: ");
+    };
+
+    let TyKind::RigidTy(RigidTy::FnDef(FnDef(def_id), ..), ..) = const_.ty().kind() else {
+        panic!("expected FnDef");
+    };
+
+    assert_eq!(def_id.name(), "incr");
+}
+
+fn main() {
+    let path = "closure_body.rs";
+    generate_input(&path).unwrap();
+    let args = &[
+        "rustc".to_string(),
+        "-Cpanic=abort".to_string(),
+        "--crate-name".to_string(),
+        CRATE_NAME.to_string(),
+        path.to_string(),
+    ];
+    run!(args, test_closure_body).unwrap();
+}
+
+fn generate_input(path: &str) -> std::io::Result<()> {
+    let mut file = std::fs::File::create(path)?;
+    write!(
+        file,
+        r#"
+        fn incr(y: i32) -> i32 {{
+            y + 1
+        }}
+
+        fn main() {{
+            let cl_incr = |x: i32| {{
+                incr(x)
+            }};
+
+            let _= cl_incr(5);
+        }}
+    "#
+    )?;
+    Ok(())
+}
diff --git a/tests/ui/abi/bad-custom.rs b/tests/ui/abi/bad-custom.rs
new file mode 100644
index 00000000000..e792f0955b9
--- /dev/null
+++ b/tests/ui/abi/bad-custom.rs
@@ -0,0 +1,121 @@
+//@ edition: 2021
+//@ check-fail
+//@ needs-asm-support
+#![feature(abi_custom)]
+
+#[unsafe(naked)]
+extern "custom" fn must_be_unsafe(a: i64) -> i64 {
+    //~^ ERROR functions with the `"custom"` ABI must be unsafe
+    //~| ERROR invalid signature for `extern "custom"` function
+    std::arch::naked_asm!("")
+}
+
+#[unsafe(naked)]
+unsafe extern "custom" fn no_parameters(a: i64) {
+    //~^ ERROR invalid signature for `extern "custom"` function
+    std::arch::naked_asm!("")
+}
+
+#[unsafe(naked)]
+unsafe extern "custom" fn no_return_type() -> i64 {
+    //~^ ERROR invalid signature for `extern "custom"` function
+    std::arch::naked_asm!("")
+}
+
+unsafe extern "custom" fn double(a: i64) -> i64 {
+    //~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions
+    //~| ERROR invalid signature for `extern "custom"` function
+    unimplemented!()
+}
+
+struct Thing(i64);
+
+impl Thing {
+    unsafe extern "custom" fn is_even(self) -> bool {
+        //~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions
+        //~| ERROR invalid signature for `extern "custom"` function
+        unimplemented!()
+    }
+}
+
+trait BitwiseNot {
+    unsafe extern "custom" fn bitwise_not(a: i64) -> i64 {
+        //~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions
+        //~| ERROR invalid signature for `extern "custom"` function
+        unimplemented!()
+    }
+}
+
+impl BitwiseNot for Thing {}
+
+trait Negate {
+    extern "custom" fn negate(a: i64) -> i64;
+    //~^ ERROR functions with the `"custom"` ABI must be unsafe
+    //~| ERROR invalid signature for `extern "custom"` function
+}
+
+impl Negate for Thing {
+    extern "custom" fn negate(a: i64) -> i64 {
+        //~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions
+        //~| ERROR functions with the `"custom"` ABI must be unsafe
+        //~| ERROR invalid signature for `extern "custom"` function
+        -a
+    }
+}
+
+unsafe extern "custom" {
+    fn increment(a: i64) -> i64;
+    //~^ ERROR invalid signature for `extern "custom"` function
+
+    safe fn extern_cannot_be_safe();
+    //~^ ERROR foreign functions with the `"custom"` ABI cannot be safe
+}
+
+fn caller(f: unsafe extern "custom" fn(i64) -> i64, mut x: i64) -> i64 {
+    unsafe { f(x) }
+    //~^ ERROR functions with the `"custom"` ABI cannot be called
+}
+
+fn caller_by_ref(f: &unsafe extern "custom" fn(i64) -> i64, mut x: i64) -> i64 {
+    unsafe { f(x) }
+    //~^ ERROR functions with the `"custom"` ABI cannot be called
+}
+
+type Custom = unsafe extern "custom" fn(i64) -> i64;
+
+fn caller_alias(f: Custom, mut x: i64) -> i64 {
+    unsafe { f(x) }
+    //~^ ERROR functions with the `"custom"` ABI cannot be called
+}
+
+#[unsafe(naked)]
+const unsafe extern "custom" fn no_const_fn() {
+    std::arch::naked_asm!("")
+    //~^ ERROR inline assembly is not allowed in constant functions
+}
+
+async unsafe extern "custom" fn no_async_fn() {
+    //~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions
+    //~| ERROR functions with the `"custom"` ABI cannot be `async`
+}
+
+fn no_promotion_to_fn_trait(f: unsafe extern "custom" fn()) -> impl Fn()  {
+    //~^ ERROR expected a `Fn()` closure, found `unsafe extern "custom" fn()`
+    f
+}
+
+pub fn main() {
+    unsafe {
+        assert_eq!(double(21), 42);
+        //~^ ERROR functions with the `"custom"` ABI cannot be called
+
+        assert_eq!(unsafe { increment(41) }, 42);
+        //~^ ERROR functions with the `"custom"` ABI cannot be called
+
+        assert!(Thing(41).is_even());
+        //~^ ERROR functions with the `"custom"` ABI cannot be called
+
+        assert_eq!(Thing::bitwise_not(42), !42);
+        //~^ ERROR functions with the `"custom"` ABI cannot be called
+    }
+}
diff --git a/tests/ui/abi/bad-custom.stderr b/tests/ui/abi/bad-custom.stderr
new file mode 100644
index 00000000000..ec0f11af898
--- /dev/null
+++ b/tests/ui/abi/bad-custom.stderr
@@ -0,0 +1,299 @@
+error: functions with the `"custom"` ABI must be unsafe
+  --> $DIR/bad-custom.rs:7:1
+   |
+LL | extern "custom" fn must_be_unsafe(a: i64) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: add the `unsafe` keyword to this definition
+   |
+LL | unsafe extern "custom" fn must_be_unsafe(a: i64) -> i64 {
+   | ++++++
+
+error: invalid signature for `extern "custom"` function
+  --> $DIR/bad-custom.rs:7:35
+   |
+LL | extern "custom" fn must_be_unsafe(a: i64) -> i64 {
+   |                                   ^^^^^^     ^^^
+   |
+   = note: functions with the `"custom"` ABI cannot have any parameters or return type
+help: remove the parameters and return type
+   |
+LL - extern "custom" fn must_be_unsafe(a: i64) -> i64 {
+LL + extern "custom" fn must_be_unsafe() {
+   |
+
+error: invalid signature for `extern "custom"` function
+  --> $DIR/bad-custom.rs:14:41
+   |
+LL | unsafe extern "custom" fn no_parameters(a: i64) {
+   |                                         ^^^^^^
+   |
+   = note: functions with the `"custom"` ABI cannot have any parameters or return type
+help: remove the parameters and return type
+   |
+LL - unsafe extern "custom" fn no_parameters(a: i64) {
+LL + unsafe extern "custom" fn no_parameters() {
+   |
+
+error: invalid signature for `extern "custom"` function
+  --> $DIR/bad-custom.rs:20:47
+   |
+LL | unsafe extern "custom" fn no_return_type() -> i64 {
+   |                                               ^^^
+   |
+   = note: functions with the `"custom"` ABI cannot have any parameters or return type
+help: remove the parameters and return type
+   |
+LL - unsafe extern "custom" fn no_return_type() -> i64 {
+LL + unsafe extern "custom" fn no_return_type() {
+   |
+
+error: invalid signature for `extern "custom"` function
+  --> $DIR/bad-custom.rs:25:34
+   |
+LL | unsafe extern "custom" fn double(a: i64) -> i64 {
+   |                                  ^^^^^^     ^^^
+   |
+   = note: functions with the `"custom"` ABI cannot have any parameters or return type
+help: remove the parameters and return type
+   |
+LL - unsafe extern "custom" fn double(a: i64) -> i64 {
+LL + unsafe extern "custom" fn double() {
+   |
+
+error: invalid signature for `extern "custom"` function
+  --> $DIR/bad-custom.rs:34:39
+   |
+LL |     unsafe extern "custom" fn is_even(self) -> bool {
+   |                                       ^^^^     ^^^^
+   |
+   = note: functions with the `"custom"` ABI cannot have any parameters or return type
+help: remove the parameters and return type
+   |
+LL -     unsafe extern "custom" fn is_even(self) -> bool {
+LL +     unsafe extern "custom" fn is_even() {
+   |
+
+error: invalid signature for `extern "custom"` function
+  --> $DIR/bad-custom.rs:42:43
+   |
+LL |     unsafe extern "custom" fn bitwise_not(a: i64) -> i64 {
+   |                                           ^^^^^^     ^^^
+   |
+   = note: functions with the `"custom"` ABI cannot have any parameters or return type
+help: remove the parameters and return type
+   |
+LL -     unsafe extern "custom" fn bitwise_not(a: i64) -> i64 {
+LL +     unsafe extern "custom" fn bitwise_not() {
+   |
+
+error: functions with the `"custom"` ABI must be unsafe
+  --> $DIR/bad-custom.rs:52:5
+   |
+LL |     extern "custom" fn negate(a: i64) -> i64;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: add the `unsafe` keyword to this definition
+   |
+LL |     unsafe extern "custom" fn negate(a: i64) -> i64;
+   |     ++++++
+
+error: invalid signature for `extern "custom"` function
+  --> $DIR/bad-custom.rs:52:31
+   |
+LL |     extern "custom" fn negate(a: i64) -> i64;
+   |                               ^^^^^^     ^^^
+   |
+   = note: functions with the `"custom"` ABI cannot have any parameters or return type
+help: remove the parameters and return type
+   |
+LL -     extern "custom" fn negate(a: i64) -> i64;
+LL +     extern "custom" fn negate();
+   |
+
+error: functions with the `"custom"` ABI must be unsafe
+  --> $DIR/bad-custom.rs:58:5
+   |
+LL |     extern "custom" fn negate(a: i64) -> i64 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: add the `unsafe` keyword to this definition
+   |
+LL |     unsafe extern "custom" fn negate(a: i64) -> i64 {
+   |     ++++++
+
+error: invalid signature for `extern "custom"` function
+  --> $DIR/bad-custom.rs:58:31
+   |
+LL |     extern "custom" fn negate(a: i64) -> i64 {
+   |                               ^^^^^^     ^^^
+   |
+   = note: functions with the `"custom"` ABI cannot have any parameters or return type
+help: remove the parameters and return type
+   |
+LL -     extern "custom" fn negate(a: i64) -> i64 {
+LL +     extern "custom" fn negate() {
+   |
+
+error: invalid signature for `extern "custom"` function
+  --> $DIR/bad-custom.rs:67:18
+   |
+LL |     fn increment(a: i64) -> i64;
+   |                  ^^^^^^     ^^^
+   |
+   = note: functions with the `"custom"` ABI cannot have any parameters or return type
+help: remove the parameters and return type
+   |
+LL -     fn increment(a: i64) -> i64;
+LL +     fn increment();
+   |
+
+error: foreign functions with the `"custom"` ABI cannot be safe
+  --> $DIR/bad-custom.rs:70:5
+   |
+LL |     safe fn extern_cannot_be_safe();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `safe` keyword from this definition
+   |
+LL -     safe fn extern_cannot_be_safe();
+LL +     fn extern_cannot_be_safe();
+   |
+
+error: functions with the `"custom"` ABI cannot be `async`
+  --> $DIR/bad-custom.rs:97:1
+   |
+LL | async unsafe extern "custom" fn no_async_fn() {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: remove the `async` keyword from this definiton
+   |
+LL - async unsafe extern "custom" fn no_async_fn() {
+LL + unsafe extern "custom" fn no_async_fn() {
+   |
+
+error: items with the `"custom"` ABI can only be declared externally or defined via naked functions
+  --> $DIR/bad-custom.rs:97:1
+   |
+LL | async unsafe extern "custom" fn no_async_fn() {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: convert this to an `#[unsafe(naked)]` function
+   |
+LL + #[unsafe(naked)]
+LL | async unsafe extern "custom" fn no_async_fn() {
+   |
+
+error[E0277]: expected a `Fn()` closure, found `unsafe extern "custom" fn()`
+  --> $DIR/bad-custom.rs:102:64
+   |
+LL | fn no_promotion_to_fn_trait(f: unsafe extern "custom" fn()) -> impl Fn()  {
+   |                                                                ^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }`
+LL |
+LL |     f
+   |     - return type was inferred to be `unsafe extern "custom" fn()` here
+   |
+   = help: the trait `Fn()` is not implemented for `unsafe extern "custom" fn()`
+   = note: unsafe function cannot be called generically without an unsafe block
+   = note: wrap the `unsafe extern "custom" fn()` in a closure with no arguments: `|| { /* code */ }`
+
+error: items with the `"custom"` ABI can only be declared externally or defined via naked functions
+  --> $DIR/bad-custom.rs:25:1
+   |
+LL | unsafe extern "custom" fn double(a: i64) -> i64 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: convert this to an `#[unsafe(naked)]` function
+   |
+LL + #[unsafe(naked)]
+LL | unsafe extern "custom" fn double(a: i64) -> i64 {
+   |
+
+error: items with the `"custom"` ABI can only be declared externally or defined via naked functions
+  --> $DIR/bad-custom.rs:34:5
+   |
+LL |     unsafe extern "custom" fn is_even(self) -> bool {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: convert this to an `#[unsafe(naked)]` function
+   |
+LL +     #[unsafe(naked)]
+LL |     unsafe extern "custom" fn is_even(self) -> bool {
+   |
+
+error: items with the `"custom"` ABI can only be declared externally or defined via naked functions
+  --> $DIR/bad-custom.rs:42:5
+   |
+LL |     unsafe extern "custom" fn bitwise_not(a: i64) -> i64 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: convert this to an `#[unsafe(naked)]` function
+   |
+LL +     #[unsafe(naked)]
+LL |     unsafe extern "custom" fn bitwise_not(a: i64) -> i64 {
+   |
+
+error: items with the `"custom"` ABI can only be declared externally or defined via naked functions
+  --> $DIR/bad-custom.rs:58:5
+   |
+LL |     extern "custom" fn negate(a: i64) -> i64 {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: convert this to an `#[unsafe(naked)]` function
+   |
+LL +     #[unsafe(naked)]
+LL |     extern "custom" fn negate(a: i64) -> i64 {
+   |
+
+error: functions with the `"custom"` ABI cannot be called
+  --> $DIR/bad-custom.rs:75:14
+   |
+LL |     unsafe { f(x) }
+   |              ^^^^
+
+error: functions with the `"custom"` ABI cannot be called
+  --> $DIR/bad-custom.rs:80:14
+   |
+LL |     unsafe { f(x) }
+   |              ^^^^
+
+error: functions with the `"custom"` ABI cannot be called
+  --> $DIR/bad-custom.rs:87:14
+   |
+LL |     unsafe { f(x) }
+   |              ^^^^
+
+error: functions with the `"custom"` ABI cannot be called
+  --> $DIR/bad-custom.rs:109:20
+   |
+LL |         assert_eq!(double(21), 42);
+   |                    ^^^^^^^^^^
+
+error: functions with the `"custom"` ABI cannot be called
+  --> $DIR/bad-custom.rs:112:29
+   |
+LL |         assert_eq!(unsafe { increment(41) }, 42);
+   |                             ^^^^^^^^^^^^^
+
+error: functions with the `"custom"` ABI cannot be called
+  --> $DIR/bad-custom.rs:115:17
+   |
+LL |         assert!(Thing(41).is_even());
+   |                 ^^^^^^^^^^^^^^^^^^^
+
+error: functions with the `"custom"` ABI cannot be called
+  --> $DIR/bad-custom.rs:118:20
+   |
+LL |         assert_eq!(Thing::bitwise_not(42), !42);
+   |                    ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0015]: inline assembly is not allowed in constant functions
+  --> $DIR/bad-custom.rs:93:5
+   |
+LL |     std::arch::naked_asm!("")
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 28 previous errors
+
+Some errors have detailed explanations: E0015, E0277.
+For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/abi/custom.rs b/tests/ui/abi/custom.rs
new file mode 100644
index 00000000000..0f6ff77f580
--- /dev/null
+++ b/tests/ui/abi/custom.rs
@@ -0,0 +1,88 @@
+// Test that `extern "custom"` functions can be called from assembly, and defined using a naked
+// function, and `global_asm!` with an `extern "custom"` block.
+//
+//@ run-pass
+//@ only-x86_64
+#![feature(abi_custom)]
+
+use std::arch::{asm, global_asm, naked_asm};
+
+#[unsafe(naked)]
+unsafe extern "custom" fn double() {
+    naked_asm!("add rax, rax", "ret");
+}
+
+global_asm!(
+    // work around macOS prefixing symbols with _
+    "    .globl  {0}",
+    "{0}:",
+    "    add     rax, 1",
+    "    ret",
+    sym increment,
+);
+
+unsafe extern "custom" {
+    fn increment();
+}
+
+#[repr(transparent)]
+struct Thing(u64);
+
+impl Thing {
+    #[unsafe(naked)]
+    unsafe extern "custom" fn is_even() {
+        naked_asm!("test al, 1", "sete al", "ret");
+    }
+}
+
+trait BitwiseNot {
+    #[unsafe(naked)]
+    unsafe extern "custom" fn bitwise_not() {
+        naked_asm!("not rax", "ret");
+    }
+}
+
+impl BitwiseNot for Thing {}
+
+#[unsafe(naked)]
+unsafe extern "C" fn const_generic<const N: u64>() {
+    naked_asm!(
+        "mov rax, {}",
+        "ret",
+        const N,
+    );
+}
+
+pub fn main() {
+    let mut x: u64 = 21;
+    unsafe { asm!("call {}", sym double, inout("rax") x) };
+    assert_eq!(x, 42);
+
+    let mut x: u64 = 41;
+    unsafe { asm!("call {}", sym increment, inout("rax") x) };
+    assert_eq!(x, 42);
+
+    let mut x: u8;
+    unsafe { asm!("call {}", sym Thing::is_even, inout("al") 42u8 => x) };
+    assert!(x != 0);
+
+    let mut x: u64 = 42;
+    unsafe { asm!("call {}", sym Thing::bitwise_not, inout("rax") x) };
+    assert_eq!(x, !42);
+
+    // Create and call in `asm!` an `extern "custom"` function pointer.
+    fn caller(f: unsafe extern "custom" fn(), mut x: u64) -> u64 {
+        unsafe { asm!("call {}", in(reg) f, inout("rax") x) };
+        x
+    }
+
+    assert_eq!(caller(double, 2), 4);
+
+    let x: u64;
+    unsafe { asm!("call {}", sym const_generic::<42>, out("rax") x) };
+    assert_eq!(x, 42);
+
+    let x: u64;
+    unsafe { asm!("call {}", sym const_generic::<84>, out("rax") x) };
+    assert_eq!(x, 84);
+}
diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr
index ea645780b0d..4721c26026d 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,43 +369,8 @@ 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
-   |
-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
-
-Future breakage diagnostic:
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:134:1
-   |
-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
-
-Future breakage diagnostic:
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:137:1
-   |
-LL | extern "cdecl-unwind" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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-unwind"` instead
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
-
-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 +381,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 +392,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()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -435,15 +401,3 @@ 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>
    = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
 
-Future breakage diagnostic:
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:126:1
-   |
-LL | extern "cdecl" fn 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
-
diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr
index 2c82e2951e2..ed9cd2ab2c5 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,43 +337,8 @@ 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
-   |
-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
-
-Future breakage diagnostic:
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:134:1
-   |
-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
-
-Future breakage diagnostic:
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:137:1
-   |
-LL | extern "cdecl-unwind" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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-unwind"` instead
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
-
-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 +349,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 +360,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()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -403,15 +369,3 @@ 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>
    = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
 
-Future breakage diagnostic:
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:126:1
-   |
-LL | extern "cdecl" fn 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
-
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..9e75dfafca0 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,43 +337,8 @@ 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
-   |
-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
-
-Future breakage diagnostic:
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:134:1
-   |
-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
-
-Future breakage diagnostic:
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:137:1
-   |
-LL | extern "cdecl-unwind" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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-unwind"` instead
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
-
-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 +349,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 +360,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()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -403,15 +369,3 @@ 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>
    = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
 
-Future breakage diagnostic:
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:126:1
-   |
-LL | extern "cdecl" fn 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
-
diff --git a/tests/ui/abi/unsupported.riscv64.stderr b/tests/ui/abi/unsupported.riscv64.stderr
index a0e2901c759..9e75dfafca0 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,43 +337,8 @@ 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
-   |
-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
-
-Future breakage diagnostic:
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:134:1
-   |
-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
-
-Future breakage diagnostic:
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:137:1
-   |
-LL | extern "cdecl-unwind" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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-unwind"` instead
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
-
-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 +349,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 +360,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()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -403,15 +369,3 @@ 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>
    = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
 
-Future breakage diagnostic:
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:126:1
-   |
-LL | extern "cdecl" fn 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
-
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..5b55e5707fa 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,43 +316,8 @@ 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
-   |
-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
-
-Future breakage diagnostic:
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:134:1
-   |
-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
-
-Future breakage diagnostic:
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:137:1
-   |
-LL | extern "cdecl-unwind" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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-unwind"` instead
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
-
-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 +328,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()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -371,15 +337,3 @@ 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>
    = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
 
-Future breakage diagnostic:
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:126:1
-   |
-LL | extern "cdecl" fn 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
-
diff --git a/tests/ui/abi/unsupported.x64_win.stderr b/tests/ui/abi/unsupported.x64_win.stderr
index 5597440d5d9..93b5a272e92 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,78 +322,8 @@ 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
-  --> $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
-
-Future breakage diagnostic:
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:117:1
-   |
-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
-
-Future breakage diagnostic:
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:121:1
-   |
-LL | extern "stdcall-unwind" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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-unwind"` on win32 and `extern "C-unwind"` everywhere else, use `extern "system-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
-   |
-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
-
-Future breakage diagnostic:
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:134:1
-   |
-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
-
-Future breakage diagnostic:
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:137:1
-   |
-LL | extern "cdecl-unwind" {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = 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-unwind"` instead
-   = note: `#[warn(unsupported_calling_conventions)]` on by default
-
-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 +334,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()) {
    |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -411,39 +343,3 @@ 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>
    = note: `#[warn(unsupported_fn_ptr_calling_conventions)]` on by default
 
-Future breakage diagnostic:
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:169:1
-   |
-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
-
-Future breakage diagnostic:
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:108:1
-   |
-LL | extern "stdcall" fn 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
-
-Future breakage diagnostic:
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:126:1
-   |
-LL | extern "cdecl" fn 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
-
diff --git a/tests/ui/async-await/async-block-control-flow-static-semantics.stderr b/tests/ui/async-await/async-block-control-flow-static-semantics.stderr
index 4ed15a942c6..b64690bae6c 100644
--- a/tests/ui/async-await/async-block-control-flow-static-semantics.stderr
+++ b/tests/ui/async-await/async-block-control-flow-static-semantics.stderr
@@ -1,19 +1,3 @@
-error[E0267]: `break` inside `async` block
-  --> $DIR/async-block-control-flow-static-semantics.rs:32:9
-   |
-LL |     async {
-   |     ----- enclosing `async` block
-LL |         break 0u8;
-   |         ^^^^^^^^^ cannot `break` inside `async` block
-
-error[E0267]: `break` inside `async` block
-  --> $DIR/async-block-control-flow-static-semantics.rs:39:13
-   |
-LL |         async {
-   |         ----- enclosing `async` block
-LL |             break 0u8;
-   |             ^^^^^^^^^ cannot `break` inside `async` block
-
 error[E0308]: mismatched types
   --> $DIR/async-block-control-flow-static-semantics.rs:21:58
    |
@@ -50,6 +34,22 @@ LL |     let _: &dyn Future<Output = ()> = &block;
    |
    = note: required for the cast from `&{async block@$DIR/async-block-control-flow-static-semantics.rs:14:17: 14:22}` to `&dyn Future<Output = ()>`
 
+error[E0267]: `break` inside `async` block
+  --> $DIR/async-block-control-flow-static-semantics.rs:32:9
+   |
+LL |     async {
+   |     ----- enclosing `async` block
+LL |         break 0u8;
+   |         ^^^^^^^^^ cannot `break` inside `async` block
+
+error[E0267]: `break` inside `async` block
+  --> $DIR/async-block-control-flow-static-semantics.rs:39:13
+   |
+LL |         async {
+   |         ----- enclosing `async` block
+LL |             break 0u8;
+   |             ^^^^^^^^^ cannot `break` inside `async` block
+
 error[E0308]: mismatched types
   --> $DIR/async-block-control-flow-static-semantics.rs:49:44
    |
diff --git a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr
index 329cec6dad3..b7259074bf6 100644
--- a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr
+++ b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr
@@ -106,11 +106,13 @@ LL | }
 error[E0621]: explicit lifetime required in the type of `x`
   --> $DIR/without-precise-captures-we-are-powerless.rs:38:5
    |
-LL | fn through_field_and_ref<'a>(x: &S<'a>) {
-   |                                 ------ help: add explicit lifetime `'a` to the type of `x`: `&'a S<'a>`
-...
 LL |     outlives::<'a>(call_once(c));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to the type of `x`
+   |
+LL | fn through_field_and_ref<'a>(x: &'a S<'a>) {
+   |                                  ++
 
 error[E0597]: `c` does not live long enough
   --> $DIR/without-precise-captures-we-are-powerless.rs:43:20
@@ -131,11 +133,13 @@ LL | }
 error[E0621]: explicit lifetime required in the type of `x`
   --> $DIR/without-precise-captures-we-are-powerless.rs:44:5
    |
-LL | fn through_field_and_ref_move<'a>(x: &S<'a>) {
-   |                                      ------ help: add explicit lifetime `'a` to the type of `x`: `&'a S<'a>`
-...
 LL |     outlives::<'a>(call_once(c));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to the type of `x`
+   |
+LL | fn through_field_and_ref_move<'a>(x: &'a S<'a>) {
+   |                                       ++
 
 error: aborting due to 10 previous errors
 
diff --git a/tests/ui/async-await/issues/issue-63388-1.stderr b/tests/ui/async-await/issues/issue-63388-1.stderr
index 277f7fa6f63..a59fe7dbc20 100644
--- a/tests/ui/async-await/issues/issue-63388-1.stderr
+++ b/tests/ui/async-await/issues/issue-63388-1.stderr
@@ -1,11 +1,14 @@
 error[E0621]: explicit lifetime required in the type of `foo`
   --> $DIR/issue-63388-1.rs:14:9
    |
-LL |         &'a self, foo: &dyn Foo
-   |                        -------- help: add explicit lifetime `'a` to the type of `foo`: `&'a (dyn Foo + 'a)`
-...
 LL |         foo
    |         ^^^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to the type of `foo`
+   |
+LL -         &'a self, foo: &dyn Foo
+LL +         &'a self, foo: &'a (dyn Foo + 'a)
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/auxiliary/typeid-intrinsic-aux1.rs b/tests/ui/auxiliary/typeid-intrinsic-aux1.rs
index 281c079682f..a028008c6ae 100644
--- a/tests/ui/auxiliary/typeid-intrinsic-aux1.rs
+++ b/tests/ui/auxiliary/typeid-intrinsic-aux1.rs
@@ -9,9 +9,9 @@ pub struct E(Result<&'static str, isize>);
 pub type F = Option<isize>;
 pub type G = usize;
 pub type H = &'static str;
-pub type I = Box<Fn()>;
-pub type I32Iterator = Iterator<Item=i32>;
-pub type U32Iterator = Iterator<Item=u32>;
+pub type I = Box<dyn Fn()>;
+pub type I32Iterator = dyn Iterator<Item=i32>;
+pub type U32Iterator = dyn Iterator<Item=u32>;
 
 pub fn id_A() -> TypeId { TypeId::of::<A>() }
 pub fn id_B() -> TypeId { TypeId::of::<B>() }
diff --git a/tests/ui/auxiliary/typeid-intrinsic-aux2.rs b/tests/ui/auxiliary/typeid-intrinsic-aux2.rs
index 281c079682f..a028008c6ae 100644
--- a/tests/ui/auxiliary/typeid-intrinsic-aux2.rs
+++ b/tests/ui/auxiliary/typeid-intrinsic-aux2.rs
@@ -9,9 +9,9 @@ pub struct E(Result<&'static str, isize>);
 pub type F = Option<isize>;
 pub type G = usize;
 pub type H = &'static str;
-pub type I = Box<Fn()>;
-pub type I32Iterator = Iterator<Item=i32>;
-pub type U32Iterator = Iterator<Item=u32>;
+pub type I = Box<dyn Fn()>;
+pub type I32Iterator = dyn Iterator<Item=i32>;
+pub type U32Iterator = dyn Iterator<Item=u32>;
 
 pub fn id_A() -> TypeId { TypeId::of::<A>() }
 pub fn id_B() -> TypeId { TypeId::of::<B>() }
diff --git a/tests/ui/box/empty-alloc-deref-rvalue.rs b/tests/ui/box/empty-alloc-deref-rvalue.rs
new file mode 100644
index 00000000000..507a753467a
--- /dev/null
+++ b/tests/ui/box/empty-alloc-deref-rvalue.rs
@@ -0,0 +1,10 @@
+//! Smoke test: dereferencing boxed zero-sized types (ZSTs) should not crash.
+//!
+//! Originally a regression test of github.com/rust-lang/rust/issues/13360
+//! but repurposed for a smoke test.
+
+//@ run-pass
+
+pub fn main() {
+    let _: () = *Box::new(());
+}
diff --git a/tests/ui/filter-block-view-items.rs b/tests/ui/cfg/cfg-false-use-item.rs
index cb599c27264..d37b48cdedb 100644
--- a/tests/ui/filter-block-view-items.rs
+++ b/tests/ui/cfg/cfg-false-use-item.rs
@@ -1,3 +1,5 @@
+//! Test that use items with cfg(false) are properly filtered out
+
 //@ run-pass
 
 pub fn main() {
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/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr
index ec81ba2e3d8..f29a41d6a8e 100644
--- a/tests/ui/check-cfg/target_feature.stderr
+++ b/tests/ui/check-cfg/target_feature.stderr
@@ -212,6 +212,9 @@ LL |     cfg!(target_feature = "_UNEXPECTED_VALUE");
 `relax`
 `relaxed-simd`
 `reserve-x18`
+`retpoline-external-thunk`
+`retpoline-indirect-branches`
+`retpoline-indirect-calls`
 `rtm`
 `sb`
 `scq`
diff --git a/tests/ui/const-generics/const-arg-in-const-arg.min.stderr b/tests/ui/const-generics/const-arg-in-const-arg.min.stderr
index 16512cb69e2..ebb3e821e07 100644
--- a/tests/ui/const-generics/const-arg-in-const-arg.min.stderr
+++ b/tests/ui/const-generics/const-arg-in-const-arg.min.stderr
@@ -13,7 +13,7 @@ error: generic parameters may not be used in const operations
 LL |     let _: [u8; bar::<N>()];
    |                       ^ cannot perform const operation using `N`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
@@ -58,7 +58,7 @@ error: generic parameters may not be used in const operations
 LL |     let _ = [0; bar::<N>()];
    |                       ^ cannot perform const operation using `N`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
@@ -112,7 +112,7 @@ error: generic parameters may not be used in const operations
 LL |     let _: Foo<{ bar::<N>() }>;
    |                        ^ cannot perform const operation using `N`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
@@ -166,7 +166,7 @@ error: generic parameters may not be used in const operations
 LL |     let _ = Foo::<{ bar::<N>() }>;
    |                           ^ cannot perform const operation using `N`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
diff --git a/tests/ui/const-generics/defaults/complex-generic-default-expr.min.stderr b/tests/ui/const-generics/defaults/complex-generic-default-expr.min.stderr
index 199546c0883..e41e488371a 100644
--- a/tests/ui/const-generics/defaults/complex-generic-default-expr.min.stderr
+++ b/tests/ui/const-generics/defaults/complex-generic-default-expr.min.stderr
@@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations
 LL | struct Foo<const N: usize, const M: usize = { N + 1 }>;
    |                                               ^ cannot perform const operation using `N`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
diff --git a/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-4.stderr b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-4.stderr
index 4722968b203..a1aee041b1f 100644
--- a/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-4.stderr
+++ b/tests/ui/const-generics/early/const_arg_trivial_macro_expansion-4.stderr
@@ -7,7 +7,7 @@ LL |         N
 LL | fn foo<const N: usize>() -> Foo<{ arg!{} arg!{} }> { loop {} }
    |                                   ------ in this macro invocation
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
    = note: this error originates in the macro `arg` (in Nightly builds, run with -Z macro-backtrace for more info)
 
@@ -20,7 +20,7 @@ LL |         N
 LL | fn foo<const N: usize>() -> Foo<{ arg!{} arg!{} }> { loop {} }
    |                                          ------ in this macro invocation
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
    = note: this error originates in the macro `arg` (in Nightly builds, run with -Z macro-backtrace for more info)
 
@@ -30,7 +30,7 @@ error: generic parameters may not be used in const operations
 LL | fn bar<const N: usize>() -> [(); { empty!{}; N }] { loop {} }
    |                                              ^ cannot perform const operation using `N`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: aborting due to 3 previous errors
diff --git a/tests/ui/const-generics/early/macro_rules-braces.stderr b/tests/ui/const-generics/early/macro_rules-braces.stderr
index 32695066801..30efa18982b 100644
--- a/tests/ui/const-generics/early/macro_rules-braces.stderr
+++ b/tests/ui/const-generics/early/macro_rules-braces.stderr
@@ -26,7 +26,7 @@ error: generic parameters may not be used in const operations
 LL |     let _: foo!({{ N }});
    |                    ^ cannot perform const operation using `N`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
@@ -35,7 +35,7 @@ error: generic parameters may not be used in const operations
 LL |     let _: bar!({ N });
    |                   ^ cannot perform const operation using `N`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
@@ -44,7 +44,7 @@ error: generic parameters may not be used in const operations
 LL |     let _: baz!({{ N }});
    |                    ^ cannot perform const operation using `N`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
@@ -53,7 +53,7 @@ error: generic parameters may not be used in const operations
 LL |     let _: biz!({ N });
    |                   ^ cannot perform const operation using `N`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: aborting due to 6 previous errors
diff --git a/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces-2.stderr b/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces-2.stderr
index e40d05924b1..d68715b4d8b 100644
--- a/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces-2.stderr
+++ b/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces-2.stderr
@@ -7,7 +7,7 @@ LL |         N
 LL | fn foo<const N: usize>() -> A<{{ y!() }}> {
    |                                  ---- in this macro invocation
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
    = note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces.stderr b/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces.stderr
index b91d6c7a024..1171b359f17 100644
--- a/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces.stderr
+++ b/tests/ui/const-generics/early/trivial-const-arg-macro-nested-braces.stderr
@@ -7,7 +7,7 @@ LL |         { N }
 LL | fn foo<const N: usize>() -> A<{ y!() }> {
    |                                 ---- in this macro invocation
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
    = note: this error originates in the macro `y` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/const-generics/early/trivial-const-arg-nested-braces.stderr b/tests/ui/const-generics/early/trivial-const-arg-nested-braces.stderr
index d60516ba4bc..b812e3333d9 100644
--- a/tests/ui/const-generics/early/trivial-const-arg-nested-braces.stderr
+++ b/tests/ui/const-generics/early/trivial-const-arg-nested-braces.stderr
@@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations
 LL | fn foo<const N: usize>() -> A<{ { N } }> {
    |                                   ^ cannot perform const operation using `N`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr b/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr
index a8b6f06ab1c..1f93c4f8909 100644
--- a/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/array-size-in-generic-struct-param.min.stderr
@@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations
 LL | struct ArithArrayLen<const N: usize>([u32; 0 + N]);
    |                                                ^ cannot perform const operation using `N`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
@@ -13,7 +13,7 @@ error: generic parameters may not be used in const operations
 LL |     arr: [u8; CFG.arr_size],
    |               ^^^ cannot perform const operation using `CFG`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `CFG`
+   = help: const parameters may only be used as standalone arguments here, i.e. `CFG`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: `Config` is forbidden as the type of a const generic parameter
diff --git a/tests/ui/const-generics/generic_const_exprs/bad-multiply.stderr b/tests/ui/const-generics/generic_const_exprs/bad-multiply.stderr
index a8d6cebabe7..7719831e20c 100644
--- a/tests/ui/const-generics/generic_const_exprs/bad-multiply.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/bad-multiply.stderr
@@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations
 LL |     SmallVec<{ D * 2 }>:,
    |                ^ cannot perform const operation using `D`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `D`
+   = help: const parameters may only be used as standalone arguments here, i.e. `D`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error[E0747]: constant provided when a type was expected
diff --git a/tests/ui/const-generics/generic_const_exprs/feature-gate-generic_const_exprs.stderr b/tests/ui/const-generics/generic_const_exprs/feature-gate-generic_const_exprs.stderr
index 9c4e3d8583c..3208bbbd86b 100644
--- a/tests/ui/const-generics/generic_const_exprs/feature-gate-generic_const_exprs.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/feature-gate-generic_const_exprs.stderr
@@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations
 LL | type Arr<const N: usize> = [u8; N - 1];
    |                                 ^ cannot perform const operation using `N`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-72787.min.stderr b/tests/ui/const-generics/generic_const_exprs/issue-72787.min.stderr
index 2454b311921..cccf6dc6ae0 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-72787.min.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/issue-72787.min.stderr
@@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations
 LL |     Condition<{ LHS <= RHS }>: True
    |                 ^^^ cannot perform const operation using `LHS`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `LHS`
+   = help: const parameters may only be used as standalone arguments here, i.e. `LHS`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
@@ -13,7 +13,7 @@ error: generic parameters may not be used in const operations
 LL |     Condition<{ LHS <= RHS }>: True
    |                        ^^^ cannot perform const operation using `RHS`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `RHS`
+   = help: const parameters may only be used as standalone arguments here, i.e. `RHS`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
@@ -22,7 +22,7 @@ error: generic parameters may not be used in const operations
 LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
    |                         ^ cannot perform const operation using `I`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `I`
+   = help: const parameters may only be used as standalone arguments here, i.e. `I`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
@@ -31,7 +31,7 @@ error: generic parameters may not be used in const operations
 LL |     IsLessOrEqual<{ 8 - I }, { 8 - J }>: True,
    |                                    ^ cannot perform const operation using `J`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `J`
+   = help: const parameters may only be used as standalone arguments here, i.e. `J`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: aborting due to 4 previous errors
diff --git a/tests/ui/const-generics/generic_const_exprs/issue-72819-generic-in-const-eval.min.stderr b/tests/ui/const-generics/generic_const_exprs/issue-72819-generic-in-const-eval.min.stderr
index c504464127a..f91a2a30286 100644
--- a/tests/ui/const-generics/generic_const_exprs/issue-72819-generic-in-const-eval.min.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/issue-72819-generic-in-const-eval.min.stderr
@@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations
 LL | where Assert::<{N < usize::MAX / 2}>: IsTrue,
    |                 ^ cannot perform const operation using `N`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.full.stderr b/tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.full.stderr
new file mode 100644
index 00000000000..586ac63016c
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.full.stderr
@@ -0,0 +1,13 @@
+error: unconstrained generic constant
+  --> $DIR/trivial-anon-const-use-cases.rs:14:12
+   |
+LL |     stuff: [u8; { S + 1 }], // `S + 1` is NOT a valid const expression in this context.
+   |            ^^^^^^^^^^^^^^^
+   |
+help: try adding a `where` bound
+   |
+LL | struct Y<const S: usize> where [(); { S + 1 }]: {
+   |                          ++++++++++++++++++++++
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.min.stderr b/tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.min.stderr
new file mode 100644
index 00000000000..6a868e95c89
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.min.stderr
@@ -0,0 +1,11 @@
+error: generic parameters may not be used in const operations
+  --> $DIR/trivial-anon-const-use-cases.rs:14:19
+   |
+LL |     stuff: [u8; { S + 1 }], // `S + 1` is NOT a valid const expression in this context.
+   |                   ^ cannot perform const operation using `S`
+   |
+   = help: const parameters may only be used as standalone arguments here, i.e. `S`
+   = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.rs b/tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.rs
new file mode 100644
index 00000000000..b1fd4cbc661
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/trivial-anon-const-use-cases.rs
@@ -0,0 +1,19 @@
+//! Regression test for <https://github.com/rust-lang/rust/issues/79429>.
+
+//@ revisions: full min
+#![cfg_attr(full, feature(generic_const_exprs))]
+#![cfg_attr(full, allow(incomplete_features))]
+
+struct X<const S: usize>;
+
+impl<const S: usize> X<S> {
+    const LEN: usize = S + 1; // `S + 1` is a valid const expression in this context.
+}
+
+struct Y<const S: usize> {
+    stuff: [u8; { S + 1 }], // `S + 1` is NOT a valid const expression in this context.
+    //[min]~^ ERROR generic parameters may not be used in const operations
+    //[full]~^^ ERROR unconstrained generic constant
+}
+
+fn main() {}
diff --git a/tests/ui/const-generics/issues/issue-68366.min.stderr b/tests/ui/const-generics/issues/issue-68366.min.stderr
index 10b5a06682f..4d721e958cb 100644
--- a/tests/ui/const-generics/issues/issue-68366.min.stderr
+++ b/tests/ui/const-generics/issues/issue-68366.min.stderr
@@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations
 LL | impl <const N: usize> Collatz<{Some(N)}> {}
    |                                     ^ cannot perform const operation using `N`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: `Option<usize>` is forbidden as the type of a const generic parameter
diff --git a/tests/ui/const-generics/issues/issue-76701-ty-param-in-const.stderr b/tests/ui/const-generics/issues/issue-76701-ty-param-in-const.stderr
index da2fbc52a6c..e58c894a270 100644
--- a/tests/ui/const-generics/issues/issue-76701-ty-param-in-const.stderr
+++ b/tests/ui/const-generics/issues/issue-76701-ty-param-in-const.stderr
@@ -13,7 +13,7 @@ error: generic parameters may not be used in const operations
 LL | fn const_param<const N: usize>() -> [u8; N + 1] {
    |                                          ^ cannot perform const operation using `N`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/const-generics/issues/issue-80375.stderr b/tests/ui/const-generics/issues/issue-80375.stderr
index 015196f8605..9a15e0380a1 100644
--- a/tests/ui/const-generics/issues/issue-80375.stderr
+++ b/tests/ui/const-generics/issues/issue-80375.stderr
@@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations
 LL | struct MyArray<const COUNT: usize>([u8; COUNT + 1]);
    |                                         ^^^^^ cannot perform const operation using `COUNT`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `COUNT`
+   = help: const parameters may only be used as standalone arguments here, i.e. `COUNT`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/const-generics/legacy-const-generics-bad.stderr b/tests/ui/const-generics/legacy-const-generics-bad.stderr
index 3a5fa417075..a8681d62053 100644
--- a/tests/ui/const-generics/legacy-const-generics-bad.stderr
+++ b/tests/ui/const-generics/legacy-const-generics-bad.stderr
@@ -16,7 +16,7 @@ error: generic parameters may not be used in const operations
 LL |     legacy_const_generics::foo(0, N + 1, 2);
    |                                   ^ cannot perform const operation using `N`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/const-generics/min_const_generics/complex-expression.stderr b/tests/ui/const-generics/min_const_generics/complex-expression.stderr
index 3affdcf9b03..35039bb4109 100644
--- a/tests/ui/const-generics/min_const_generics/complex-expression.stderr
+++ b/tests/ui/const-generics/min_const_generics/complex-expression.stderr
@@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations
 LL | struct Break0<const N: usize>([u8; { N + 1 }]);
    |                                      ^ cannot perform const operation using `N`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
@@ -13,7 +13,7 @@ error: generic parameters may not be used in const operations
 LL | struct Break1<const N: usize>([u8; { { N } }]);
    |                                        ^ cannot perform const operation using `N`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
@@ -22,7 +22,7 @@ error: generic parameters may not be used in const operations
 LL |     let _: [u8; N + 1];
    |                 ^ cannot perform const operation using `N`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
@@ -31,7 +31,7 @@ error: generic parameters may not be used in const operations
 LL |     let _ = [0; N + 1];
    |                 ^ cannot perform const operation using `N`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
diff --git a/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.stderr b/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.stderr
index ead6c621d60..fe32fbcc87d 100644
--- a/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.stderr
+++ b/tests/ui/const-generics/repeat_expr_hack_gives_right_generics.stderr
@@ -4,7 +4,7 @@ error: generic parameters may not be used in const operations
 LL |     bar::<{ [1; N] }>();
    |                 ^ cannot perform const operation using `N`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: generic parameters may not be used in const operations
@@ -13,7 +13,7 @@ error: generic parameters may not be used in const operations
 LL |     bar::<{ [1; { N + 1 }] }>();
    |                   ^ cannot perform const operation using `N`
    |
-   = help: const parameters may only be used as standalone arguments, i.e. `N`
+   = help: const parameters may only be used as standalone arguments here, i.e. `N`
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/consts/auxiliary/unstable_intrinsic.rs b/tests/ui/consts/auxiliary/unstable_intrinsic.rs
index 45631df7859..c1c7571e0c9 100644
--- a/tests/ui/consts/auxiliary/unstable_intrinsic.rs
+++ b/tests/ui/consts/auxiliary/unstable_intrinsic.rs
@@ -8,4 +8,4 @@ pub const unsafe fn size_of_val<T>(x: *const T) -> usize;
 #[unstable(feature = "unstable", issue = "42")]
 #[rustc_const_unstable(feature = "unstable", issue = "42")]
 #[rustc_intrinsic]
-pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize;
+pub const unsafe fn align_of_val<T>(x: *const T) -> usize;
diff --git a/tests/ui/consts/const-adt-align-mismatch.rs b/tests/ui/consts/const-adt-align-mismatch.rs
index 8faddbff30d..6ff74ad3a9c 100644
--- a/tests/ui/consts/const-adt-align-mismatch.rs
+++ b/tests/ui/consts/const-adt-align-mismatch.rs
@@ -18,5 +18,5 @@ static FOO: Foo = Foo::C;
 fn main() {
     assert_eq!(FOO, Foo::C);
     assert_eq!(mem::size_of::<Foo>(), 12);
-    assert_eq!(mem::min_align_of::<Foo>(), 4);
+    assert_eq!(mem::align_of::<Foo>(), 4);
 }
diff --git a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs
index 14cdf6bb7c6..423ff37baef 100644
--- a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs
+++ b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs
@@ -1,13 +1,13 @@
 #![feature(extern_types)]
 #![feature(core_intrinsics)]
 
-use std::intrinsics::{min_align_of_val, size_of_val};
+use std::intrinsics::{align_of_val, size_of_val};
 
 extern "C" {
     type Opaque;
 }
 
 const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) }; //~ ERROR layout
-const _ALIGN: usize = unsafe { min_align_of_val(&4 as *const i32 as *const Opaque) }; //~ ERROR layout
+const _ALIGN: usize = unsafe { align_of_val(&4 as *const i32 as *const Opaque) }; //~ ERROR layout
 
 fn main() {}
diff --git a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr
index 64b7a4129e0..c78626bdefc 100644
--- a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr
+++ b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr
@@ -7,8 +7,8 @@ LL | const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque
 error[E0080]: `extern type` does not have known layout
   --> $DIR/const-size_of_val-align_of_val-extern-type.rs:11:32
    |
-LL | const _ALIGN: usize = unsafe { min_align_of_val(&4 as *const i32 as *const Opaque) };
-   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_ALIGN` failed here
+LL | const _ALIGN: usize = unsafe { align_of_val(&4 as *const i32 as *const Opaque) };
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_ALIGN` failed here
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/consts/const-unstable-intrinsic.rs b/tests/ui/consts/const-unstable-intrinsic.rs
index 890a30c73c8..d130eb6c707 100644
--- a/tests/ui/consts/const-unstable-intrinsic.rs
+++ b/tests/ui/consts/const-unstable-intrinsic.rs
@@ -17,13 +17,13 @@ const fn const_main() {
         unstable_intrinsic::size_of_val(&x);
         //~^ERROR: unstable library feature `unstable`
         //~|ERROR: not yet stable as a const intrinsic
-        unstable_intrinsic::min_align_of_val(&x);
+        unstable_intrinsic::align_of_val(&x);
         //~^ERROR: unstable library feature `unstable`
         //~|ERROR: not yet stable as a const intrinsic
 
         size_of_val(&x);
         //~^ERROR: cannot use `#[feature(local)]`
-        min_align_of_val(&x);
+        align_of_val(&x);
         //~^ERROR: cannot use `#[feature(local)]`
     }
 }
@@ -35,7 +35,7 @@ pub const unsafe fn size_of_val<T>(x: *const T) -> usize;
 #[unstable(feature = "local", issue = "42")]
 #[rustc_const_unstable(feature = "local", issue = "42")]
 #[rustc_intrinsic]
-pub const unsafe fn min_align_of_val<T>(x: *const T) -> usize;
+pub const unsafe fn align_of_val<T>(x: *const T) -> usize;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "const_intrinsic_copy", since = "1.63.0")]
diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr
index 7e7ba966cee..973c7bae586 100644
--- a/tests/ui/consts/const-unstable-intrinsic.stderr
+++ b/tests/ui/consts/const-unstable-intrinsic.stderr
@@ -11,8 +11,8 @@ LL |         unstable_intrinsic::size_of_val(&x);
 error[E0658]: use of unstable library feature `unstable`
   --> $DIR/const-unstable-intrinsic.rs:20:9
    |
-LL |         unstable_intrinsic::min_align_of_val(&x);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         unstable_intrinsic::align_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #42 <https://github.com/rust-lang/rust/issues/42> for more information
    = help: add `#![feature(unstable)]` to the crate attributes to enable
@@ -29,11 +29,11 @@ help: add `#![feature(unstable)]` to the crate attributes to enable
 LL + #![feature(unstable)]
    |
 
-error: `min_align_of_val` is not yet stable as a const intrinsic
+error: `align_of_val` is not yet stable as a const intrinsic
   --> $DIR/const-unstable-intrinsic.rs:20:9
    |
-LL |         unstable_intrinsic::min_align_of_val(&x);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         unstable_intrinsic::align_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: add `#![feature(unstable)]` to the crate attributes to enable
    |
@@ -55,8 +55,8 @@ LL | const fn const_main() {
 error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]`
   --> $DIR/const-unstable-intrinsic.rs:26:9
    |
-LL |         min_align_of_val(&x);
-   |         ^^^^^^^^^^^^^^^^^^^^
+LL |         align_of_val(&x);
+   |         ^^^^^^^^^^^^^^^^
    |
 help: if the function is not (yet) meant to be exposed to stable const contexts, add `#[rustc_const_unstable]`
    |
diff --git a/tests/ui/consts/gate-do-not-const-check.rs b/tests/ui/consts/gate-do-not-const-check.rs
index be7e70dfabb..0ebb1e7c82e 100644
--- a/tests/ui/consts/gate-do-not-const-check.rs
+++ b/tests/ui/consts/gate-do-not-const-check.rs
@@ -1,5 +1,7 @@
 #[rustc_do_not_const_check]
-//~^ ERROR this is an internal attribute that will never be stable
+//~^ ERROR use of an internal attribute [E0658]
+//~| NOTE the `#[rustc_do_not_const_check]` attribute is an internal implementation detail that will never be stable
+//~| NOTE `#[rustc_do_not_const_check]` skips const-check for this function's body
 const fn foo() {}
 
 fn main() {}
diff --git a/tests/ui/consts/gate-do-not-const-check.stderr b/tests/ui/consts/gate-do-not-const-check.stderr
index 74ea71c4ed8..778ee50e71b 100644
--- a/tests/ui/consts/gate-do-not-const-check.stderr
+++ b/tests/ui/consts/gate-do-not-const-check.stderr
@@ -1,11 +1,12 @@
-error[E0658]: this is an internal attribute that will never be stable
+error[E0658]: use of an internal attribute
   --> $DIR/gate-do-not-const-check.rs:1:1
    |
 LL | #[rustc_do_not_const_check]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: the `#[rustc_do_not_const_check]` attribute is an internal implementation detail that will never be stable
+   = note: `#[rustc_do_not_const_check]` skips const-check for this function's body
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/coroutine/auto-trait-regions.stderr b/tests/ui/coroutine/auto-trait-regions.stderr
index a9a0bde2ba0..a3b5a5f006e 100644
--- a/tests/ui/coroutine/auto-trait-regions.stderr
+++ b/tests/ui/coroutine/auto-trait-regions.stderr
@@ -11,7 +11,7 @@ LL |         assert_foo(a);
    |
 help: consider using a `let` binding to create a longer lived value
    |
-LL ~         let binding = true;
+LL ~         let mut binding = true;
 LL ~         let a = A(&mut binding, &mut true, No);
    |
 
@@ -28,7 +28,7 @@ LL |         assert_foo(a);
    |
 help: consider using a `let` binding to create a longer lived value
    |
-LL ~         let binding = true;
+LL ~         let mut binding = true;
 LL ~         let a = A(&mut true, &mut binding, No);
    |
 
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/exclusive-drop-and-copy.rs b/tests/ui/derives/copy-drop-mutually-exclusive.rs
index 210ecaed756..5147605910d 100644
--- a/tests/ui/exclusive-drop-and-copy.rs
+++ b/tests/ui/derives/copy-drop-mutually-exclusive.rs
@@ -1,4 +1,4 @@
-// issue #20126
+//! Regression test for issue #20126: Copy and Drop traits are mutually exclusive
 
 #[derive(Copy, Clone)] //~ ERROR the trait `Copy` cannot be implemented
 struct Foo;
diff --git a/tests/ui/exclusive-drop-and-copy.stderr b/tests/ui/derives/copy-drop-mutually-exclusive.stderr
index 340ca89c396..771bbc92569 100644
--- a/tests/ui/exclusive-drop-and-copy.stderr
+++ b/tests/ui/derives/copy-drop-mutually-exclusive.stderr
@@ -1,11 +1,11 @@
 error[E0184]: the trait `Copy` cannot be implemented for this type; the type has a destructor
-  --> $DIR/exclusive-drop-and-copy.rs:3:10
+  --> $DIR/copy-drop-mutually-exclusive.rs:3:10
    |
 LL | #[derive(Copy, Clone)]
    |          ^^^^ `Copy` not allowed on types with destructors
 
 error[E0184]: the trait `Copy` cannot be implemented for this type; the type has a destructor
-  --> $DIR/exclusive-drop-and-copy.rs:10:10
+  --> $DIR/copy-drop-mutually-exclusive.rs:10:10
    |
 LL | #[derive(Copy, Clone)]
    |          ^^^^ `Copy` not allowed on types with destructors
diff --git a/tests/ui/diagnostic_namespace/multiline_spans.rs b/tests/ui/diagnostic_namespace/multiline_spans.rs
new file mode 100644
index 00000000000..994dd9fd011
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/multiline_spans.rs
@@ -0,0 +1,55 @@
+#![crate_type = "lib"]
+#![deny(unknown_or_malformed_diagnostic_attributes)]
+
+
+#[diagnostic::on_unimplemented(message = "here is a big \
+                                         multiline string \
+                                         {unknown}")]
+//~^ ERROR there is no parameter `unknown` on trait `MultiLine` [unknown_or_malformed_diagnostic_attributes]
+pub trait MultiLine {}
+
+#[diagnostic::on_unimplemented(message = "here is a big \
+                                         multiline string {unknown}")]
+//~^ ERROR there is no parameter `unknown` on trait `MultiLine2` [unknown_or_malformed_diagnostic_attributes]
+pub trait MultiLine2 {}
+
+#[diagnostic::on_unimplemented(message = "here is a big \
+    multiline string {unknown}")]
+//~^ ERROR there is no parameter `unknown` on trait `MultiLine3` [unknown_or_malformed_diagnostic_attributes]
+pub trait MultiLine3 {}
+
+
+#[diagnostic::on_unimplemented(message = "here is a big \
+\
+                \
+                                \
+                                                \
+    multiline string {unknown}")]
+//~^ ERROR there is no parameter `unknown` on trait `MultiLine4` [unknown_or_malformed_diagnostic_attributes]
+pub trait MultiLine4 {}
+
+#[diagnostic::on_unimplemented(message = "here is a big \
+                                         multiline string \
+                                         {Self:+}")]
+//~^ ERROR invalid format specifier [unknown_or_malformed_diagnostic_attributes]
+pub trait MultiLineFmt {}
+
+#[diagnostic::on_unimplemented(message = "here is a big \
+                                         multiline string {Self:X}")]
+//~^ ERROR invalid format specifier [unknown_or_malformed_diagnostic_attributes]
+pub trait MultiLineFmt2 {}
+
+#[diagnostic::on_unimplemented(message = "here is a big \
+    multiline string {Self:#}")]
+//~^ ERROR invalid format specifier [unknown_or_malformed_diagnostic_attributes]
+pub trait MultiLineFmt3 {}
+
+
+#[diagnostic::on_unimplemented(message = "here is a big \
+\
+                \
+                                \
+                                                \
+    multiline string {Self:?}")]
+//~^ ERROR invalid format specifier [unknown_or_malformed_diagnostic_attributes]
+pub trait MultiLineFmt4 {}
diff --git a/tests/ui/diagnostic_namespace/multiline_spans.stderr b/tests/ui/diagnostic_namespace/multiline_spans.stderr
new file mode 100644
index 00000000000..894bfe3d90a
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/multiline_spans.stderr
@@ -0,0 +1,71 @@
+error: there is no parameter `unknown` on trait `MultiLine`
+  --> $DIR/multiline_spans.rs:7:43
+   |
+LL | ...                   {unknown}")]
+   |                        ^^^^^^^
+   |
+   = help: expect either a generic argument name or `{Self}` as format argument
+note: the lint level is defined here
+  --> $DIR/multiline_spans.rs:2:9
+   |
+LL | #![deny(unknown_or_malformed_diagnostic_attributes)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: there is no parameter `unknown` on trait `MultiLine2`
+  --> $DIR/multiline_spans.rs:12:60
+   |
+LL | ...                   multiline string {unknown}")]
+   |                                         ^^^^^^^
+   |
+   = help: expect either a generic argument name or `{Self}` as format argument
+
+error: there is no parameter `unknown` on trait `MultiLine3`
+  --> $DIR/multiline_spans.rs:17:23
+   |
+LL |     multiline string {unknown}")]
+   |                       ^^^^^^^
+   |
+   = help: expect either a generic argument name or `{Self}` as format argument
+
+error: there is no parameter `unknown` on trait `MultiLine4`
+  --> $DIR/multiline_spans.rs:27:23
+   |
+LL |     multiline string {unknown}")]
+   |                       ^^^^^^^
+   |
+   = help: expect either a generic argument name or `{Self}` as format argument
+
+error: invalid format specifier
+  --> $DIR/multiline_spans.rs:33:47
+   |
+LL | ...                   {Self:+}")]
+   |                            ^^
+   |
+   = help: no format specifier are supported in this position
+
+error: invalid format specifier
+  --> $DIR/multiline_spans.rs:38:64
+   |
+LL | ...                   multiline string {Self:X}")]
+   |                                             ^^
+   |
+   = help: no format specifier are supported in this position
+
+error: invalid format specifier
+  --> $DIR/multiline_spans.rs:43:27
+   |
+LL |     multiline string {Self:#}")]
+   |                           ^^
+   |
+   = help: no format specifier are supported in this position
+
+error: invalid format specifier
+  --> $DIR/multiline_spans.rs:53:27
+   |
+LL |     multiline string {Self:?}")]
+   |                           ^^
+   |
+   = help: no format specifier are supported in this position
+
+error: aborting due to 8 previous errors
+
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs
index 44f269eb967..4762d9e793f 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.rs
@@ -12,6 +12,8 @@ trait ImportantTrait2 {}
 #[diagnostic::on_unimplemented(message = "Test {1:}")]
 //~^WARN positional format arguments are not allowed here
 //~|WARN positional format arguments are not allowed here
+//~|WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes]
+//~|WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes]
 trait ImportantTrait3 {}
 
 #[diagnostic::on_unimplemented(message = "Test {Self:123}")]
@@ -20,17 +22,22 @@ trait ImportantTrait3 {}
 trait ImportantTrait4 {}
 
 #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
-//~^WARN expected `}`, found `!`
-//~|WARN expected `}`, found `!`
-//~|WARN unmatched `}` found
-//~|WARN unmatched `}` found
+//~^WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes]
+//~|WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes]
 trait ImportantTrait5 {}
 
+#[diagnostic::on_unimplemented(message = "Test {Self:}")]
+//~^WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes]
+//~|WARN invalid format specifier [unknown_or_malformed_diagnostic_attributes]
+trait ImportantTrait6 {}
+
+
 fn check_1(_: impl ImportantTrait1) {}
 fn check_2(_: impl ImportantTrait2) {}
 fn check_3(_: impl ImportantTrait3) {}
 fn check_4(_: impl ImportantTrait4) {}
 fn check_5(_: impl ImportantTrait5) {}
+fn check_6(_: impl ImportantTrait6) {}
 
 fn main() {
     check_1(());
@@ -42,5 +49,7 @@ fn main() {
     check_4(());
     //~^ERROR Test ()
     check_5(());
-    //~^ERROR Test {Self:!}
+    //~^ERROR Test ()
+    check_6(());
+    //~^ERROR Test ()
 }
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr
index a82a1e78da0..2670d0630f7 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr
@@ -14,6 +14,14 @@ LL | #[diagnostic::on_unimplemented(message = "Test {}")]
    |
    = help: only named format arguments with the name of one of the generic types are allowed in this context
 
+warning: invalid format specifier
+  --> $DIR/broken_format.rs:12:50
+   |
+LL | #[diagnostic::on_unimplemented(message = "Test {1:}")]
+   |                                                  ^
+   |
+   = help: no format specifier are supported in this position
+
 warning: positional format arguments are not allowed here
   --> $DIR/broken_format.rs:12:49
    |
@@ -23,24 +31,28 @@ LL | #[diagnostic::on_unimplemented(message = "Test {1:}")]
    = help: only named format arguments with the name of one of the generic types are allowed in this context
 
 warning: invalid format specifier
-  --> $DIR/broken_format.rs:17:42
+  --> $DIR/broken_format.rs:19:53
    |
 LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")]
-   |                                          ^^^^^^^^^^^^^^^^^
+   |                                                     ^^^^
    |
    = help: no format specifier are supported in this position
 
-warning: expected `}`, found `!`
-  --> $DIR/broken_format.rs:22:42
+warning: invalid format specifier
+  --> $DIR/broken_format.rs:24:53
    |
 LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
-   |                                          ^^^^^^^^^^^^^^^
+   |                                                     ^^
+   |
+   = help: no format specifier are supported in this position
 
-warning: unmatched `}` found
-  --> $DIR/broken_format.rs:22:42
+warning: invalid format specifier
+  --> $DIR/broken_format.rs:29:53
    |
-LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
-   |                                          ^^^^^^^^^^^^^^^
+LL | #[diagnostic::on_unimplemented(message = "Test {Self:}")]
+   |                                                     ^
+   |
+   = help: no format specifier are supported in this position
 
 warning: unmatched `}` found
   --> $DIR/broken_format.rs:2:42
@@ -51,7 +63,7 @@ LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: {{Test } thing
-  --> $DIR/broken_format.rs:36:13
+  --> $DIR/broken_format.rs:43:13
    |
 LL |     check_1(());
    |     ------- ^^ the trait `ImportantTrait1` is not implemented for `()`
@@ -64,7 +76,7 @@ help: this trait has no implementations, consider adding one
 LL | trait ImportantTrait1 {}
    | ^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `check_1`
-  --> $DIR/broken_format.rs:29:20
+  --> $DIR/broken_format.rs:35:20
    |
 LL | fn check_1(_: impl ImportantTrait1) {}
    |                    ^^^^^^^^^^^^^^^ required by this bound in `check_1`
@@ -79,7 +91,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {}")]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: Test {}
-  --> $DIR/broken_format.rs:38:13
+  --> $DIR/broken_format.rs:45:13
    |
 LL |     check_2(());
    |     ------- ^^ the trait `ImportantTrait2` is not implemented for `()`
@@ -92,11 +104,20 @@ help: this trait has no implementations, consider adding one
 LL | trait ImportantTrait2 {}
    | ^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `check_2`
-  --> $DIR/broken_format.rs:30:20
+  --> $DIR/broken_format.rs:36:20
    |
 LL | fn check_2(_: impl ImportantTrait2) {}
    |                    ^^^^^^^^^^^^^^^ required by this bound in `check_2`
 
+warning: invalid format specifier
+  --> $DIR/broken_format.rs:12:50
+   |
+LL | #[diagnostic::on_unimplemented(message = "Test {1:}")]
+   |                                                  ^
+   |
+   = help: no format specifier are supported in this position
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
 warning: positional format arguments are not allowed here
   --> $DIR/broken_format.rs:12:49
    |
@@ -107,7 +128,7 @@ LL | #[diagnostic::on_unimplemented(message = "Test {1:}")]
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: Test {1}
-  --> $DIR/broken_format.rs:40:13
+  --> $DIR/broken_format.rs:47:13
    |
 LL |     check_3(());
    |     ------- ^^ the trait `ImportantTrait3` is not implemented for `()`
@@ -115,27 +136,27 @@ LL |     check_3(());
    |     required by a bound introduced by this call
    |
 help: this trait has no implementations, consider adding one
-  --> $DIR/broken_format.rs:15:1
+  --> $DIR/broken_format.rs:17:1
    |
 LL | trait ImportantTrait3 {}
    | ^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `check_3`
-  --> $DIR/broken_format.rs:31:20
+  --> $DIR/broken_format.rs:37:20
    |
 LL | fn check_3(_: impl ImportantTrait3) {}
    |                    ^^^^^^^^^^^^^^^ required by this bound in `check_3`
 
 warning: invalid format specifier
-  --> $DIR/broken_format.rs:17:42
+  --> $DIR/broken_format.rs:19:53
    |
 LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")]
-   |                                          ^^^^^^^^^^^^^^^^^
+   |                                                     ^^^^
    |
    = help: no format specifier are supported in this position
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0277]: Test ()
-  --> $DIR/broken_format.rs:42:13
+  --> $DIR/broken_format.rs:49:13
    |
 LL |     check_4(());
    |     ------- ^^ the trait `ImportantTrait4` is not implemented for `()`
@@ -143,34 +164,27 @@ LL |     check_4(());
    |     required by a bound introduced by this call
    |
 help: this trait has no implementations, consider adding one
-  --> $DIR/broken_format.rs:20:1
+  --> $DIR/broken_format.rs:22:1
    |
 LL | trait ImportantTrait4 {}
    | ^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `check_4`
-  --> $DIR/broken_format.rs:32:20
+  --> $DIR/broken_format.rs:38:20
    |
 LL | fn check_4(_: impl ImportantTrait4) {}
    |                    ^^^^^^^^^^^^^^^ required by this bound in `check_4`
 
-warning: expected `}`, found `!`
-  --> $DIR/broken_format.rs:22:42
-   |
-LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
-   |                                          ^^^^^^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-warning: unmatched `}` found
-  --> $DIR/broken_format.rs:22:42
+warning: invalid format specifier
+  --> $DIR/broken_format.rs:24:53
    |
 LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
-   |                                          ^^^^^^^^^^^^^^^
+   |                                                     ^^
    |
+   = help: no format specifier are supported in this position
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error[E0277]: Test {Self:!}
-  --> $DIR/broken_format.rs:44:13
+error[E0277]: Test ()
+  --> $DIR/broken_format.rs:51:13
    |
 LL |     check_5(());
    |     ------- ^^ the trait `ImportantTrait5` is not implemented for `()`
@@ -183,11 +197,39 @@ help: this trait has no implementations, consider adding one
 LL | trait ImportantTrait5 {}
    | ^^^^^^^^^^^^^^^^^^^^^
 note: required by a bound in `check_5`
-  --> $DIR/broken_format.rs:33:20
+  --> $DIR/broken_format.rs:39:20
    |
 LL | fn check_5(_: impl ImportantTrait5) {}
    |                    ^^^^^^^^^^^^^^^ required by this bound in `check_5`
 
-error: aborting due to 5 previous errors; 12 warnings emitted
+warning: invalid format specifier
+  --> $DIR/broken_format.rs:29:53
+   |
+LL | #[diagnostic::on_unimplemented(message = "Test {Self:}")]
+   |                                                     ^
+   |
+   = help: no format specifier are supported in this position
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error[E0277]: Test ()
+  --> $DIR/broken_format.rs:53:13
+   |
+LL |     check_6(());
+   |     ------- ^^ the trait `ImportantTrait6` is not implemented for `()`
+   |     |
+   |     required by a bound introduced by this call
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/broken_format.rs:32:1
+   |
+LL | trait ImportantTrait6 {}
+   | ^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `check_6`
+  --> $DIR/broken_format.rs:40:20
+   |
+LL | fn check_6(_: impl ImportantTrait6) {}
+   |                    ^^^^^^^^^^^^^^^ required by this bound in `check_6`
+
+error: aborting due to 6 previous errors; 14 warnings emitted
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/illegal-ufcs-drop.fixed b/tests/ui/drop/explicit-drop-call-error.fixed
index 2b1c967ed1e..f2f0245df96 100644
--- a/tests/ui/illegal-ufcs-drop.fixed
+++ b/tests/ui/drop/explicit-drop-call-error.fixed
@@ -1,3 +1,5 @@
+//! Test error for explicit destructor method calls via UFCS
+
 //@ run-rustfix
 
 #![allow(dropping_references)]
diff --git a/tests/ui/illegal-ufcs-drop.rs b/tests/ui/drop/explicit-drop-call-error.rs
index 99dda0dab34..e41c806bd1e 100644
--- a/tests/ui/illegal-ufcs-drop.rs
+++ b/tests/ui/drop/explicit-drop-call-error.rs
@@ -1,3 +1,5 @@
+//! Test error for explicit destructor method calls via UFCS
+
 //@ run-rustfix
 
 #![allow(dropping_references)]
diff --git a/tests/ui/illegal-ufcs-drop.stderr b/tests/ui/drop/explicit-drop-call-error.stderr
index 4f214a12747..95d5c31ab6d 100644
--- a/tests/ui/illegal-ufcs-drop.stderr
+++ b/tests/ui/drop/explicit-drop-call-error.stderr
@@ -1,5 +1,5 @@
 error[E0040]: explicit use of destructor method
-  --> $DIR/illegal-ufcs-drop.rs:12:5
+  --> $DIR/explicit-drop-call-error.rs:14:5
    |
 LL |     Drop::drop(&mut Foo)
    |     ^^^^^^^^^^
diff --git a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr
index 152a6f3a41e..34f5c7d3084 100644
--- a/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr
+++ b/tests/ui/editions/edition-keywords-2018-2015-parsing.stderr
@@ -44,22 +44,22 @@ note: while trying to match `r#async`
 LL |     (r#async) => (1)
    |      ^^^^^^^
 
-error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
+error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `{`, `|`, or `||`
   --> $DIR/auxiliary/edition-kw-macro-2015.rs:27:23
    |
 LL |     ($i: ident) => ($i)
-   |                       ^ expected one of `move`, `use`, `|`, or `||`
+   |                       ^ expected one of `move`, `use`, `{`, `|`, or `||`
    |
   ::: $DIR/edition-keywords-2018-2015-parsing.rs:22:8
    |
 LL |     if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved
    |        -------------------- in this macro invocation
 
-error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
+error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `{`, `|`, or `||`
   --> $DIR/edition-keywords-2018-2015-parsing.rs:24:24
    |
 LL |     if passes_tt!(async) == 1 {}
-   |                        ^ expected one of `move`, `use`, `|`, or `||`
+   |                        ^ expected one of `move`, `use`, `{`, `|`, or `||`
 
 error[E0308]: mismatched types
   --> $DIR/edition-keywords-2018-2015-parsing.rs:29:33
diff --git a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr
index 53f1b827f9c..dd3f4938c74 100644
--- a/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr
+++ b/tests/ui/editions/edition-keywords-2018-2018-parsing.stderr
@@ -44,34 +44,34 @@ note: while trying to match `r#async`
 LL |     (r#async) => (1)
    |      ^^^^^^^
 
-error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
+error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `{`, `|`, or `||`
   --> $DIR/auxiliary/edition-kw-macro-2018.rs:27:23
    |
 LL |     ($i: ident) => ($i)
-   |                       ^ expected one of `move`, `use`, `|`, or `||`
+   |                       ^ expected one of `move`, `use`, `{`, `|`, or `||`
    |
   ::: $DIR/edition-keywords-2018-2018-parsing.rs:29:8
    |
 LL |     if passes_ident!(async) == 1 {} // FIXME: Edition hygiene bug, async here is 2018 and reserved
    |        -------------------- in this macro invocation
 
-error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
+error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `{`, `|`, or `||`
   --> $DIR/edition-keywords-2018-2018-parsing.rs:31:24
    |
 LL |     if passes_tt!(async) == 1 {}
-   |                        ^ expected one of `move`, `use`, `|`, or `||`
+   |                        ^ expected one of `move`, `use`, `{`, `|`, or `||`
 
-error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
+error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `{`, `|`, or `||`
   --> $DIR/edition-keywords-2018-2018-parsing.rs:14:23
    |
 LL |     ($i: ident) => ($i)
-   |                       ^ expected one of `move`, `use`, `|`, or `||`
+   |                       ^ expected one of `move`, `use`, `{`, `|`, or `||`
 
-error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `|`, or `||`
+error: macro expansion ends with an incomplete expression: expected one of `move`, `use`, `{`, `|`, or `||`
   --> $DIR/edition-keywords-2018-2018-parsing.rs:35:30
    |
 LL |     if local_passes_tt!(async) == 1 {}
-   |                              ^ expected one of `move`, `use`, `|`, or `||`
+   |                              ^ expected one of `move`, `use`, `{`, `|`, or `||`
 
 error[E0308]: mismatched types
   --> $DIR/edition-keywords-2018-2018-parsing.rs:40:33
diff --git a/tests/ui/editions/unsafe-attr-edition-span.e2024.stderr b/tests/ui/editions/unsafe-attr-edition-span.e2024.stderr
new file mode 100644
index 00000000000..28871a1cce4
--- /dev/null
+++ b/tests/ui/editions/unsafe-attr-edition-span.e2024.stderr
@@ -0,0 +1,24 @@
+error: unsafe attribute used without unsafe
+  --> $DIR/unsafe-attr-edition-span.rs:21:3
+   |
+LL | #[no_mangle]
+   |   ^^^^^^^^^ usage of unsafe attribute
+   |
+help: wrap the attribute in `unsafe(...)`
+   |
+LL | #[unsafe(no_mangle)]
+   |   +++++++         +
+
+error: unsafe attribute used without unsafe
+  --> $DIR/unsafe-attr-edition-span.rs:25:7
+   |
+LL |     #[no_mangle]
+   |       ^^^^^^^^^ usage of unsafe attribute
+   |
+help: wrap the attribute in `unsafe(...)`
+   |
+LL |     #[unsafe(no_mangle)]
+   |       +++++++         +
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/editions/unsafe-attr-edition-span.rs b/tests/ui/editions/unsafe-attr-edition-span.rs
new file mode 100644
index 00000000000..bc44b34063c
--- /dev/null
+++ b/tests/ui/editions/unsafe-attr-edition-span.rs
@@ -0,0 +1,27 @@
+// Tests that the correct span is used to determine the edition of an attribute that was safe to use
+// in earlier editions, but has become `unsafe` in later editions.
+//
+// Determining the correct edition is non-trivial because of macro expansion. For instance,
+// the `thread_local!` macro (defined in std and hence using the most recent edition) parses the
+// attribute, and then re-emits it. Therefore, the span of the `#` token starting the
+// `#[no_mangle]` attribute has std's edition, while the attribute name has the edition of this
+// file, which may be different.
+
+//@ revisions: e2015 e2018 e2021 e2024
+
+//@[e2018] edition:2018
+//@[e2021] edition:2021
+//@[e2024] edition:2024
+//
+//@[e2015] check-pass
+//@[e2018] check-pass
+//@[e2021] check-pass
+#![crate_type = "lib"]
+
+#[no_mangle] //[e2024]~ ERROR unsafe attribute used without unsafe
+static TEST_OUTSIDE: usize = 0;
+
+thread_local! {
+    #[no_mangle]//[e2024]~ ERROR unsafe attribute used without unsafe
+    static TEST: usize = 0;
+}
diff --git a/tests/ui/empty-allocation-rvalue-non-null.rs b/tests/ui/empty-allocation-rvalue-non-null.rs
deleted file mode 100644
index 0cd4fde73ed..00000000000
--- a/tests/ui/empty-allocation-rvalue-non-null.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-//@ run-pass
-
-#![allow(unused_variables)]
-
-pub fn main() {
-    let x: () = *Box::new(());
-}
diff --git a/tests/ui/empty-type-parameter-list.rs b/tests/ui/empty-type-parameter-list.rs
deleted file mode 100644
index e8d6b2a9964..00000000000
--- a/tests/ui/empty-type-parameter-list.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-//@ run-pass
-// Test that empty type parameter list (<>) is synonymous with
-// no type parameters at all
-
-struct S<>;
-trait T<> {} //~ WARN trait `T` is never used
-enum E<> { V }
-impl<> T<> for S<> {}
-impl T for E {}
-fn foo<>() {}
-fn bar() {}
-
-fn main() {
-    let _ = S;
-    let _ = S::<>;
-    let _ = E::V;
-    let _ = E::<>::V;
-    foo();
-    foo::<>();
-
-    // Test that we can supply <> to non generic things
-    bar::<>();
-    let _: i32<>;
-}
diff --git a/tests/ui/enum/dead-code-associated-function.rs b/tests/ui/enum/dead-code-associated-function.rs
new file mode 100644
index 00000000000..d172ceb41dd
--- /dev/null
+++ b/tests/ui/enum/dead-code-associated-function.rs
@@ -0,0 +1,20 @@
+//@ check-pass
+#![warn(dead_code)]
+
+enum E {
+    F(),
+    C(),
+}
+
+impl E {
+    #[expect(non_snake_case)]
+    fn F() {}
+    //~^ WARN: associated items `F` and `C` are never used
+
+    const C: () = ();
+}
+
+fn main() {
+    let _: E = E::F();
+    let _: E = E::C();
+}
diff --git a/tests/ui/enum/dead-code-associated-function.stderr b/tests/ui/enum/dead-code-associated-function.stderr
new file mode 100644
index 00000000000..e3c1a4c81a4
--- /dev/null
+++ b/tests/ui/enum/dead-code-associated-function.stderr
@@ -0,0 +1,30 @@
+warning: associated items `F` and `C` are never used
+  --> $DIR/dead-code-associated-function.rs:11:8
+   |
+LL | impl E {
+   | ------ associated items in this implementation
+LL |     #[expect(non_snake_case)]
+LL |     fn F() {}
+   |        ^
+...
+LL |     const C: () = ();
+   |           ^
+   |
+note: it is impossible to refer to the associated function `F` because it is shadowed by this enum variant with the same name
+  --> $DIR/dead-code-associated-function.rs:5:5
+   |
+LL |     F(),
+   |     ^
+note: it is impossible to refer to the associated constant `C` because it is shadowed by this enum variant with the same name
+  --> $DIR/dead-code-associated-function.rs:6:5
+   |
+LL |     C(),
+   |     ^
+note: the lint level is defined here
+  --> $DIR/dead-code-associated-function.rs:2:9
+   |
+LL | #![warn(dead_code)]
+   |         ^^^^^^^^^
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/error-should-say-copy-not-pod.rs b/tests/ui/error-should-say-copy-not-pod.rs
deleted file mode 100644
index 40c4730ef69..00000000000
--- a/tests/ui/error-should-say-copy-not-pod.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-// Tests that the error message uses the word Copy, not Pod.
-
-fn check_bound<T:Copy>(_: T) {}
-
-fn main() {
-    check_bound("nocopy".to_string()); //~ ERROR : Copy` is not satisfied
-}
diff --git a/tests/ui/error-should-say-copy-not-pod.stderr b/tests/ui/error-should-say-copy-not-pod.stderr
deleted file mode 100644
index 6aa129fa29b..00000000000
--- a/tests/ui/error-should-say-copy-not-pod.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error[E0277]: the trait bound `String: Copy` is not satisfied
-  --> $DIR/error-should-say-copy-not-pod.rs:6:17
-   |
-LL |     check_bound("nocopy".to_string());
-   |     ----------- ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
-   |     |
-   |     required by a bound introduced by this call
-   |
-note: required by a bound in `check_bound`
-  --> $DIR/error-should-say-copy-not-pod.rs:3:18
-   |
-LL | fn check_bound<T:Copy>(_: T) {}
-   |                  ^^^^ required by this bound in `check_bound`
-help: consider removing this method call, as the receiver has type `&'static str` and `&'static str: Copy` trivially holds
-   |
-LL -     check_bound("nocopy".to_string());
-LL +     check_bound("nocopy");
-   |
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/explicit-i-suffix.rs b/tests/ui/explicit-i-suffix.rs
deleted file mode 100644
index 0a6ed49ae27..00000000000
--- a/tests/ui/explicit-i-suffix.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-//@ run-pass
-
-#![allow(unused_must_use)]
-
-pub fn main() {
-    let x: isize = 8;
-    let y = 9;
-    x + y;
-
-    let q: isize = -8;
-    let r = -9;
-    q + r;
-}
diff --git a/tests/ui/ext-nonexistent.rs b/tests/ui/ext-nonexistent.rs
deleted file mode 100644
index 1293324b67e..00000000000
--- a/tests/ui/ext-nonexistent.rs
+++ /dev/null
@@ -1,2 +0,0 @@
-fn main() { iamnotanextensionthatexists!(""); }
-//~^ ERROR cannot find macro `iamnotanextensionthatexists` in this scope
diff --git a/tests/ui/ext-nonexistent.stderr b/tests/ui/ext-nonexistent.stderr
deleted file mode 100644
index edb59bba6e5..00000000000
--- a/tests/ui/ext-nonexistent.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: cannot find macro `iamnotanextensionthatexists` in this scope
-  --> $DIR/ext-nonexistent.rs:1:13
-   |
-LL | fn main() { iamnotanextensionthatexists!(""); }
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/fact.rs b/tests/ui/fact.rs
deleted file mode 100644
index e94c12da013..00000000000
--- a/tests/ui/fact.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-//@ run-pass
-
-fn f(x: isize) -> isize {
-    // println!("in f:");
-
-    println!("{}", x);
-    if x == 1 {
-        // println!("bottoming out");
-
-        return 1;
-    } else {
-        // println!("recurring");
-
-        let y: isize = x * f(x - 1);
-        // println!("returned");
-
-        println!("{}", y);
-        return y;
-    }
-}
-
-pub fn main() {
-    assert_eq!(f(5), 120);
-    // println!("all done");
-
-}
diff --git a/tests/ui/feature-gates/feature-gate-abi-custom.rs b/tests/ui/feature-gates/feature-gate-abi-custom.rs
new file mode 100644
index 00000000000..3ddce974dd7
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-abi-custom.rs
@@ -0,0 +1,51 @@
+//@ add-core-stubs
+//@ needs-asm-support
+#![no_core]
+#![feature(no_core, lang_items)]
+#![crate_type = "rlib"]
+
+extern crate minicore;
+use minicore::*;
+
+#[unsafe(naked)]
+unsafe extern "custom" fn f7() {
+    //~^ ERROR "custom" ABI is experimental
+    naked_asm!("")
+}
+trait Tr {
+    extern "custom" fn m7();
+    //~^ ERROR "custom" ABI is experimental
+    //~| ERROR functions with the `"custom"` ABI must be unsafe
+    #[unsafe(naked)]
+    extern "custom" fn dm7() {
+        //~^ ERROR "custom" ABI is experimental
+        //~| ERROR functions with the `"custom"` ABI must be unsafe
+        naked_asm!("")
+    }
+}
+
+struct S;
+
+// Methods in trait impl
+impl Tr for S {
+    #[unsafe(naked)]
+    extern "custom" fn m7() {
+        //~^ ERROR "custom" ABI is experimental
+        //~| ERROR functions with the `"custom"` ABI must be unsafe
+        naked_asm!("")
+    }
+}
+
+// Methods in inherent impl
+impl S {
+    #[unsafe(naked)]
+    extern "custom" fn im7() {
+        //~^ ERROR "custom" ABI is experimental
+        //~| ERROR functions with the `"custom"` ABI must be unsafe
+        naked_asm!("")
+    }
+}
+
+type A7 = extern "custom" fn(); //~ ERROR "custom" ABI is experimental
+
+extern "custom" {} //~ ERROR "custom" ABI is experimental
diff --git a/tests/ui/feature-gates/feature-gate-abi-custom.stderr b/tests/ui/feature-gates/feature-gate-abi-custom.stderr
new file mode 100644
index 00000000000..e6dce0126d6
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-abi-custom.stderr
@@ -0,0 +1,117 @@
+error: functions with the `"custom"` ABI must be unsafe
+  --> $DIR/feature-gate-abi-custom.rs:16:5
+   |
+LL |     extern "custom" fn m7();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: add the `unsafe` keyword to this definition
+   |
+LL |     unsafe extern "custom" fn m7();
+   |     ++++++
+
+error: functions with the `"custom"` ABI must be unsafe
+  --> $DIR/feature-gate-abi-custom.rs:20:5
+   |
+LL |     extern "custom" fn dm7() {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: add the `unsafe` keyword to this definition
+   |
+LL |     unsafe extern "custom" fn dm7() {
+   |     ++++++
+
+error: functions with the `"custom"` ABI must be unsafe
+  --> $DIR/feature-gate-abi-custom.rs:32:5
+   |
+LL |     extern "custom" fn m7() {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: add the `unsafe` keyword to this definition
+   |
+LL |     unsafe extern "custom" fn m7() {
+   |     ++++++
+
+error: functions with the `"custom"` ABI must be unsafe
+  --> $DIR/feature-gate-abi-custom.rs:42:5
+   |
+LL |     extern "custom" fn im7() {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: add the `unsafe` keyword to this definition
+   |
+LL |     unsafe extern "custom" fn im7() {
+   |     ++++++
+
+error[E0658]: the extern "custom" ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi-custom.rs:11:15
+   |
+LL | unsafe extern "custom" fn f7() {
+   |               ^^^^^^^^
+   |
+   = note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information
+   = help: add `#![feature(abi_custom)]` 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[E0658]: the extern "custom" ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi-custom.rs:16:12
+   |
+LL |     extern "custom" fn m7();
+   |            ^^^^^^^^
+   |
+   = note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information
+   = help: add `#![feature(abi_custom)]` 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[E0658]: the extern "custom" ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi-custom.rs:20:12
+   |
+LL |     extern "custom" fn dm7() {
+   |            ^^^^^^^^
+   |
+   = note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information
+   = help: add `#![feature(abi_custom)]` 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[E0658]: the extern "custom" ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi-custom.rs:32:12
+   |
+LL |     extern "custom" fn m7() {
+   |            ^^^^^^^^
+   |
+   = note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information
+   = help: add `#![feature(abi_custom)]` 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[E0658]: the extern "custom" ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi-custom.rs:42:12
+   |
+LL |     extern "custom" fn im7() {
+   |            ^^^^^^^^
+   |
+   = note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information
+   = help: add `#![feature(abi_custom)]` 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[E0658]: the extern "custom" ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi-custom.rs:49:18
+   |
+LL | type A7 = extern "custom" fn();
+   |                  ^^^^^^^^
+   |
+   = note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information
+   = help: add `#![feature(abi_custom)]` 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[E0658]: the extern "custom" ABI is experimental and subject to change
+  --> $DIR/feature-gate-abi-custom.rs:51:8
+   |
+LL | extern "custom" {}
+   |        ^^^^^^^^
+   |
+   = note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information
+   = help: add `#![feature(abi_custom)]` 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 11 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
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/feature-gate-pattern-complexity-limit.rs b/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.rs
index d1f6f4755f0..ffb444cd9aa 100644
--- a/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.rs
+++ b/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.rs
@@ -1,6 +1,8 @@
 // check that `pattern_complexity_limit` is feature-gated
 
 #![pattern_complexity_limit = "42"]
-//~^ ERROR: the `#[pattern_complexity_limit]` attribute is just used for rustc unit tests
+//~^ ERROR: use of an internal attribute [E0658]
+//~| NOTE the `#[pattern_complexity_limit]` attribute is an internal implementation detail that will never be stable
+//~| NOTE: the `#[pattern_complexity_limit]` attribute is used for rustc unit tests
 
 fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.stderr b/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.stderr
index e6f17710e09..9ddea866ea9 100644
--- a/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.stderr
+++ b/tests/ui/feature-gates/feature-gate-pattern-complexity-limit.stderr
@@ -1,11 +1,12 @@
-error[E0658]: the `#[pattern_complexity_limit]` attribute is just used for rustc unit tests and will never be stable
+error[E0658]: use of an internal attribute
   --> $DIR/feature-gate-pattern-complexity-limit.rs:3:1
    |
 LL | #![pattern_complexity_limit = "42"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: the `#[pattern_complexity_limit]` attribute is an internal implementation detail that will never be stable
+   = note: the `#[pattern_complexity_limit]` attribute is used for rustc unit tests
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs
index 025b4b52f12..17556723622 100644
--- a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs
+++ b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.rs
@@ -1,6 +1,12 @@
 // Test that `#[rustc_*]` attributes are gated by `rustc_attrs` feature gate.
 
-#[rustc_variance] //~ ERROR the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable
-#[rustc_nonnull_optimization_guaranteed] //~ ERROR the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in libcore and libstd and will never be stable
-
+#[rustc_variance]
+//~^ ERROR use of an internal attribute [E0658]
+//~| NOTE the `#[rustc_variance]` attribute is an internal implementation detail that will never be stable
+//~| NOTE the `#[rustc_variance]` attribute is used for rustc unit tests
+#[rustc_nonnull_optimization_guaranteed]
+//~^ ERROR use of an internal attribute [E0658]
+//~| NOTE the `#[rustc_nonnull_optimization_guaranteed]` attribute is an internal implementation detail that will never be stable
+//~| NOTE  the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in the standard library
+//~| NOTE the compiler does not even check whether the type indeed is being non-null-optimized; it is your responsibility to ensure that the attribute is only used on types that are optimized
 fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr
index 0f760e0602d..159d383e408 100644
--- a/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr
+++ b/tests/ui/feature-gates/feature-gate-rustc-attrs-1.stderr
@@ -1,21 +1,23 @@
-error[E0658]: the `#[rustc_variance]` attribute is just used for rustc unit tests and will never be stable
+error[E0658]: use of an internal attribute
   --> $DIR/feature-gate-rustc-attrs-1.rs:3:1
    |
 LL | #[rustc_variance]
    | ^^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: the `#[rustc_variance]` attribute is an internal implementation detail that will never be stable
+   = note: the `#[rustc_variance]` attribute is used for rustc unit tests
 
-error[E0658]: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in libcore and libstd and will never be stable
-              (note that the compiler does not even check whether the type indeed is being non-null-optimized; it is your responsibility to ensure that the attribute is only used on types that are optimized)
-  --> $DIR/feature-gate-rustc-attrs-1.rs:4:1
+error[E0658]: use of an internal attribute
+  --> $DIR/feature-gate-rustc-attrs-1.rs:7:1
    |
 LL | #[rustc_nonnull_optimization_guaranteed]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: the `#[rustc_nonnull_optimization_guaranteed]` attribute is an internal implementation detail that will never be stable
+   = note: the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in the standard library
+   = note: the compiler does not even check whether the type indeed is being non-null-optimized; it is your responsibility to ensure that the attribute is only used on types that are optimized
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/feature-gates/feature-gate-rustc-attrs.rs b/tests/ui/feature-gates/feature-gate-rustc-attrs.rs
index c985298a30a..e7b2eca6f85 100644
--- a/tests/ui/feature-gates/feature-gate-rustc-attrs.rs
+++ b/tests/ui/feature-gates/feature-gate-rustc-attrs.rs
@@ -8,15 +8,19 @@ mod unknown { pub macro rustc() {} }
 #[rustc::unknown]
 //~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
 //~| ERROR expected attribute, found macro `rustc::unknown`
+//~| NOTE not an attribute
 fn f() {}
 
 #[unknown::rustc]
 //~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
 //~| ERROR expected attribute, found macro `unknown::rustc`
+//~| NOTE not an attribute
 fn g() {}
 
 #[rustc_dummy]
-//~^ ERROR the `#[rustc_dummy]` attribute is just used for rustc unit tests
+//~^ ERROR use of an internal attribute [E0658]
+//~| NOTE the `#[rustc_dummy]` attribute is an internal implementation detail that will never be stable
+//~| NOTE the `#[rustc_dummy]` attribute is used for rustc unit tests
 #[rustc_unknown]
 //~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler
 //~| ERROR cannot find attribute `rustc_unknown` in this scope
diff --git a/tests/ui/feature-gates/feature-gate-rustc-attrs.stderr b/tests/ui/feature-gates/feature-gate-rustc-attrs.stderr
index c7a5ef3e44b..d58603883f1 100644
--- a/tests/ui/feature-gates/feature-gate-rustc-attrs.stderr
+++ b/tests/ui/feature-gates/feature-gate-rustc-attrs.stderr
@@ -11,37 +11,38 @@ LL | #[rustc::unknown]
    |   ^^^^^^^^^^^^^^ not an attribute
 
 error: attributes starting with `rustc` are reserved for use by the `rustc` compiler
-  --> $DIR/feature-gate-rustc-attrs.rs:13:12
+  --> $DIR/feature-gate-rustc-attrs.rs:14:12
    |
 LL | #[unknown::rustc]
    |            ^^^^^
 
 error: expected attribute, found macro `unknown::rustc`
-  --> $DIR/feature-gate-rustc-attrs.rs:13:3
+  --> $DIR/feature-gate-rustc-attrs.rs:14:3
    |
 LL | #[unknown::rustc]
    |   ^^^^^^^^^^^^^^ not an attribute
 
 error: attributes starting with `rustc` are reserved for use by the `rustc` compiler
-  --> $DIR/feature-gate-rustc-attrs.rs:20:3
+  --> $DIR/feature-gate-rustc-attrs.rs:24:3
    |
 LL | #[rustc_unknown]
    |   ^^^^^^^^^^^^^
 
 error: cannot find attribute `rustc_unknown` in this scope
-  --> $DIR/feature-gate-rustc-attrs.rs:20:3
+  --> $DIR/feature-gate-rustc-attrs.rs:24:3
    |
 LL | #[rustc_unknown]
    |   ^^^^^^^^^^^^^
 
-error[E0658]: the `#[rustc_dummy]` attribute is just used for rustc unit tests and will never be stable
-  --> $DIR/feature-gate-rustc-attrs.rs:18:1
+error[E0658]: use of an internal attribute
+  --> $DIR/feature-gate-rustc-attrs.rs:20:1
    |
 LL | #[rustc_dummy]
    | ^^^^^^^^^^^^^^
    |
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: the `#[rustc_dummy]` attribute is an internal implementation detail that will never be stable
+   = note: the `#[rustc_dummy]` attribute is used for rustc unit tests
 
 error: aborting due to 7 previous errors
 
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/issue-43106-gating-of-builtin-attrs-error.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
index 02a56c7e6aa..7fb11b7bde7 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
@@ -11,9 +11,11 @@
 
 #![macro_export]
 //~^ ERROR: `macro_export` attribute cannot be used at crate level
-#![rustc_main] //~ ERROR: the `#[rustc_main]` attribute is used internally to specify
+#![rustc_main]
 //~^ ERROR: `rustc_main` attribute cannot be used at crate level
-//~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+//~| ERROR: use of an internal attribute [E0658]
+//~| NOTE: the `#[rustc_main]` attribute is an internal implementation detail that will never be stable
+//~| NOTE: the `#[rustc_main]` attribute is used internally to specify test entry point function
 #![repr()]
 //~^ ERROR: `repr` attribute cannot be used at crate level
 #![path = "3800"]
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
index 5c2a3ae699c..bdca6163473 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
@@ -1,14 +1,15 @@
-error[E0658]: the `#[rustc_main]` attribute is used internally to specify test entry point function
+error[E0658]: use of an internal attribute
   --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:14:1
    |
 LL | #![rustc_main]
    | ^^^^^^^^^^^^^^
    |
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: the `#[rustc_main]` attribute is an internal implementation detail that will never be stable
+   = note: the `#[rustc_main]` attribute is used internally to specify test entry point function
 
 error: valid forms for the attribute are `#[inline]` and `#[inline(always|never)]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:44:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:5
    |
 LL |     #[inline = "2100"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^
@@ -18,7 +19,7 @@ LL |     #[inline = "2100"] fn f() { }
    = note: `#[deny(ill_formed_attribute_input)]` on by default
 
 error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:30:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:32:1
    |
 LL |   #[inline]
    |   ^^^^^^^^^
@@ -29,7 +30,7 @@ LL | | }
    | |_- not a function or closure
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:63:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:65:1
    |
 LL |   #[no_link]
    |   ^^^^^^^^^^
@@ -43,7 +44,7 @@ LL | | }
    | |_- not an `extern crate` item
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:89:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:91:1
    |
 LL |   #[export_name = "2200"]
    |   ^^^^^^^^^^^^^^^^^^^^^^^
@@ -57,7 +58,7 @@ LL | | }
    | |_- not a free function, impl method or static
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:123:8
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:125:8
    |
 LL |   #[repr(C)]
    |          ^
@@ -70,7 +71,7 @@ LL | | }
    | |_- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:147:8
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:149:8
    |
 LL |   #[repr(Rust)]
    |          ^^^^
@@ -83,19 +84,19 @@ LL | | }
    | |_- not a struct, enum, or union
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:24:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:26:1
    |
 LL | #![no_link]
    | ^^^^^^^^^^^ not an `extern crate` item
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:26:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:1
    |
 LL | #![export_name = "2200"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^ not a free function, impl method or static
 
 error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:30:1
    |
 LL | #![inline]
    | ^^^^^^^^^^ not a function or closure
@@ -131,7 +132,7 @@ LL + #[rustc_main]
    |
 
 error: `path` attribute cannot be used at crate level
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:21:1
    |
 LL | #![path = "3800"]
    | ^^^^^^^^^^^^^^^^^
@@ -146,7 +147,7 @@ LL + #[path = "3800"]
    |
 
 error: `automatically_derived` attribute cannot be used at crate level
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:21:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:23:1
    |
 LL | #![automatically_derived]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -161,7 +162,7 @@ LL + #[automatically_derived]
    |
 
 error: `repr` attribute cannot be used at crate level
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:17:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1
    |
 LL | #![repr()]
    | ^^^^^^^^^^
@@ -176,139 +177,139 @@ LL + #[repr()]
    |
 
 error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:40:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:42:17
    |
 LL |     mod inner { #![inline] }
    |     ------------^^^^^^^^^^-- not a function or closure
 
 error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:50:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:52:5
    |
 LL |     #[inline] struct S;
    |     ^^^^^^^^^ --------- not a function or closure
 
 error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:54:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:56:5
    |
 LL |     #[inline] type T = S;
    |     ^^^^^^^^^ ----------- not a function or closure
 
 error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:58:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:60:5
    |
 LL |     #[inline] impl S { }
    |     ^^^^^^^^^ ---------- not a function or closure
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:68:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:70:17
    |
 LL |     mod inner { #![no_link] }
    |     ------------^^^^^^^^^^^-- not an `extern crate` item
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:72:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:74:5
    |
 LL |     #[no_link] fn f() { }
    |     ^^^^^^^^^^ ---------- not an `extern crate` item
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:76:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:78:5
    |
 LL |     #[no_link] struct S;
    |     ^^^^^^^^^^ --------- not an `extern crate` item
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:80:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:82:5
    |
 LL |     #[no_link]type T = S;
    |     ^^^^^^^^^^----------- not an `extern crate` item
 
 error: attribute should be applied to an `extern crate` item
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:84:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:86:5
    |
 LL |     #[no_link] impl S { }
    |     ^^^^^^^^^^ ---------- not an `extern crate` item
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:94:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:96:17
    |
 LL |     mod inner { #![export_name="2200"] }
    |     ------------^^^^^^^^^^^^^^^^^^^^^^-- not a free function, impl method or static
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:100:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:102:5
    |
 LL |     #[export_name = "2200"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:104:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:106:5
    |
 LL |     #[export_name = "2200"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:108:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:110:5
    |
 LL |     #[export_name = "2200"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a free function, impl method or static
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:113:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:115:9
    |
 LL |         #[export_name = "2200"] fn foo();
    |         ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static
 
 error: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:117:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:119:9
    |
 LL |         #[export_name = "2200"] fn bar() {}
    |         ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:127:25
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:129:25
    |
 LL |     mod inner { #![repr(C)] }
    |     --------------------^---- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:131:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:133:12
    |
 LL |     #[repr(C)] fn f() { }
    |            ^   ---------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:137:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:139:12
    |
 LL |     #[repr(C)] type T = S;
    |            ^   ----------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:141:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:143:12
    |
 LL |     #[repr(C)] impl S { }
    |            ^   ---------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:151:25
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:153:25
    |
 LL |     mod inner { #![repr(Rust)] }
    |     --------------------^^^^---- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:155:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:157:12
    |
 LL |     #[repr(Rust)] fn f() { }
    |            ^^^^   ---------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:161:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:163:12
    |
 LL |     #[repr(Rust)] type T = S;
    |            ^^^^   ----------- not a struct, enum, or union
 
 error[E0517]: attribute should be applied to a struct, enum, or union
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:165:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:167:12
    |
 LL |     #[repr(Rust)] impl S { }
    |            ^^^^   ---------- not a struct, enum, or union
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/format-no-std.rs b/tests/ui/fmt/format-macro-no-std.rs
index 657b210a9a0..d096b4de013 100644
--- a/tests/ui/format-no-std.rs
+++ b/tests/ui/fmt/format-macro-no-std.rs
@@ -1,3 +1,5 @@
+//! Test format! macro functionality in no_std environment
+
 //@ run-pass
 //@ ignore-emscripten no no_std executables
 //@ ignore-wasm different `main` convention
@@ -9,7 +11,8 @@
 // Import global allocator and panic handler.
 extern crate std as other;
 
-#[macro_use] extern crate alloc;
+#[macro_use]
+extern crate alloc;
 
 use alloc::string::ToString;
 
@@ -21,7 +24,7 @@ extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ff
     let s = format!("test");
     assert_eq!(s, "test".to_string());
 
-    let s = format!("{test}", test=3_isize);
+    let s = format!("{test}", test = 3_isize);
     assert_eq!(s, "3".to_string());
 
     let s = format!("hello {}", "world");
diff --git a/tests/ui/force-inlining/gate.rs b/tests/ui/force-inlining/gate.rs
index cea094c14f2..5918b0d4979 100644
--- a/tests/ui/force-inlining/gate.rs
+++ b/tests/ui/force-inlining/gate.rs
@@ -2,11 +2,15 @@
 #![allow(internal_features)]
 
 #[rustc_force_inline]
-//~^ ERROR #[rustc_force_inline] forces a free function to be inlined
+//~^ ERROR use of an internal attribute [E0658]
+//~| NOTE the `#[rustc_force_inline]` attribute is an internal implementation detail that will never be stable
+//~| NOTE `#[rustc_force_inline]` forces a free function to be inlined
 pub fn bare() {
 }
 
 #[rustc_force_inline = "the test requires it"]
-//~^ ERROR #[rustc_force_inline] forces a free function to be inlined
+//~^ ERROR use of an internal attribute [E0658]
+//~| NOTE the `#[rustc_force_inline]` attribute is an internal implementation detail that will never be stable
+//~| NOTE `#[rustc_force_inline]` forces a free function to be inlined
 pub fn justified() {
 }
diff --git a/tests/ui/force-inlining/gate.stderr b/tests/ui/force-inlining/gate.stderr
index 964d43fa18f..6c2df08b1a3 100644
--- a/tests/ui/force-inlining/gate.stderr
+++ b/tests/ui/force-inlining/gate.stderr
@@ -1,20 +1,22 @@
-error[E0658]: #[rustc_force_inline] forces a free function to be inlined
+error[E0658]: use of an internal attribute
   --> $DIR/gate.rs:4:1
    |
 LL | #[rustc_force_inline]
    | ^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: the `#[rustc_force_inline]` attribute is an internal implementation detail that will never be stable
+   = note: `#[rustc_force_inline]` forces a free function to be inlined
 
-error[E0658]: #[rustc_force_inline] forces a free function to be inlined
-  --> $DIR/gate.rs:9:1
+error[E0658]: use of an internal attribute
+  --> $DIR/gate.rs:11:1
    |
 LL | #[rustc_force_inline = "the test requires it"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: the `#[rustc_force_inline]` attribute is an internal implementation detail that will never be stable
+   = note: `#[rustc_force_inline]` forces a free function to be inlined
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/fun-indirect-call.rs b/tests/ui/fun-indirect-call.rs
deleted file mode 100644
index 7919be07f7e..00000000000
--- a/tests/ui/fun-indirect-call.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ run-pass
-
-fn f() -> isize { return 42; }
-
-pub fn main() {
-    let g: fn() -> isize = f;
-    let i: isize = g();
-    assert_eq!(i, 42);
-}
diff --git a/tests/ui/future-incompatible-lint-group.rs b/tests/ui/future-incompatible-lint-group.rs
deleted file mode 100644
index ed2c47bb609..00000000000
--- a/tests/ui/future-incompatible-lint-group.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-// Ensure that the future_incompatible lint group only includes
-// lints for changes that are not tied to an edition
-#![deny(future_incompatible)]
-
-// Error since this is a `future_incompatible` lint
-macro_rules! m { ($i) => {} } //~ ERROR missing fragment specifier
-                              //~| WARN this was previously accepted
-
-trait Tr {
-    // Warn only since this is not a `future_incompatible` lint
-    fn f(u8) {} //~ WARN anonymous parameters are deprecated
-                //~| WARN this is accepted in the current edition
-}
-
-fn main() {}
diff --git a/tests/ui/future-incompatible-lint-group.stderr b/tests/ui/future-incompatible-lint-group.stderr
deleted file mode 100644
index 4c867e0aab3..00000000000
--- a/tests/ui/future-incompatible-lint-group.stderr
+++ /dev/null
@@ -1,43 +0,0 @@
-error: missing fragment specifier
-  --> $DIR/future-incompatible-lint-group.rs:6:19
-   |
-LL | macro_rules! m { ($i) => {} }
-   |                   ^^
-   |
-   = 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 #40107 <https://github.com/rust-lang/rust/issues/40107>
-note: the lint level is defined here
-  --> $DIR/future-incompatible-lint-group.rs:3:9
-   |
-LL | #![deny(future_incompatible)]
-   |         ^^^^^^^^^^^^^^^^^^^
-   = note: `#[deny(missing_fragment_specifier)]` implied by `#[deny(future_incompatible)]`
-
-warning: anonymous parameters are deprecated and will be removed in the next edition
-  --> $DIR/future-incompatible-lint-group.rs:11:10
-   |
-LL |     fn f(u8) {}
-   |          ^^ help: try naming the parameter or explicitly ignoring it: `_: u8`
-   |
-   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
-   = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
-   = note: `#[warn(anonymous_parameters)]` on by default
-
-error: aborting due to 1 previous error; 1 warning emitted
-
-Future incompatibility report: Future breakage diagnostic:
-error: missing fragment specifier
-  --> $DIR/future-incompatible-lint-group.rs:6:19
-   |
-LL | macro_rules! m { ($i) => {} }
-   |                   ^^
-   |
-   = 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 #40107 <https://github.com/rust-lang/rust/issues/40107>
-note: the lint level is defined here
-  --> $DIR/future-incompatible-lint-group.rs:3:9
-   |
-LL | #![deny(future_incompatible)]
-   |         ^^^^^^^^^^^^^^^^^^^
-   = note: `#[deny(missing_fragment_specifier)]` implied by `#[deny(future_incompatible)]`
-
diff --git a/tests/ui/generics/empty-generic-brackets-equiv.rs b/tests/ui/generics/empty-generic-brackets-equiv.rs
new file mode 100644
index 00000000000..d84498a60f8
--- /dev/null
+++ b/tests/ui/generics/empty-generic-brackets-equiv.rs
@@ -0,0 +1,27 @@
+//! Test that empty type parameter list <> is equivalent to no type parameters
+//!
+//! Checks` that empty angle brackets <> are syntactically valid and equivalent
+//! to omitting type parameters entirely across various language constructs.
+
+//@ run-pass
+
+struct S<>;
+trait T<> {} //~ WARN trait `T` is never used
+enum E<> {
+    V
+}
+impl<> T<> for S<> {}
+impl T for E {}
+fn foo<>() {}
+fn bar() {}
+fn main() {
+    let _ = S;
+    let _ = S::<>;
+    let _ = E::V;
+    let _ = E::<>::V;
+    foo();
+    foo::<>();
+    // Test that we can supply <> to non-generic things
+    bar::<>();
+    let _: i32<>;
+}
diff --git a/tests/ui/empty-type-parameter-list.stderr b/tests/ui/generics/empty-generic-brackets-equiv.stderr
index 31a5015e993..151ee4697b4 100644
--- a/tests/ui/empty-type-parameter-list.stderr
+++ b/tests/ui/generics/empty-generic-brackets-equiv.stderr
@@ -1,5 +1,5 @@
 warning: trait `T` is never used
-  --> $DIR/empty-type-parameter-list.rs:6:7
+  --> $DIR/empty-generic-brackets-equiv.rs:9:7
    |
 LL | trait T<> {}
    |       ^
diff --git a/tests/ui/global-scope.rs b/tests/ui/global-scope.rs
deleted file mode 100644
index 33b56bca940..00000000000
--- a/tests/ui/global-scope.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-//@ run-pass
-
-pub fn f() -> isize { return 1; }
-
-pub mod foo {
-    pub fn f() -> isize { return 2; }
-    pub fn g() {
-        assert_eq!(f(), 2);
-        assert_eq!(::f(), 1);
-    }
-}
-
-pub fn main() { return foo::g(); }
diff --git a/tests/ui/hello.rs b/tests/ui/hello.rs
deleted file mode 100644
index f329ee086f9..00000000000
--- a/tests/ui/hello.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-//@ run-pass
-//@ revisions: e2015 e2018 e2021 e2024
-
-//@[e2018] edition:2018
-//@[e2021] edition:2021
-//@[e2024] edition:2024
-
-fn main() {
-    println!("hello");
-}
diff --git a/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr b/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr
index 54ceec0aff5..5caf0eb2fd4 100644
--- a/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr
+++ b/tests/ui/impl-trait/auto-trait-selection-freeze.next.stderr
@@ -1,9 +1,22 @@
-error[E0284]: type annotations needed: cannot satisfy `impl Sized == _`
-  --> $DIR/auto-trait-selection-freeze.rs:19:5
+error[E0283]: type annotations needed
+  --> $DIR/auto-trait-selection-freeze.rs:19:16
    |
 LL |     if false { is_trait(foo()) } else { Default::default() }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `impl Sized == _`
+   |                ^^^^^^^^ ----- type must be known at this point
+   |                |
+   |                cannot infer type of the type parameter `T` declared on the function `is_trait`
+   |
+   = note: cannot satisfy `_: Trait<_>`
+note: required by a bound in `is_trait`
+  --> $DIR/auto-trait-selection-freeze.rs:11:16
+   |
+LL | fn is_trait<T: Trait<U>, U: Default>(_: T) -> U {
+   |                ^^^^^^^^ required by this bound in `is_trait`
+help: consider specifying the generic arguments
+   |
+LL |     if false { is_trait::<T, U>(foo()) } else { Default::default() }
+   |                        ++++++++
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0284`.
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/impl-trait/auto-trait-selection.next.stderr b/tests/ui/impl-trait/auto-trait-selection.next.stderr
index 7acb9fd41b7..d34fdcc4496 100644
--- a/tests/ui/impl-trait/auto-trait-selection.next.stderr
+++ b/tests/ui/impl-trait/auto-trait-selection.next.stderr
@@ -1,9 +1,22 @@
-error[E0284]: type annotations needed: cannot satisfy `impl Sized == _`
-  --> $DIR/auto-trait-selection.rs:15:5
+error[E0283]: type annotations needed
+  --> $DIR/auto-trait-selection.rs:15:16
    |
 LL |     if false { is_trait(foo()) } else { Default::default() }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `impl Sized == _`
+   |                ^^^^^^^^ ----- type must be known at this point
+   |                |
+   |                cannot infer type of the type parameter `T` declared on the function `is_trait`
+   |
+   = note: cannot satisfy `_: Trait<_>`
+note: required by a bound in `is_trait`
+  --> $DIR/auto-trait-selection.rs:7:16
+   |
+LL | fn is_trait<T: Trait<U>, U: Default>(_: T) -> U {
+   |                ^^^^^^^^ required by this bound in `is_trait`
+help: consider specifying the generic arguments
+   |
+LL |     if false { is_trait::<T, U>(foo()) } else { Default::default() }
+   |                        ++++++++
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0284`.
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr
index 9632d2ce624..f2e249f2cbf 100644
--- a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr
+++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr
@@ -25,7 +25,7 @@ LL |     type LineStream<'c, 'd> = impl Stream;
    |
    = note: `LineStream` must be used in combination with a concrete type within the same impl
 
-error[E0271]: type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()`
+error[E0271]: type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to ()`
   --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:29:43
    |
 LL |     fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}
diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs
index 0b507ed948a..7cf155ce01e 100644
--- a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs
+++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs
@@ -29,7 +29,7 @@ impl X for Y {
     fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {}
     //~^ ERROR method `line_stream` is not a member of trait `X`
     //[current]~^^ ERROR `()` is not a future
-    //[next]~^^^ ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()`
+    //[next]~^^^ ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to ()`
     //[next]~| ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to _`
     //[next]~| ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> normalizes-to _`
 }
diff --git a/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr
index ba7d7770e50..53c55686604 100644
--- a/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr
+++ b/tests/ui/impl-trait/must_outlive_least_region_or_bound.stderr
@@ -65,9 +65,12 @@ error[E0621]: explicit lifetime required in the type of `x`
   --> $DIR/must_outlive_least_region_or_bound.rs:15:41
    |
 LL | fn foo<'a>(x: &i32) -> impl Copy + 'a { x }
-   |               ----                      ^ lifetime `'a` required
-   |               |
-   |               help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
+   |                                         ^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to the type of `x`
+   |
+LL | fn foo<'a>(x: &'a i32) -> impl Copy + 'a { x }
+   |                ++
 
 error: lifetime may not live long enough
   --> $DIR/must_outlive_least_region_or_bound.rs:30:55
diff --git a/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr b/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr
index 132f7de4ef2..5ce6eb0fc39 100644
--- a/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr
+++ b/tests/ui/impl-trait/recursive-coroutine-boxed.next.stderr
@@ -1,5 +1,5 @@
 error[E0282]: type annotations needed
-  --> $DIR/recursive-coroutine-boxed.rs:14:23
+  --> $DIR/recursive-coroutine-boxed.rs:11:23
    |
 LL |         let mut gen = Box::pin(foo());
    |                       ^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `Box`
diff --git a/tests/ui/impl-trait/recursive-coroutine-boxed.rs b/tests/ui/impl-trait/recursive-coroutine-boxed.rs
index 8d38e6aed12..306edc3591e 100644
--- a/tests/ui/impl-trait/recursive-coroutine-boxed.rs
+++ b/tests/ui/impl-trait/recursive-coroutine-boxed.rs
@@ -7,9 +7,6 @@
 use std::ops::{Coroutine, CoroutineState};
 
 fn foo() -> impl Coroutine<Yield = (), Return = ()> {
-    // FIXME(-Znext-solver): this fails with a mismatched types as the
-    // hidden type of the opaque ends up as {type error}. We should not
-    // emit errors for such goals.
     #[coroutine] || {
         let mut gen = Box::pin(foo());
         //[next]~^ ERROR type annotations needed
diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr
index a3609b93cb3..db57be73acc 100644
--- a/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr
+++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.next.stderr
@@ -1,8 +1,8 @@
-error[E0284]: type annotations needed: cannot satisfy `impl Sized == _`
-  --> $DIR/recursive-in-exhaustiveness.rs:19:17
+error[E0284]: type annotations needed: cannot normalize `build<_>::{opaque#0}`
+  --> $DIR/recursive-in-exhaustiveness.rs:20:5
    |
-LL |     let (x,) = (build(x),);
-   |                 ^^^^^^^^ cannot satisfy `impl Sized == _`
+LL |     build(x)
+   |     ^^^^^^^^ cannot normalize `build<_>::{opaque#0}`
 
 error[E0271]: type mismatch resolving `build2<(_,)>::{opaque#0} normalizes-to _`
   --> $DIR/recursive-in-exhaustiveness.rs:30:6
diff --git a/tests/ui/impl-trait/recursive-in-exhaustiveness.rs b/tests/ui/impl-trait/recursive-in-exhaustiveness.rs
index fa8fa0e8174..dabef22af86 100644
--- a/tests/ui/impl-trait/recursive-in-exhaustiveness.rs
+++ b/tests/ui/impl-trait/recursive-in-exhaustiveness.rs
@@ -17,8 +17,8 @@
 fn build<T>(x: T) -> impl Sized {
     //[current]~^ ERROR cannot resolve opaque type
     let (x,) = (build(x),);
-    //[next]~^ ERROR type annotations needed
     build(x)
+    //[next]~^ ERROR type annotations needed: cannot normalize `build<_>::{opaque#0}`
 }
 
 // Opaque<T> = (Opaque<T>,)
diff --git a/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr b/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr
index 1a4c0f5f7ee..fac4776905d 100644
--- a/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr
+++ b/tests/ui/impl-trait/two_tait_defining_each_other2.next.stderr
@@ -1,9 +1,9 @@
-error[E0284]: type annotations needed: cannot satisfy `_ == A`
-  --> $DIR/two_tait_defining_each_other2.rs:12:8
+error[E0282]: type annotations needed
+  --> $DIR/two_tait_defining_each_other2.rs:12:11
    |
 LL | fn muh(x: A) -> B {
-   |        ^ cannot satisfy `_ == A`
+   |           ^ cannot infer type
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0284`.
+For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/impl-trait/two_tait_defining_each_other2.rs b/tests/ui/impl-trait/two_tait_defining_each_other2.rs
index 6c454bba502..ec2963249f9 100644
--- a/tests/ui/impl-trait/two_tait_defining_each_other2.rs
+++ b/tests/ui/impl-trait/two_tait_defining_each_other2.rs
@@ -10,7 +10,7 @@ trait Foo {}
 
 #[define_opaque(A, B)]
 fn muh(x: A) -> B {
-    //[next]~^ ERROR: cannot satisfy `_ == A`
+    //[next]~^ ERROR: type annotations needed
     x // B's hidden type is A (opaquely)
     //[current]~^ ERROR opaque type's hidden type cannot be another opaque type
 }
diff --git a/tests/ui/include-macros/parent_dir.rs b/tests/ui/include-macros/parent_dir.rs
index 1dcf27324d1..9a81a6deeb1 100644
--- a/tests/ui/include-macros/parent_dir.rs
+++ b/tests/ui/include-macros/parent_dir.rs
@@ -3,8 +3,6 @@
 fn main() {
     let _ = include_str!("include-macros/file.txt");            //~ ERROR couldn't read
                                                                 //~^HELP different directory
-    let _ = include_str!("hello.rs");                           //~ ERROR couldn't read
-                                                                //~^HELP different directory
     let _ = include_bytes!("../../data.bin");                   //~ ERROR couldn't read
                                                                 //~^HELP different directory
     let _ = include_str!("tests/ui/include-macros/file.txt");   //~ ERROR couldn't read
diff --git a/tests/ui/include-macros/parent_dir.stderr b/tests/ui/include-macros/parent_dir.stderr
index 4ee6fe104b0..7a18b1de5d1 100644
--- a/tests/ui/include-macros/parent_dir.stderr
+++ b/tests/ui/include-macros/parent_dir.stderr
@@ -10,19 +10,8 @@ LL -     let _ = include_str!("include-macros/file.txt");
 LL +     let _ = include_str!("file.txt");
    |
 
-error: couldn't read `$DIR/hello.rs`: $FILE_NOT_FOUND_MSG
-  --> $DIR/parent_dir.rs:6:13
-   |
-LL |     let _ = include_str!("hello.rs");
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: there is a file with the same name in a different directory
-   |
-LL |     let _ = include_str!("../hello.rs");
-   |                           +++
-
 error: couldn't read `$DIR/../../data.bin`: $FILE_NOT_FOUND_MSG
-  --> $DIR/parent_dir.rs:8:13
+  --> $DIR/parent_dir.rs:6:13
    |
 LL |     let _ = include_bytes!("../../data.bin");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -34,7 +23,7 @@ LL +     let _ = include_bytes!("data.bin");
    |
 
 error: couldn't read `$DIR/tests/ui/include-macros/file.txt`: $FILE_NOT_FOUND_MSG
-  --> $DIR/parent_dir.rs:10:13
+  --> $DIR/parent_dir.rs:8:13
    |
 LL |     let _ = include_str!("tests/ui/include-macros/file.txt");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -45,5 +34,5 @@ LL -     let _ = include_str!("tests/ui/include-macros/file.txt");
 LL +     let _ = include_str!("file.txt");
    |
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/inline-const/break-inside-inline-const-issue-128604.rs b/tests/ui/inline-const/break-inside-inline-const-issue-128604.rs
index a9795d1569c..cc0d757885d 100644
--- a/tests/ui/inline-const/break-inside-inline-const-issue-128604.rs
+++ b/tests/ui/inline-const/break-inside-inline-const-issue-128604.rs
@@ -23,3 +23,9 @@ fn main() {
         }
     }
 }
+
+const FOO: () = break;
+//~^ ERROR: `break` outside of a loop or labeled block
+
+static BAR: () = break;
+//~^ ERROR: `break` outside of a loop or labeled block
diff --git a/tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr b/tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr
index 300cd45ad69..6a967c59864 100644
--- a/tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr
+++ b/tests/ui/inline-const/break-inside-inline-const-issue-128604.stderr
@@ -11,6 +11,19 @@ LL |             break;
    |             ^^^^^ cannot `break` outside of a loop or labeled block
 
 error[E0268]: `break` outside of a loop or labeled block
+  --> $DIR/break-inside-inline-const-issue-128604.rs:9:13
+   |
+LL |             break;
+   |             ^^^^^ cannot `break` outside of a loop or labeled block
+   |
+help: consider labeling this block to be able to break within it
+   |
+LL ~         'block: {
+LL |
+LL ~             break 'block;
+   |
+
+error[E0268]: `break` outside of a loop or labeled block
   --> $DIR/break-inside-inline-const-issue-128604.rs:2:21
    |
 LL |     let _ = ['a'; { break 2; 1 }];
@@ -22,18 +35,17 @@ LL |     let _ = ['a'; 'block: { break 'block 2; 1 }];
    |                   +++++++         ++++++
 
 error[E0268]: `break` outside of a loop or labeled block
-  --> $DIR/break-inside-inline-const-issue-128604.rs:9:13
-   |
-LL |             break;
-   |             ^^^^^ cannot `break` outside of a loop or labeled block
-   |
-help: consider labeling this block to be able to break within it
+  --> $DIR/break-inside-inline-const-issue-128604.rs:27:17
    |
-LL ~         'block: {
-LL |
-LL ~             break 'block;
+LL | const FOO: () = break;
+   |                 ^^^^^ cannot `break` outside of a loop or labeled block
+
+error[E0268]: `break` outside of a loop or labeled block
+  --> $DIR/break-inside-inline-const-issue-128604.rs:30:18
    |
+LL | static BAR: () = break;
+   |                  ^^^^^ cannot `break` outside of a loop or labeled block
 
-error: aborting due to 4 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0268`.
diff --git a/tests/ui/inline-const/cross-const-control-flow-125846.stderr b/tests/ui/inline-const/cross-const-control-flow-125846.stderr
index 0a910e70d09..5ea571fe98a 100644
--- a/tests/ui/inline-const/cross-const-control-flow-125846.stderr
+++ b/tests/ui/inline-const/cross-const-control-flow-125846.stderr
@@ -39,6 +39,16 @@ LL |     const { async {}.await }
    |           |          only allowed inside `async` functions and blocks
    |           this is not `async`
 
+error[E0572]: return statement outside of function body
+  --> $DIR/cross-const-control-flow-125846.rs:4:13
+   |
+LL | / fn foo() {
+LL | |     const { return }
+   | |           --^^^^^^-- the return is part of this body...
+LL | |
+LL | | }
+   | |_- ...not the enclosing function body
+
 error[E0268]: `break` outside of a loop or labeled block
   --> $DIR/cross-const-control-flow-125846.rs:9:19
    |
@@ -63,16 +73,6 @@ error[E0268]: `continue` outside of a loop
 LL |         const { continue }
    |                 ^^^^^^^^ cannot `continue` outside of a loop
 
-error[E0572]: return statement outside of function body
-  --> $DIR/cross-const-control-flow-125846.rs:4:13
-   |
-LL | / fn foo() {
-LL | |     const { return }
-   | |           --^^^^^^-- the return is part of this body...
-LL | |
-LL | | }
-   | |_- ...not the enclosing function body
-
 error: aborting due to 9 previous errors
 
 Some errors have detailed explanations: E0268, E0435, E0572, E0728, E0767.
diff --git a/tests/ui/intrinsics/intrinsic-alignment.rs b/tests/ui/intrinsics/intrinsic-alignment.rs
index 30a523f364c..904da71c306 100644
--- a/tests/ui/intrinsics/intrinsic-alignment.rs
+++ b/tests/ui/intrinsics/intrinsic-alignment.rs
@@ -23,12 +23,12 @@ use std::intrinsics as rusti;
 mod m {
     #[cfg(target_arch = "x86")]
     pub fn main() {
-        assert_eq!(crate::rusti::min_align_of::<u64>(), 4);
+        assert_eq!(crate::rusti::align_of::<u64>(), 4);
     }
 
     #[cfg(not(target_arch = "x86"))]
     pub fn main() {
-        assert_eq!(crate::rusti::min_align_of::<u64>(), 8);
+        assert_eq!(crate::rusti::align_of::<u64>(), 8);
     }
 }
 
@@ -36,21 +36,21 @@ mod m {
 mod m {
     #[cfg(target_arch = "x86_64")]
     pub fn main() {
-        assert_eq!(crate::rusti::min_align_of::<u64>(), 8);
+        assert_eq!(crate::rusti::align_of::<u64>(), 8);
     }
 }
 
 #[cfg(target_os = "windows")]
 mod m {
     pub fn main() {
-        assert_eq!(crate::rusti::min_align_of::<u64>(), 8);
+        assert_eq!(crate::rusti::align_of::<u64>(), 8);
     }
 }
 
 #[cfg(target_family = "wasm")]
 mod m {
     pub fn main() {
-        assert_eq!(crate::rusti::min_align_of::<u64>(), 8);
+        assert_eq!(crate::rusti::align_of::<u64>(), 8);
     }
 }
 
diff --git a/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr
index d92836aa063..8d120ae98d9 100644
--- a/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr
+++ b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr
@@ -19,7 +19,7 @@ LL |     std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, 5 + || ());
 help: try using a const generic argument instead
    |
 LL -     std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, 5 + || ());
-LL +     std::arch::x86_64::_mm_blend_ps::<{ 5 + (|| ()) }>(loop {}, loop {});
+LL +     std::arch::x86_64::_mm_blend_ps::<{ 5 + || () }>(loop {}, loop {});
    |
 
 error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items
@@ -81,7 +81,7 @@ LL |     std::arch::x86_64::_mm_inserti_si64(loop {}, loop {}, || (), 1 + || ())
 help: try using a const generic argument instead
    |
 LL -     std::arch::x86_64::_mm_inserti_si64(loop {}, loop {}, || (), 1 + || ());
-LL +     std::arch::x86_64::_mm_inserti_si64::<{ || () }, { 1 + (|| ()) }>(loop {}, loop {});
+LL +     std::arch::x86_64::_mm_inserti_si64::<{ || () }, { 1 + || () }>(loop {}, loop {});
    |
 
 error: aborting due to 7 previous errors
diff --git a/tests/ui/issues/issue-13058.stderr b/tests/ui/issues/issue-13058.stderr
index 7cc2860eb50..4f4108fa182 100644
--- a/tests/ui/issues/issue-13058.stderr
+++ b/tests/ui/issues/issue-13058.stderr
@@ -1,11 +1,13 @@
 error[E0621]: explicit lifetime required in the type of `cont`
   --> $DIR/issue-13058.rs:14:21
    |
-LL | fn check<'r, I: Iterator<Item=usize>, T: Itble<'r, usize, I>>(cont: &T) -> bool
-   |                                                                     -- help: add explicit lifetime `'r` to the type of `cont`: `&'r T`
-LL | {
 LL |     let cont_iter = cont.iter();
    |                     ^^^^^^^^^^^ lifetime `'r` required
+   |
+help: add explicit lifetime `'r` to the type of `cont`
+   |
+LL | fn check<'r, I: Iterator<Item=usize>, T: Itble<'r, usize, I>>(cont: &'r T) -> bool
+   |                                                                      ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-14285.stderr b/tests/ui/issues/issue-14285.stderr
index 4f89ae51157..edd139eecba 100644
--- a/tests/ui/issues/issue-14285.stderr
+++ b/tests/ui/issues/issue-14285.stderr
@@ -1,10 +1,14 @@
 error[E0621]: explicit lifetime required in the type of `a`
   --> $DIR/issue-14285.rs:12:5
    |
-LL | fn foo<'a>(a: &dyn Foo) -> B<'a> {
-   |               -------- help: add explicit lifetime `'a` to the type of `a`: `&'a (dyn Foo + 'a)`
 LL |     B(a)
    |     ^^^^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to the type of `a`
+   |
+LL - fn foo<'a>(a: &dyn Foo) -> B<'a> {
+LL + fn foo<'a>(a: &'a (dyn Foo + 'a)) -> B<'a> {
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-15034.stderr b/tests/ui/issues/issue-15034.stderr
index 587a5c85e92..7db8ade2e48 100644
--- a/tests/ui/issues/issue-15034.stderr
+++ b/tests/ui/issues/issue-15034.stderr
@@ -1,10 +1,13 @@
 error[E0621]: explicit lifetime required in the type of `lexer`
   --> $DIR/issue-15034.rs:17:9
    |
-LL |     pub fn new(lexer: &'a mut Lexer) -> Parser<'a> {
-   |                       ------------- help: add explicit lifetime `'a` to the type of `lexer`: `&'a mut Lexer<'a>`
 LL |         Parser { lexer: lexer }
    |         ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to the type of `lexer`
+   |
+LL |     pub fn new(lexer: &'a mut Lexer<'a>) -> Parser<'a> {
+   |                                    ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-28561.rs b/tests/ui/issues/issue-28561.rs
index f9b0ceb22fc..642b2193a4f 100644
--- a/tests/ui/issues/issue-28561.rs
+++ b/tests/ui/issues/issue-28561.rs
@@ -37,6 +37,7 @@ struct Array<T> {
 }
 
 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[allow(unpredictable_function_pointer_comparisons)]
 struct Fn<A, B, C, D, E, F, G, H, I, J, K, L> {
     f00: fn(),
     f01: fn(A),
diff --git a/tests/ui/issues/issue-3154.stderr b/tests/ui/issues/issue-3154.stderr
index 3106aaddc4a..c17e59f7fc3 100644
--- a/tests/ui/issues/issue-3154.stderr
+++ b/tests/ui/issues/issue-3154.stderr
@@ -1,10 +1,13 @@
 error[E0621]: explicit lifetime required in the type of `x`
   --> $DIR/issue-3154.rs:6:5
    |
-LL | fn thing<'a,Q>(x: &Q) -> Thing<'a,Q> {
-   |                   -- help: add explicit lifetime `'a` to the type of `x`: `&'a Q`
 LL |     Thing { x: x }
    |     ^^^^^^^^^^^^^^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to the type of `x`
+   |
+LL | fn thing<'a,Q>(x: &'a Q) -> Thing<'a,Q> {
+   |                    ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-40288-2.stderr b/tests/ui/issues/issue-40288-2.stderr
index 2c64856b08f..81cb7cdd51f 100644
--- a/tests/ui/issues/issue-40288-2.stderr
+++ b/tests/ui/issues/issue-40288-2.stderr
@@ -1,20 +1,24 @@
 error[E0621]: explicit lifetime required in the type of `y`
   --> $DIR/issue-40288-2.rs:9:5
    |
-LL | fn lifetime_transmute_slice<'a, T: ?Sized>(x: &'a T, y: &T) -> &'a T {
-   |                                                         -- help: add explicit lifetime `'a` to the type of `y`: `&'a T`
-...
 LL |     out[0]
    |     ^^^^^^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to the type of `y`
+   |
+LL | fn lifetime_transmute_slice<'a, T: ?Sized>(x: &'a T, y: &'a T) -> &'a T {
+   |                                                          ++
 
 error[E0621]: explicit lifetime required in the type of `y`
   --> $DIR/issue-40288-2.rs:24:5
    |
-LL | fn lifetime_transmute_struct<'a, T: ?Sized>(x: &'a T, y: &T) -> &'a T {
-   |                                                          -- help: add explicit lifetime `'a` to the type of `y`: `&'a T`
-...
 LL |     out.head
    |     ^^^^^^^^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to the type of `y`
+   |
+LL | fn lifetime_transmute_struct<'a, T: ?Sized>(x: &'a T, y: &'a T) -> &'a T {
+   |                                                           ++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr b/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr
index 1a43fd4ad18..5f6a6099ba2 100644
--- a/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr
+++ b/tests/ui/layout/invalid-unsized-in-always-sized-tail.stderr
@@ -24,7 +24,7 @@ error[E0080]: the type `MySlice<[bool]>` has an unknown layout
 LL | static CHECK: () = assert!(align_of::<P2>() == 1);
    |                            ^^^^^^^^^^^^^^^^ evaluation of `CHECK` failed inside this call
    |
-note: inside `align_of::<P2>`
+note: inside `std::mem::align_of::<P2>`
   --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/lifetimes/lifetime-errors/42701_one_named_and_one_anonymous.stderr b/tests/ui/lifetimes/lifetime-errors/42701_one_named_and_one_anonymous.stderr
index af22078aff5..c524aabfacb 100644
--- a/tests/ui/lifetimes/lifetime-errors/42701_one_named_and_one_anonymous.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/42701_one_named_and_one_anonymous.stderr
@@ -1,11 +1,13 @@
 error[E0621]: explicit lifetime required in the type of `x`
   --> $DIR/42701_one_named_and_one_anonymous.rs:10:9
    |
-LL | fn foo2<'a>(a: &'a Foo, x: &i32) -> &'a i32 {
-   |                            ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
-...
 LL |         &*x
    |         ^^^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to the type of `x`
+   |
+LL | fn foo2<'a>(a: &'a Foo, x: &'a i32) -> &'a i32 {
+   |                             ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.stderr
index e202c31214d..44a542eeeeb 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-early-bound-in-struct.stderr
@@ -1,11 +1,13 @@
 error[E0621]: explicit lifetime required in the type of `other`
   --> $DIR/ex1-return-one-existing-name-early-bound-in-struct.rs:11:21
    |
-LL |     fn bar(&self, other: Foo) -> Foo<'a> {
-   |                          --- help: add explicit lifetime `'a` to the type of `other`: `Foo<'a>`
-...
 LL |                     other
    |                     ^^^^^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to the type of `other`
+   |
+LL |     fn bar(&self, other: Foo<'a>) -> Foo<'a> {
+   |                             ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-2.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-2.stderr
index 5518ded0106..52cf8595448 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-2.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-2.stderr
@@ -1,10 +1,13 @@
 error[E0621]: explicit lifetime required in the type of `x`
   --> $DIR/ex1-return-one-existing-name-if-else-2.rs:2:16
    |
-LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 {
-   |               ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
 LL |     if x > y { x } else { y }
    |                ^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to the type of `x`
+   |
+LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
+   |                ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-3.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-3.stderr
index c689fa9884a..fbd9695e85f 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-3.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-3.stderr
@@ -1,10 +1,13 @@
 error[E0621]: explicit lifetime required in parameter type
   --> $DIR/ex1-return-one-existing-name-if-else-3.rs:2:27
    |
-LL | fn foo<'a>((x, y): (&'a i32, &i32)) -> &'a i32 {
-   |                    --------------- help: add explicit lifetime `'a` to type: `(&'a i32, &'a i32)`
 LL |     if x > y { x } else { y }
    |                           ^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to type
+   |
+LL | fn foo<'a>((x, y): (&'a i32, &'a i32)) -> &'a i32 {
+   |                               ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr
index 3da50cfbb1d..c875381c615 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-2.stderr
@@ -1,10 +1,13 @@
 error[E0621]: explicit lifetime required in the type of `x`
   --> $DIR/ex1-return-one-existing-name-if-else-using-impl-2.rs:4:15
    |
-LL | fn foo<'a>(x: &i32, y: &'a i32) -> &'a i32 {
-   |               ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
 LL |    if x > y { x } else { y }
    |               ^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to the type of `x`
+   |
+LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
+   |                ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr
index 071bda24ef8..83cd11baf39 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl-3.stderr
@@ -1,10 +1,13 @@
 error[E0621]: explicit lifetime required in the type of `x`
   --> $DIR/ex1-return-one-existing-name-if-else-using-impl-3.rs:7:36
    |
-LL |   fn foo<'a>(&'a self, x: &i32) -> &i32 {
-   |                           ---- help: add explicit lifetime `'a` to the type of `x`: `&'a i32`
 LL |     if true { &self.field } else { x }
    |                                    ^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to the type of `x`
+   |
+LL |   fn foo<'a>(&'a self, x: &'a i32) -> &i32 {
+   |                            ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else.stderr
index 1df0776a51b..bf09bd26359 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else.stderr
@@ -1,10 +1,13 @@
 error[E0621]: explicit lifetime required in the type of `y`
   --> $DIR/ex1-return-one-existing-name-if-else.rs:2:27
    |
-LL | fn foo<'a>(x: &'a i32, y: &i32) -> &'a i32 {
-   |                           ---- help: add explicit lifetime `'a` to the type of `y`: `&'a i32`
 LL |     if x > y { x } else { y }
    |                           ^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to the type of `y`
+   |
+LL | fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
+   |                            ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.stderr b/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.stderr
index 25a2f4b96f4..f37e1ba00e7 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-2.stderr
@@ -1,10 +1,13 @@
 error[E0621]: explicit lifetime required in the type of `x`
   --> $DIR/ex2a-push-one-existing-name-2.rs:6:5
    |
-LL | fn foo<'a>(x: Ref<i32>, y: &mut Vec<Ref<'a, i32>>) {
-   |               -------- help: add explicit lifetime `'a` to the type of `x`: `Ref<'a, i32>`
 LL |     y.push(x);
    |     ^^^^^^^^^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to the type of `x`
+   |
+LL | fn foo<'a>(x: Ref<'a, i32>, y: &mut Vec<Ref<'a, i32>>) {
+   |                   +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.stderr b/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.stderr
index e2725977d83..c25b4c9921f 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name-early-bound.stderr
@@ -1,11 +1,13 @@
 error[E0621]: explicit lifetime required in the type of `y`
   --> $DIR/ex2a-push-one-existing-name-early-bound.rs:8:5
    |
-LL | fn baz<'a, 'b, T>(x: &mut Vec<&'a T>, y: &T)
-   |                                          -- help: add explicit lifetime `'a` to the type of `y`: `&'a T`
-...
 LL |     x.push(y);
    |     ^^^^^^^^^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to the type of `y`
+   |
+LL | fn baz<'a, 'b, T>(x: &mut Vec<&'a T>, y: &'a T)
+   |                                           ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.stderr b/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.stderr
index 1025581d5ac..8c7bee4bfc4 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex2a-push-one-existing-name.stderr
@@ -1,10 +1,13 @@
 error[E0621]: explicit lifetime required in the type of `y`
   --> $DIR/ex2a-push-one-existing-name.rs:6:5
    |
-LL | fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<i32>) {
-   |                                          -------- help: add explicit lifetime `'a` to the type of `y`: `Ref<'a, i32>`
 LL |     x.push(y);
    |     ^^^^^^^^^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to the type of `y`
+   |
+LL | fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<'a, i32>) {
+   |                                              +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/noisy-follow-up-erro.stderr b/tests/ui/lifetimes/noisy-follow-up-erro.stderr
index 04863badbd1..eb52147dba4 100644
--- a/tests/ui/lifetimes/noisy-follow-up-erro.stderr
+++ b/tests/ui/lifetimes/noisy-follow-up-erro.stderr
@@ -15,11 +15,14 @@ LL | struct Foo<'c, 'd>(&'c (), &'d ());
 error[E0621]: explicit lifetime required in the type of `foo`
   --> $DIR/noisy-follow-up-erro.rs:14:9
    |
-LL |     fn boom(&self, foo: &mut Foo<'_, '_, 'a>) -> Result<(), &'a ()> {
-   |                         -------------------- help: add explicit lifetime `'a` to the type of `foo`: `&mut Foo<'_, 'a>`
-LL |
 LL |         self.bar().map_err(|()| foo.acc(self))?;
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to the type of `foo`
+   |
+LL -     fn boom(&self, foo: &mut Foo<'_, '_, 'a>) -> Result<(), &'a ()> {
+LL +     fn boom(&self, foo: &mut Foo<'_, 'a>) -> Result<(), &'a ()> {
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs
index df69782e154..9babc20d1a1 100644
--- a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs
+++ b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.rs
@@ -1,6 +1,14 @@
-//@ only-x86_64
-//@ only-windows
+//@ add-core-stubs
+//@ compile-flags: --target x86_64-pc-windows-msvc
 //@ compile-flags: --crate-type lib --emit link
+//@ needs-llvm-components: x86
+#![no_core]
+#![feature(no_core)]
+extern crate minicore;
+
+// It may seem weird this is a cross-platform-testable thing, since doesn't it test linkage?
+// However the main thing we are testing is an *error*, so it works fine!
+
 #[link(name = "foo", kind = "raw-dylib")]
 extern "stdcall" {
 //~^ WARN: calling convention not supported on this target
diff --git a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr
index e7a32f4c84b..95ea9080486 100644
--- a/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr
+++ b/tests/ui/linkage-attr/raw-dylib/windows/unsupported-abi.stderr
@@ -1,5 +1,5 @@
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported-abi.rs:5:1
+  --> $DIR/unsupported-abi.rs:13:1
    |
 LL | / extern "stdcall" {
 LL | |
@@ -15,27 +15,10 @@ LL | | }
    = note: `#[warn(unsupported_calling_conventions)]` on by default
 
 error: ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
-  --> $DIR/unsupported-abi.rs:8:5
+  --> $DIR/unsupported-abi.rs:16:5
    |
 LL |     fn f(x: i32);
    |     ^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error; 1 warning emitted
 
-Future incompatibility report: Future breakage diagnostic:
-warning: use of calling convention not supported on this target
-  --> $DIR/unsupported-abi.rs:5:1
-   |
-LL | / extern "stdcall" {
-LL | |
-LL | |
-LL | |     fn f(x: i32);
-LL | |
-LL | | }
-   | |_^
-   |
-   = 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
-
diff --git a/tests/ui/lint/expansion-time.rs b/tests/ui/lint/expansion-time.rs
index 5ffb0c7881e..2c59bf00065 100644
--- a/tests/ui/lint/expansion-time.rs
+++ b/tests/ui/lint/expansion-time.rs
@@ -5,10 +5,6 @@ macro_rules! foo {
     ( $($i:ident)* ) => { $($i)+ }; //~ WARN meta-variable repeats with different Kleene operator
 }
 
-#[warn(missing_fragment_specifier)]
-macro_rules! m { ($i) => {} } //~ WARN missing fragment specifier
-                              //~| WARN this was previously accepted
-
 #[deprecated = "reason"]
 macro_rules! deprecated {
     () => {}
diff --git a/tests/ui/lint/expansion-time.stderr b/tests/ui/lint/expansion-time.stderr
index f24d1b68a8d..b1154d1a54c 100644
--- a/tests/ui/lint/expansion-time.stderr
+++ b/tests/ui/lint/expansion-time.stderr
@@ -12,20 +12,6 @@ note: the lint level is defined here
 LL | #[warn(meta_variable_misuse)]
    |        ^^^^^^^^^^^^^^^^^^^^
 
-warning: missing fragment specifier
-  --> $DIR/expansion-time.rs:9:19
-   |
-LL | macro_rules! m { ($i) => {} }
-   |                   ^^
-   |
-   = 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 #40107 <https://github.com/rust-lang/rust/issues/40107>
-note: the lint level is defined here
-  --> $DIR/expansion-time.rs:8:8
-   |
-LL | #[warn(missing_fragment_specifier)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 warning: include macro expected single expression in source
   --> $DIR/expansion-time-include.rs:4:1
    |
@@ -33,25 +19,10 @@ LL | 2
    | ^
    |
 note: the lint level is defined here
-  --> $DIR/expansion-time.rs:22:8
+  --> $DIR/expansion-time.rs:18:8
    |
 LL | #[warn(incomplete_include)]
    |        ^^^^^^^^^^^^^^^^^^
 
-warning: 3 warnings emitted
-
-Future incompatibility report: Future breakage diagnostic:
-warning: missing fragment specifier
-  --> $DIR/expansion-time.rs:9:19
-   |
-LL | macro_rules! m { ($i) => {} }
-   |                   ^^
-   |
-   = 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 #40107 <https://github.com/rust-lang/rust/issues/40107>
-note: the lint level is defined here
-  --> $DIR/expansion-time.rs:8:8
-   |
-LL | #[warn(missing_fragment_specifier)]
-   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^
+warning: 2 warnings emitted
 
diff --git a/tests/ui/lint/fn-ptr-comparisons-some.rs b/tests/ui/lint/fn-ptr-comparisons-some.rs
index 152e16b9884..c6ddd759baa 100644
--- a/tests/ui/lint/fn-ptr-comparisons-some.rs
+++ b/tests/ui/lint/fn-ptr-comparisons-some.rs
@@ -12,6 +12,6 @@ fn main() {
     let _ = Some::<FnPtr>(func) == Some(func as unsafe extern "C" fn());
     //~^ WARN function pointer comparisons
 
-    // Undecided as of https://github.com/rust-lang/rust/pull/134536
     assert_eq!(Some::<FnPtr>(func), Some(func as unsafe extern "C" fn()));
+    //~^ WARN function pointer comparisons
 }
diff --git a/tests/ui/lint/fn-ptr-comparisons-some.stderr b/tests/ui/lint/fn-ptr-comparisons-some.stderr
index eefad05b676..522c4399bce 100644
--- a/tests/ui/lint/fn-ptr-comparisons-some.stderr
+++ b/tests/ui/lint/fn-ptr-comparisons-some.stderr
@@ -9,5 +9,16 @@ LL |     let _ = Some::<FnPtr>(func) == Some(func as unsafe extern "C" fn());
    = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
    = note: `#[warn(unpredictable_function_pointer_comparisons)]` on by default
 
-warning: 1 warning emitted
+warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
+  --> $DIR/fn-ptr-comparisons-some.rs:15:5
+   |
+LL |     assert_eq!(Some::<FnPtr>(func), Some(func as unsafe extern "C" fn()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the address of the same function can vary between different codegen units
+   = note: furthermore, different functions could have the same address after being merged together
+   = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
+   = note: this warning originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: 2 warnings emitted
 
diff --git a/tests/ui/lint/fn-ptr-comparisons-weird.rs b/tests/ui/lint/fn-ptr-comparisons-weird.rs
index 171fbfb8727..4d756cb49df 100644
--- a/tests/ui/lint/fn-ptr-comparisons-weird.rs
+++ b/tests/ui/lint/fn-ptr-comparisons-weird.rs
@@ -1,5 +1,23 @@
 //@ check-pass
 
+#[derive(PartialEq, Eq)]
+struct A {
+    f: fn(),
+    //~^ WARN function pointer comparisons
+}
+
+#[allow(unpredictable_function_pointer_comparisons)]
+#[derive(PartialEq, Eq)]
+struct AllowedAbove {
+    f: fn(),
+}
+
+#[derive(PartialEq, Eq)]
+#[allow(unpredictable_function_pointer_comparisons)]
+struct AllowedBelow {
+    f: fn(),
+}
+
 fn main() {
     let f: fn() = main;
     let g: fn() = main;
@@ -12,4 +30,8 @@ fn main() {
     //~^ WARN function pointer comparisons
     let _ = f < g;
     //~^ WARN function pointer comparisons
+    let _ = assert_eq!(g, g);
+    //~^ WARN function pointer comparisons
+    let _ = assert_ne!(g, g);
+    //~^ WARN function pointer comparisons
 }
diff --git a/tests/ui/lint/fn-ptr-comparisons-weird.stderr b/tests/ui/lint/fn-ptr-comparisons-weird.stderr
index f2371663922..2014e519c25 100644
--- a/tests/ui/lint/fn-ptr-comparisons-weird.stderr
+++ b/tests/ui/lint/fn-ptr-comparisons-weird.stderr
@@ -1,5 +1,19 @@
 warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
-  --> $DIR/fn-ptr-comparisons-weird.rs:7:13
+  --> $DIR/fn-ptr-comparisons-weird.rs:5:5
+   |
+LL | #[derive(PartialEq, Eq)]
+   |          --------- in this derive macro expansion
+LL | struct A {
+LL |     f: fn(),
+   |     ^^^^^^^
+   |
+   = note: the address of the same function can vary between different codegen units
+   = note: furthermore, different functions could have the same address after being merged together
+   = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
+   = note: `#[warn(unpredictable_function_pointer_comparisons)]` on by default
+
+warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
+  --> $DIR/fn-ptr-comparisons-weird.rs:25:13
    |
 LL |     let _ = f > g;
    |             ^^^^^
@@ -7,10 +21,9 @@ LL |     let _ = f > g;
    = note: the address of the same function can vary between different codegen units
    = note: furthermore, different functions could have the same address after being merged together
    = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
-   = note: `#[warn(unpredictable_function_pointer_comparisons)]` on by default
 
 warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
-  --> $DIR/fn-ptr-comparisons-weird.rs:9:13
+  --> $DIR/fn-ptr-comparisons-weird.rs:27:13
    |
 LL |     let _ = f >= g;
    |             ^^^^^^
@@ -20,7 +33,7 @@ LL |     let _ = f >= g;
    = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
 
 warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
-  --> $DIR/fn-ptr-comparisons-weird.rs:11:13
+  --> $DIR/fn-ptr-comparisons-weird.rs:29:13
    |
 LL |     let _ = f <= g;
    |             ^^^^^^
@@ -30,7 +43,7 @@ LL |     let _ = f <= g;
    = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
 
 warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
-  --> $DIR/fn-ptr-comparisons-weird.rs:13:13
+  --> $DIR/fn-ptr-comparisons-weird.rs:31:13
    |
 LL |     let _ = f < g;
    |             ^^^^^
@@ -39,5 +52,27 @@ LL |     let _ = f < g;
    = note: furthermore, different functions could have the same address after being merged together
    = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
 
-warning: 4 warnings emitted
+warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
+  --> $DIR/fn-ptr-comparisons-weird.rs:33:13
+   |
+LL |     let _ = assert_eq!(g, g);
+   |             ^^^^^^^^^^^^^^^^
+   |
+   = note: the address of the same function can vary between different codegen units
+   = note: furthermore, different functions could have the same address after being merged together
+   = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
+   = note: this warning originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
+  --> $DIR/fn-ptr-comparisons-weird.rs:35:13
+   |
+LL |     let _ = assert_ne!(g, g);
+   |             ^^^^^^^^^^^^^^^^
+   |
+   = note: the address of the same function can vary between different codegen units
+   = note: furthermore, different functions could have the same address after being merged together
+   = note: for more information visit <https://doc.rust-lang.org/nightly/core/ptr/fn.fn_addr_eq.html>
+   = note: this warning originates in the macro `assert_ne` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+warning: 7 warnings emitted
 
diff --git a/tests/ui/lint/fn-ptr-comparisons.fixed b/tests/ui/lint/fn-ptr-comparisons.fixed
index 22f16177a04..41cdb7bf6ae 100644
--- a/tests/ui/lint/fn-ptr-comparisons.fixed
+++ b/tests/ui/lint/fn-ptr-comparisons.fixed
@@ -11,7 +11,6 @@ extern "C" fn c() {}
 
 extern "C" fn args(_a: i32) -> i32 { 0 }
 
-#[derive(PartialEq, Eq)]
 struct A {
     f: fn(),
 }
@@ -52,7 +51,6 @@ fn main() {
     let _ = std::ptr::fn_addr_eq(t, test as unsafe extern "C" fn());
     //~^ WARN function pointer comparisons
 
-    let _ = a1 == a2; // should not warn
     let _ = std::ptr::fn_addr_eq(a1.f, a2.f);
     //~^ WARN function pointer comparisons
 }
diff --git a/tests/ui/lint/fn-ptr-comparisons.rs b/tests/ui/lint/fn-ptr-comparisons.rs
index 90a8ab5c926..c2601d6adfb 100644
--- a/tests/ui/lint/fn-ptr-comparisons.rs
+++ b/tests/ui/lint/fn-ptr-comparisons.rs
@@ -11,7 +11,6 @@ extern "C" fn c() {}
 
 extern "C" fn args(_a: i32) -> i32 { 0 }
 
-#[derive(PartialEq, Eq)]
 struct A {
     f: fn(),
 }
@@ -52,7 +51,6 @@ fn main() {
     let _ = t == test;
     //~^ WARN function pointer comparisons
 
-    let _ = a1 == a2; // should not warn
     let _ = a1.f == a2.f;
     //~^ WARN function pointer comparisons
 }
diff --git a/tests/ui/lint/fn-ptr-comparisons.stderr b/tests/ui/lint/fn-ptr-comparisons.stderr
index e6993323898..5913acca16b 100644
--- a/tests/ui/lint/fn-ptr-comparisons.stderr
+++ b/tests/ui/lint/fn-ptr-comparisons.stderr
@@ -1,5 +1,5 @@
 warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
-  --> $DIR/fn-ptr-comparisons.rs:26:13
+  --> $DIR/fn-ptr-comparisons.rs:25:13
    |
 LL |     let _ = f == a;
    |             ^^^^^^
@@ -15,7 +15,7 @@ LL +     let _ = std::ptr::fn_addr_eq(f, a as fn());
    |
 
 warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
-  --> $DIR/fn-ptr-comparisons.rs:28:13
+  --> $DIR/fn-ptr-comparisons.rs:27:13
    |
 LL |     let _ = f != a;
    |             ^^^^^^
@@ -30,7 +30,7 @@ LL +     let _ = !std::ptr::fn_addr_eq(f, a as fn());
    |
 
 warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
-  --> $DIR/fn-ptr-comparisons.rs:30:13
+  --> $DIR/fn-ptr-comparisons.rs:29:13
    |
 LL |     let _ = f == g;
    |             ^^^^^^
@@ -45,7 +45,7 @@ LL +     let _ = std::ptr::fn_addr_eq(f, g);
    |
 
 warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
-  --> $DIR/fn-ptr-comparisons.rs:32:13
+  --> $DIR/fn-ptr-comparisons.rs:31:13
    |
 LL |     let _ = f == f;
    |             ^^^^^^
@@ -60,7 +60,7 @@ LL +     let _ = std::ptr::fn_addr_eq(f, f);
    |
 
 warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
-  --> $DIR/fn-ptr-comparisons.rs:34:13
+  --> $DIR/fn-ptr-comparisons.rs:33:13
    |
 LL |     let _ = g == g;
    |             ^^^^^^
@@ -75,7 +75,7 @@ LL +     let _ = std::ptr::fn_addr_eq(g, g);
    |
 
 warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
-  --> $DIR/fn-ptr-comparisons.rs:36:13
+  --> $DIR/fn-ptr-comparisons.rs:35:13
    |
 LL |     let _ = g == g;
    |             ^^^^^^
@@ -90,7 +90,7 @@ LL +     let _ = std::ptr::fn_addr_eq(g, g);
    |
 
 warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
-  --> $DIR/fn-ptr-comparisons.rs:38:13
+  --> $DIR/fn-ptr-comparisons.rs:37:13
    |
 LL |     let _ = &g == &g;
    |             ^^^^^^^^
@@ -105,7 +105,7 @@ LL +     let _ = std::ptr::fn_addr_eq(g, g);
    |
 
 warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
-  --> $DIR/fn-ptr-comparisons.rs:40:13
+  --> $DIR/fn-ptr-comparisons.rs:39:13
    |
 LL |     let _ = a as fn() == g;
    |             ^^^^^^^^^^^^^^
@@ -120,7 +120,7 @@ LL +     let _ = std::ptr::fn_addr_eq(a as fn(), g);
    |
 
 warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
-  --> $DIR/fn-ptr-comparisons.rs:44:13
+  --> $DIR/fn-ptr-comparisons.rs:43:13
    |
 LL |     let _ = cfn == c;
    |             ^^^^^^^^
@@ -135,7 +135,7 @@ LL +     let _ = std::ptr::fn_addr_eq(cfn, c as extern "C" fn());
    |
 
 warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
-  --> $DIR/fn-ptr-comparisons.rs:48:13
+  --> $DIR/fn-ptr-comparisons.rs:47:13
    |
 LL |     let _ = argsfn == args;
    |             ^^^^^^^^^^^^^^
@@ -150,7 +150,7 @@ LL +     let _ = std::ptr::fn_addr_eq(argsfn, args as extern "C" fn(i32) -> i32)
    |
 
 warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
-  --> $DIR/fn-ptr-comparisons.rs:52:13
+  --> $DIR/fn-ptr-comparisons.rs:51:13
    |
 LL |     let _ = t == test;
    |             ^^^^^^^^^
@@ -165,7 +165,7 @@ LL +     let _ = std::ptr::fn_addr_eq(t, test as unsafe extern "C" fn());
    |
 
 warning: function pointer comparisons do not produce meaningful results since their addresses are not guaranteed to be unique
-  --> $DIR/fn-ptr-comparisons.rs:56:13
+  --> $DIR/fn-ptr-comparisons.rs:54:13
    |
 LL |     let _ = a1.f == a2.f;
    |             ^^^^^^^^^^^^
diff --git a/tests/ui/lint/future-incompatible-lint-group.rs b/tests/ui/lint/future-incompatible-lint-group.rs
new file mode 100644
index 00000000000..22a7ccb463b
--- /dev/null
+++ b/tests/ui/lint/future-incompatible-lint-group.rs
@@ -0,0 +1,30 @@
+//! Test that future_incompatible lint group only includes edition-independent lints
+
+// Ensure that the future_incompatible lint group only includes
+// lints for changes that are not tied to an edition
+#![deny(future_incompatible)]
+
+enum E { V }
+
+trait Tr1 {
+    type V;
+    fn foo() -> Self::V;
+}
+
+impl Tr1 for E {
+    type V = u8;
+
+    // Error since this is a `future_incompatible` lint
+    fn foo() -> Self::V { 0 }
+    //~^ ERROR ambiguous associated item
+    //~| WARN this was previously accepted
+}
+
+trait Tr2 {
+    // Warn only since this is not a `future_incompatible` lint
+    fn f(u8) {}
+    //~^ WARN anonymous parameters are deprecated
+    //~| WARN this is accepted in the current edition
+}
+
+fn main() {}
diff --git a/tests/ui/lint/future-incompatible-lint-group.stderr b/tests/ui/lint/future-incompatible-lint-group.stderr
new file mode 100644
index 00000000000..87b9ebec08b
--- /dev/null
+++ b/tests/ui/lint/future-incompatible-lint-group.stderr
@@ -0,0 +1,37 @@
+warning: anonymous parameters are deprecated and will be removed in the next edition
+  --> $DIR/future-incompatible-lint-group.rs:25:10
+   |
+LL |     fn f(u8) {}
+   |          ^^ help: try naming the parameter or explicitly ignoring it: `_: u8`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
+   = note: `#[warn(anonymous_parameters)]` on by default
+
+error: ambiguous associated item
+  --> $DIR/future-incompatible-lint-group.rs:18:17
+   |
+LL |     fn foo() -> Self::V { 0 }
+   |                 ^^^^^^^ help: use fully-qualified syntax: `<E as Tr1>::V`
+   |
+   = 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 #57644 <https://github.com/rust-lang/rust/issues/57644>
+note: `V` could refer to the variant defined here
+  --> $DIR/future-incompatible-lint-group.rs:7:10
+   |
+LL | enum E { V }
+   |          ^
+note: `V` could also refer to the associated type defined here
+  --> $DIR/future-incompatible-lint-group.rs:10:5
+   |
+LL |     type V;
+   |     ^^^^^^
+note: the lint level is defined here
+  --> $DIR/future-incompatible-lint-group.rs:5:9
+   |
+LL | #![deny(future_incompatible)]
+   |         ^^^^^^^^^^^^^^^^^^^
+   = note: `#[deny(ambiguous_associated_items)]` implied by `#[deny(future_incompatible)]`
+
+error: aborting due to 1 previous error; 1 warning emitted
+
diff --git a/tests/ui/loops/issue-43162.stderr b/tests/ui/loops/issue-43162.stderr
index 40d9200058e..f6b6bf2621c 100644
--- a/tests/ui/loops/issue-43162.stderr
+++ b/tests/ui/loops/issue-43162.stderr
@@ -4,12 +4,6 @@ error[E0268]: `break` outside of a loop or labeled block
 LL |     break true;
    |     ^^^^^^^^^^ cannot `break` outside of a loop or labeled block
 
-error[E0268]: `break` outside of a loop or labeled block
-  --> $DIR/issue-43162.rs:7:5
-   |
-LL |     break {};
-   |     ^^^^^^^^ cannot `break` outside of a loop or labeled block
-
 error[E0308]: mismatched types
   --> $DIR/issue-43162.rs:1:13
    |
@@ -18,6 +12,12 @@ LL | fn foo() -> bool {
    |    |
    |    implicitly returns `()` as its body has no tail or `return` expression
 
+error[E0268]: `break` outside of a loop or labeled block
+  --> $DIR/issue-43162.rs:7:5
+   |
+LL |     break {};
+   |     ^^^^^^^^ cannot `break` outside of a loop or labeled block
+
 error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0268, E0308.
diff --git a/tests/ui/macros/auxiliary/serde.rs b/tests/ui/macros/auxiliary/serde.rs
new file mode 100644
index 00000000000..355b650bcf3
--- /dev/null
+++ b/tests/ui/macros/auxiliary/serde.rs
@@ -0,0 +1,19 @@
+//@ force-host
+//@ no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro_quote)]
+
+extern crate proc_macro;
+
+use proc_macro::*;
+
+#[proc_macro_derive(Serialize, attributes(serde))]
+pub fn serialize(ts: TokenStream) -> TokenStream {
+    quote!{}
+}
+
+#[proc_macro_derive(Deserialize, attributes(serde))]
+pub fn deserialize(ts: TokenStream) -> TokenStream {
+    quote!{}
+}
diff --git a/tests/ui/macros/issue-39404.rs b/tests/ui/macros/issue-39404.rs
index 2229f2c3900..ceeb6231bc8 100644
--- a/tests/ui/macros/issue-39404.rs
+++ b/tests/ui/macros/issue-39404.rs
@@ -1,7 +1,7 @@
 #![allow(unused)]
 
-macro_rules! m { ($i) => {} }
-//~^ ERROR missing fragment specifier
-//~| WARN previously accepted
+macro_rules! m {
+    ($i) => {}; //~ ERROR missing fragment specifier
+}
 
 fn main() {}
diff --git a/tests/ui/macros/issue-39404.stderr b/tests/ui/macros/issue-39404.stderr
index 176c8e9f073..62d0bc1018c 100644
--- a/tests/ui/macros/issue-39404.stderr
+++ b/tests/ui/macros/issue-39404.stderr
@@ -1,23 +1,15 @@
 error: missing fragment specifier
-  --> $DIR/issue-39404.rs:3:19
+  --> $DIR/issue-39404.rs:4:6
    |
-LL | macro_rules! m { ($i) => {} }
-   |                   ^^
+LL |     ($i) => {};
+   |      ^^
    |
-   = 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 #40107 <https://github.com/rust-lang/rust/issues/40107>
-   = note: `#[deny(missing_fragment_specifier)]` on by default
+   = note: fragment specifiers must be provided
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
+help: try adding a specifier here
+   |
+LL |     ($i:spec) => {};
+   |        +++++
 
 error: aborting due to 1 previous error
 
-Future incompatibility report: Future breakage diagnostic:
-error: missing fragment specifier
-  --> $DIR/issue-39404.rs:3:19
-   |
-LL | macro_rules! m { ($i) => {} }
-   |                   ^^
-   |
-   = 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 #40107 <https://github.com/rust-lang/rust/issues/40107>
-   = note: `#[deny(missing_fragment_specifier)]` on by default
-
diff --git a/tests/ui/macros/macro-match-nonterminal.rs b/tests/ui/macros/macro-match-nonterminal.rs
index 5d9eb55fee0..fa2af945a1f 100644
--- a/tests/ui/macros/macro-match-nonterminal.rs
+++ b/tests/ui/macros/macro-match-nonterminal.rs
@@ -3,8 +3,6 @@ macro_rules! test {
         //~^ ERROR missing fragment
         //~| ERROR missing fragment
         //~| ERROR missing fragment
-        //~| WARN this was previously accepted
-        //~| WARN this was previously accepted
         ()
     };
 }
diff --git a/tests/ui/macros/macro-match-nonterminal.stderr b/tests/ui/macros/macro-match-nonterminal.stderr
index f221f92c3cd..8196d795c4c 100644
--- a/tests/ui/macros/macro-match-nonterminal.stderr
+++ b/tests/ui/macros/macro-match-nonterminal.stderr
@@ -3,16 +3,13 @@ error: missing fragment specifier
    |
 LL |     ($a, $b) => {
    |      ^^
-
-error: missing fragment specifier
-  --> $DIR/macro-match-nonterminal.rs:2:6
    |
-LL |     ($a, $b) => {
-   |      ^^
+   = note: fragment specifiers must be provided
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
+help: try adding a specifier here
    |
-   = 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 #40107 <https://github.com/rust-lang/rust/issues/40107>
-   = note: `#[deny(missing_fragment_specifier)]` on by default
+LL |     ($a:spec, $b) => {
+   |        +++++
 
 error: missing fragment specifier
   --> $DIR/macro-match-nonterminal.rs:2:10
@@ -20,30 +17,18 @@ error: missing fragment specifier
 LL |     ($a, $b) => {
    |          ^^
    |
-   = 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 #40107 <https://github.com/rust-lang/rust/issues/40107>
-
-error: aborting due to 3 previous errors
+   = note: fragment specifiers must be provided
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
+help: try adding a specifier here
+   |
+LL |     ($a, $b:spec) => {
+   |            +++++
 
-Future incompatibility report: Future breakage diagnostic:
 error: missing fragment specifier
   --> $DIR/macro-match-nonterminal.rs:2:6
    |
 LL |     ($a, $b) => {
    |      ^^
-   |
-   = 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 #40107 <https://github.com/rust-lang/rust/issues/40107>
-   = note: `#[deny(missing_fragment_specifier)]` on by default
 
-Future breakage diagnostic:
-error: missing fragment specifier
-  --> $DIR/macro-match-nonterminal.rs:2:10
-   |
-LL |     ($a, $b) => {
-   |          ^^
-   |
-   = 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 #40107 <https://github.com/rust-lang/rust/issues/40107>
-   = note: `#[deny(missing_fragment_specifier)]` on by default
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/macros/macro-missing-fragment-deduplication.rs b/tests/ui/macros/macro-missing-fragment-deduplication.rs
index b77c51e055b..481f08fa111 100644
--- a/tests/ui/macros/macro-missing-fragment-deduplication.rs
+++ b/tests/ui/macros/macro-missing-fragment-deduplication.rs
@@ -1,10 +1,8 @@
 //@ compile-flags: -Zdeduplicate-diagnostics=yes
 
 macro_rules! m {
-    ($name) => {}
-    //~^ ERROR missing fragment
-    //~| ERROR missing fragment
-    //~| WARN this was previously accepted
+    ($name) => {}; //~ ERROR missing fragment
+                   //~| ERROR missing fragment
 }
 
 fn main() {
diff --git a/tests/ui/macros/macro-missing-fragment-deduplication.stderr b/tests/ui/macros/macro-missing-fragment-deduplication.stderr
index c46712f70fd..820f7eb3cf7 100644
--- a/tests/ui/macros/macro-missing-fragment-deduplication.stderr
+++ b/tests/ui/macros/macro-missing-fragment-deduplication.stderr
@@ -1,29 +1,21 @@
 error: missing fragment specifier
   --> $DIR/macro-missing-fragment-deduplication.rs:4:6
    |
-LL |     ($name) => {}
+LL |     ($name) => {};
    |      ^^^^^
-
-error: missing fragment specifier
-  --> $DIR/macro-missing-fragment-deduplication.rs:4:6
    |
-LL |     ($name) => {}
-   |      ^^^^^
+   = note: fragment specifiers must be provided
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
+help: try adding a specifier here
    |
-   = 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 #40107 <https://github.com/rust-lang/rust/issues/40107>
-   = note: `#[deny(missing_fragment_specifier)]` on by default
+LL |     ($name:spec) => {};
+   |           +++++
 
-error: aborting due to 2 previous errors
-
-Future incompatibility report: Future breakage diagnostic:
 error: missing fragment specifier
   --> $DIR/macro-missing-fragment-deduplication.rs:4:6
    |
-LL |     ($name) => {}
+LL |     ($name) => {};
    |      ^^^^^
-   |
-   = 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 #40107 <https://github.com/rust-lang/rust/issues/40107>
-   = note: `#[deny(missing_fragment_specifier)]` on by default
+
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/macros/macro-missing-fragment.e2015.stderr b/tests/ui/macros/macro-missing-fragment.e2015.stderr
deleted file mode 100644
index 3d32f203d4a..00000000000
--- a/tests/ui/macros/macro-missing-fragment.e2015.stderr
+++ /dev/null
@@ -1,85 +0,0 @@
-error: missing fragment specifier
-  --> $DIR/macro-missing-fragment.rs:8:20
-   |
-LL |     ( $( any_token $field_rust_type )* ) => {};
-   |                    ^^^^^^^^^^^^^^^^
-
-warning: missing fragment specifier
-  --> $DIR/macro-missing-fragment.rs:8:20
-   |
-LL |     ( $( any_token $field_rust_type )* ) => {};
-   |                    ^^^^^^^^^^^^^^^^
-   |
-   = 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 #40107 <https://github.com/rust-lang/rust/issues/40107>
-note: the lint level is defined here
-  --> $DIR/macro-missing-fragment.rs:5:9
-   |
-LL | #![warn(missing_fragment_specifier)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-warning: missing fragment specifier
-  --> $DIR/macro-missing-fragment.rs:18:7
-   |
-LL |     ( $name ) => {};
-   |       ^^^^^
-   |
-   = 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 #40107 <https://github.com/rust-lang/rust/issues/40107>
-
-warning: missing fragment specifier
-  --> $DIR/macro-missing-fragment.rs:25:7
-   |
-LL |     ( $name ) => {};
-   |       ^^^^^
-   |
-   = 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 #40107 <https://github.com/rust-lang/rust/issues/40107>
-
-error: aborting due to 1 previous error; 3 warnings emitted
-
-Future incompatibility report: Future breakage diagnostic:
-warning: missing fragment specifier
-  --> $DIR/macro-missing-fragment.rs:8:20
-   |
-LL |     ( $( any_token $field_rust_type )* ) => {};
-   |                    ^^^^^^^^^^^^^^^^
-   |
-   = 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 #40107 <https://github.com/rust-lang/rust/issues/40107>
-note: the lint level is defined here
-  --> $DIR/macro-missing-fragment.rs:5:9
-   |
-LL | #![warn(missing_fragment_specifier)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-warning: missing fragment specifier
-  --> $DIR/macro-missing-fragment.rs:18:7
-   |
-LL |     ( $name ) => {};
-   |       ^^^^^
-   |
-   = 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 #40107 <https://github.com/rust-lang/rust/issues/40107>
-note: the lint level is defined here
-  --> $DIR/macro-missing-fragment.rs:5:9
-   |
-LL | #![warn(missing_fragment_specifier)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-warning: missing fragment specifier
-  --> $DIR/macro-missing-fragment.rs:25:7
-   |
-LL |     ( $name ) => {};
-   |       ^^^^^
-   |
-   = 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 #40107 <https://github.com/rust-lang/rust/issues/40107>
-note: the lint level is defined here
-  --> $DIR/macro-missing-fragment.rs:5:9
-   |
-LL | #![warn(missing_fragment_specifier)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
-
diff --git a/tests/ui/macros/macro-missing-fragment.rs b/tests/ui/macros/macro-missing-fragment.rs
index 42387e8dbbf..533aa147bcb 100644
--- a/tests/ui/macros/macro-missing-fragment.rs
+++ b/tests/ui/macros/macro-missing-fragment.rs
@@ -1,31 +1,17 @@
-//@ revisions: e2015 e2024
-//@[e2015] edition:2015
-//@[e2024] edition:2024
-
-#![warn(missing_fragment_specifier)]
+//! Ensure that macros produce an error if fragment specifiers are missing.
 
 macro_rules! used_arm {
-    ( $( any_token $field_rust_type )* ) => {};
-    //[e2015]~^ ERROR missing fragment
-    //[e2015]~| WARN missing fragment
-    //[e2015]~| WARN this was previously accepted
-    //[e2024]~^^^^ ERROR missing fragment
-    //[e2024]~| ERROR missing fragment
+    ( $( any_token $field_rust_type )* ) => {}; //~ ERROR missing fragment
+                                                //~| ERROR missing fragment
 }
 
 macro_rules! used_macro_unused_arm {
     () => {};
-    ( $name ) => {};
-    //[e2015]~^ WARN missing fragment
-    //[e2015]~| WARN this was previously accepted
-    //[e2024]~^^^ ERROR missing fragment
+    ( $name ) => {}; //~ ERROR missing fragment
 }
 
 macro_rules! unused_macro {
-    ( $name ) => {};
-    //[e2015]~^ WARN missing fragment
-    //[e2015]~| WARN this was previously accepted
-    //[e2024]~^^^ ERROR missing fragment
+    ( $name ) => {}; //~ ERROR missing fragment
 }
 
 fn main() {
diff --git a/tests/ui/macros/macro-missing-fragment.e2024.stderr b/tests/ui/macros/macro-missing-fragment.stderr
index a9195063a5b..4a99d7d949c 100644
--- a/tests/ui/macros/macro-missing-fragment.e2024.stderr
+++ b/tests/ui/macros/macro-missing-fragment.stderr
@@ -1,10 +1,10 @@
 error: missing fragment specifier
-  --> $DIR/macro-missing-fragment.rs:8:20
+  --> $DIR/macro-missing-fragment.rs:4:20
    |
 LL |     ( $( any_token $field_rust_type )* ) => {};
    |                    ^^^^^^^^^^^^^^^^
    |
-   = note: fragment specifiers must be specified in the 2024 edition
+   = note: fragment specifiers must be provided
    = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
 help: try adding a specifier here
    |
@@ -12,12 +12,12 @@ LL |     ( $( any_token $field_rust_type:spec )* ) => {};
    |                                    +++++
 
 error: missing fragment specifier
-  --> $DIR/macro-missing-fragment.rs:18:7
+  --> $DIR/macro-missing-fragment.rs:10:7
    |
 LL |     ( $name ) => {};
    |       ^^^^^
    |
-   = note: fragment specifiers must be specified in the 2024 edition
+   = note: fragment specifiers must be provided
    = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
 help: try adding a specifier here
    |
@@ -25,12 +25,12 @@ LL |     ( $name:spec ) => {};
    |            +++++
 
 error: missing fragment specifier
-  --> $DIR/macro-missing-fragment.rs:25:7
+  --> $DIR/macro-missing-fragment.rs:14:7
    |
 LL |     ( $name ) => {};
    |       ^^^^^
    |
-   = note: fragment specifiers must be specified in the 2024 edition
+   = note: fragment specifiers must be provided
    = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
 help: try adding a specifier here
    |
@@ -38,7 +38,7 @@ LL |     ( $name:spec ) => {};
    |            +++++
 
 error: missing fragment specifier
-  --> $DIR/macro-missing-fragment.rs:8:20
+  --> $DIR/macro-missing-fragment.rs:4:20
    |
 LL |     ( $( any_token $field_rust_type )* ) => {};
    |                    ^^^^^^^^^^^^^^^^
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/macros/missing-derive-1.rs b/tests/ui/macros/missing-derive-1.rs
new file mode 100644
index 00000000000..e23ef7bf07b
--- /dev/null
+++ b/tests/ui/macros/missing-derive-1.rs
@@ -0,0 +1,33 @@
+//@aux-build:serde.rs
+
+// derive macros imported and used
+
+extern crate serde;
+use serde::{Serialize, Deserialize};
+
+#[serde(untagged)] //~ ERROR cannot find attribute `serde`
+enum A { //~ HELP `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`
+    A,
+    B,
+}
+
+enum B { //~ HELP `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`
+    A,
+    #[serde(untagged)] //~ ERROR cannot find attribute `serde`
+    B,
+}
+
+enum C {
+    A,
+    #[sede(untagged)] //~ ERROR cannot find attribute `sede`
+    B, //~^ HELP the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute
+}
+
+#[derive(Serialize, Deserialize)]
+#[serde(untagged)]
+enum D {
+    A,
+    B,
+}
+
+fn main() {}
diff --git a/tests/ui/macros/missing-derive-1.stderr b/tests/ui/macros/missing-derive-1.stderr
new file mode 100644
index 00000000000..15584100ffa
--- /dev/null
+++ b/tests/ui/macros/missing-derive-1.stderr
@@ -0,0 +1,47 @@
+error: cannot find attribute `serde` in this scope
+  --> $DIR/missing-derive-1.rs:8:3
+   |
+LL | #[serde(untagged)]
+   |   ^^^^^
+   |
+note: `serde` is imported here, but it is a crate, not an attribute
+  --> $DIR/missing-derive-1.rs:5:1
+   |
+LL | extern crate serde;
+   | ^^^^^^^^^^^^^^^^^^^
+help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute
+   |
+LL + #[derive(Deserialize, Serialize)]
+LL | enum A {
+   |
+
+error: cannot find attribute `serde` in this scope
+  --> $DIR/missing-derive-1.rs:16:7
+   |
+LL |     #[serde(untagged)]
+   |       ^^^^^
+   |
+note: `serde` is imported here, but it is a crate, not an attribute
+  --> $DIR/missing-derive-1.rs:5:1
+   |
+LL | extern crate serde;
+   | ^^^^^^^^^^^^^^^^^^^
+help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute
+   |
+LL + #[derive(Deserialize, Serialize)]
+LL | enum B {
+   |
+
+error: cannot find attribute `sede` in this scope
+  --> $DIR/missing-derive-1.rs:22:7
+   |
+LL |     #[sede(untagged)]
+   |       ^^^^
+   |
+help: the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute
+   |
+LL |     #[serde(untagged)]
+   |         +
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/macros/missing-derive-2.rs b/tests/ui/macros/missing-derive-2.rs
new file mode 100644
index 00000000000..027d465d8b3
--- /dev/null
+++ b/tests/ui/macros/missing-derive-2.rs
@@ -0,0 +1,26 @@
+//@aux-build:serde.rs
+
+// derive macros imported but unused
+
+extern crate serde;
+use serde::{Serialize, Deserialize};
+
+#[serde(untagged)] //~ ERROR cannot find attribute `serde`
+enum A { //~ HELP `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`
+    A,
+    B,
+}
+
+enum B { //~ HELP `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`
+    A,
+    #[serde(untagged)] //~ ERROR cannot find attribute `serde`
+    B,
+}
+
+enum C {
+    A,
+    #[sede(untagged)] //~ ERROR cannot find attribute `sede`
+    B, //~^ HELP the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute
+}
+
+fn main() {}
diff --git a/tests/ui/macros/missing-derive-2.stderr b/tests/ui/macros/missing-derive-2.stderr
new file mode 100644
index 00000000000..6c8e9e12019
--- /dev/null
+++ b/tests/ui/macros/missing-derive-2.stderr
@@ -0,0 +1,47 @@
+error: cannot find attribute `sede` in this scope
+  --> $DIR/missing-derive-2.rs:22:7
+   |
+LL |     #[sede(untagged)]
+   |       ^^^^
+   |
+help: the derive macros `Deserialize` and `Serialize` accept the similarly named `serde` attribute
+   |
+LL |     #[serde(untagged)]
+   |         +
+
+error: cannot find attribute `serde` in this scope
+  --> $DIR/missing-derive-2.rs:16:7
+   |
+LL |     #[serde(untagged)]
+   |       ^^^^^
+   |
+note: `serde` is imported here, but it is a crate, not an attribute
+  --> $DIR/missing-derive-2.rs:5:1
+   |
+LL | extern crate serde;
+   | ^^^^^^^^^^^^^^^^^^^
+help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute
+   |
+LL + #[derive(Deserialize, Serialize)]
+LL | enum B {
+   |
+
+error: cannot find attribute `serde` in this scope
+  --> $DIR/missing-derive-2.rs:8:3
+   |
+LL | #[serde(untagged)]
+   |   ^^^^^
+   |
+note: `serde` is imported here, but it is a crate, not an attribute
+  --> $DIR/missing-derive-2.rs:5:1
+   |
+LL | extern crate serde;
+   | ^^^^^^^^^^^^^^^^^^^
+help: `serde` is an attribute that can be used by the derive macros `Deserialize` and `Serialize`, you might be missing a `derive` attribute
+   |
+LL + #[derive(Deserialize, Serialize)]
+LL | enum A {
+   |
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/macros/missing-derive-3.rs b/tests/ui/macros/missing-derive-3.rs
new file mode 100644
index 00000000000..8add8198890
--- /dev/null
+++ b/tests/ui/macros/missing-derive-3.rs
@@ -0,0 +1,24 @@
+//@aux-build:serde.rs
+
+// derive macros not imported, but namespace imported. Not yet handled.
+extern crate serde;
+
+#[serde(untagged)] //~ ERROR cannot find attribute `serde`
+enum A {
+    A,
+    B,
+}
+
+enum B {
+    A,
+    #[serde(untagged)] //~ ERROR cannot find attribute `serde`
+    B,
+}
+
+enum C {
+    A,
+    #[sede(untagged)] //~ ERROR cannot find attribute `sede`
+    B,
+}
+
+fn main() {}
diff --git a/tests/ui/macros/missing-derive-3.stderr b/tests/ui/macros/missing-derive-3.stderr
new file mode 100644
index 00000000000..0a7ed8d0876
--- /dev/null
+++ b/tests/ui/macros/missing-derive-3.stderr
@@ -0,0 +1,32 @@
+error: cannot find attribute `sede` in this scope
+  --> $DIR/missing-derive-3.rs:20:7
+   |
+LL |     #[sede(untagged)]
+   |       ^^^^
+
+error: cannot find attribute `serde` in this scope
+  --> $DIR/missing-derive-3.rs:14:7
+   |
+LL |     #[serde(untagged)]
+   |       ^^^^^
+   |
+note: `serde` is imported here, but it is a crate, not an attribute
+  --> $DIR/missing-derive-3.rs:4:1
+   |
+LL | extern crate serde;
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: cannot find attribute `serde` in this scope
+  --> $DIR/missing-derive-3.rs:6:3
+   |
+LL | #[serde(untagged)]
+   |   ^^^^^
+   |
+note: `serde` is imported here, but it is a crate, not an attribute
+  --> $DIR/missing-derive-3.rs:4:1
+   |
+LL | extern crate serde;
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/ext-expand-inner-exprs.rs b/tests/ui/macros/nested-macro-expansion.rs
index 94610d0a328..3b94b1051c9 100644
--- a/tests/ui/ext-expand-inner-exprs.rs
+++ b/tests/ui/macros/nested-macro-expansion.rs
@@ -1,3 +1,5 @@
+//! Test nested macro expansion with concat! macros
+
 //@ run-pass
 
 static FOO : &'static str = concat!(concat!("hel", "lo"), "world");
diff --git a/tests/ui/impl-inherent-non-conflict.rs b/tests/ui/methods/inherent-methods-same-name.rs
index 41ab865892a..d7d19bc3325 100644
--- a/tests/ui/impl-inherent-non-conflict.rs
+++ b/tests/ui/methods/inherent-methods-same-name.rs
@@ -1,17 +1,22 @@
+//! Test multiple inherent methods with same name on different type parameters
+
 //@ run-pass
 // Ensure that a user-defined type admits multiple inherent methods
 // with the same name, which can be called on values that have a
 // precise enough type to allow distinguishing between the methods.
 
-
 struct Foo<T>(T);
 
 impl Foo<usize> {
-    fn bar(&self) -> i32 { self.0 as i32 }
+    fn bar(&self) -> i32 {
+        self.0 as i32
+    }
 }
 
 impl Foo<isize> {
-    fn bar(&self) -> i32 { -(self.0 as i32) }
+    fn bar(&self) -> i32 {
+        -(self.0 as i32)
+    }
 }
 
 fn main() {
diff --git a/tests/ui/methods/missing-bound-on-tuple.rs b/tests/ui/methods/missing-bound-on-tuple.rs
new file mode 100644
index 00000000000..25deabf5926
--- /dev/null
+++ b/tests/ui/methods/missing-bound-on-tuple.rs
@@ -0,0 +1,39 @@
+trait WorksOnDefault {
+    fn do_something() {}
+}
+
+impl<T: Default> WorksOnDefault for T {}
+//~^ NOTE the following trait bounds were not satisfied
+//~| NOTE unsatisfied trait bound introduced here
+
+trait Foo {}
+
+trait WorksOnFoo {
+    fn do_be_do() {}
+}
+
+impl<T: Foo> WorksOnFoo for T {}
+//~^ NOTE the following trait bounds were not satisfied
+//~| NOTE unsatisfied trait bound introduced here
+
+impl<A: Foo, B: Foo, C: Foo> Foo for (A, B, C) {}
+//~^ NOTE `Foo` is implemented for `(i32, u32, String)`
+impl Foo for i32 {}
+impl Foo for &i32 {}
+impl Foo for u32 {}
+impl Foo for String {}
+
+fn main() {
+    let _success = <(i32, u32, String)>::do_something();
+    let _failure = <(i32, &u32, String)>::do_something(); //~ ERROR E0599
+    //~^ NOTE `Default` is implemented for `(i32, u32, String)`
+    //~| NOTE function or associated item cannot be called on
+    let _success = <(i32, u32, String)>::do_be_do();
+    let _failure = <(i32, &u32, String)>::do_be_do(); //~ ERROR E0599
+    //~^ NOTE function or associated item cannot be called on
+    let _success = <(i32, u32, String)>::default();
+    let _failure = <(i32, &u32, String)>::default(); //~ ERROR E0599
+    //~^ NOTE `Default` is implemented for `(i32, u32, String)`
+    //~| NOTE function or associated item cannot be called on
+    //~| NOTE the following trait bounds were not satisfied
+}
diff --git a/tests/ui/methods/missing-bound-on-tuple.stderr b/tests/ui/methods/missing-bound-on-tuple.stderr
new file mode 100644
index 00000000000..f3e0897e5e6
--- /dev/null
+++ b/tests/ui/methods/missing-bound-on-tuple.stderr
@@ -0,0 +1,58 @@
+error[E0599]: the function or associated item `do_something` exists for tuple `(i32, &u32, String)`, but its trait bounds were not satisfied
+  --> $DIR/missing-bound-on-tuple.rs:28:43
+   |
+LL |     let _failure = <(i32, &u32, String)>::do_something();
+   |                                           ^^^^^^^^^^^^ function or associated item cannot be called on `(i32, &u32, String)` due to unsatisfied trait bounds
+   |
+note: the following trait bounds were not satisfied:
+      `&(i32, &u32, String): Default`
+      `&mut (i32, &u32, String): Default`
+      `(i32, &u32, String): Default`
+  --> $DIR/missing-bound-on-tuple.rs:5:9
+   |
+LL | impl<T: Default> WorksOnDefault for T {}
+   |         ^^^^^^^  --------------     -
+   |         |
+   |         unsatisfied trait bound introduced here
+note: `Default` is implemented for `(i32, u32, String)` but not for `(i32, &u32, String)`
+  --> $SRC_DIR/core/src/tuple.rs:LL:COL
+   = note: this error originates in the macro `tuple_impls` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0599]: the function or associated item `do_be_do` exists for tuple `(i32, &u32, String)`, but its trait bounds were not satisfied
+  --> $DIR/missing-bound-on-tuple.rs:32:43
+   |
+LL |     let _failure = <(i32, &u32, String)>::do_be_do();
+   |                                           ^^^^^^^^ function or associated item cannot be called on `(i32, &u32, String)` due to unsatisfied trait bounds
+   |
+note: the following trait bounds were not satisfied:
+      `&(i32, &u32, String): Foo`
+      `&mut (i32, &u32, String): Foo`
+      `(i32, &u32, String): Foo`
+  --> $DIR/missing-bound-on-tuple.rs:15:9
+   |
+LL | impl<T: Foo> WorksOnFoo for T {}
+   |         ^^^  ----------     -
+   |         |
+   |         unsatisfied trait bound introduced here
+note: `Foo` is implemented for `(i32, u32, String)` but not for `(i32, &u32, String)`
+  --> $DIR/missing-bound-on-tuple.rs:19:1
+   |
+LL | impl<A: Foo, B: Foo, C: Foo> Foo for (A, B, C) {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0599]: the function or associated item `default` exists for tuple `(i32, &u32, String)`, but its trait bounds were not satisfied
+  --> $DIR/missing-bound-on-tuple.rs:35:43
+   |
+LL |     let _failure = <(i32, &u32, String)>::default();
+   |                                           ^^^^^^^ function or associated item cannot be called on `(i32, &u32, String)` due to unsatisfied trait bounds
+   |
+   = note: the following trait bounds were not satisfied:
+           `&u32: Default`
+           which is required by `(i32, &u32, String): Default`
+note: `Default` is implemented for `(i32, u32, String)` but not for `(i32, &u32, String)`
+  --> $SRC_DIR/core/src/tuple.rs:LL:COL
+   = note: this error originates in the macro `tuple_impls` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/mir/mir_refs_correct.rs b/tests/ui/mir/mir_refs_correct.rs
index fc23c8c3631..f1832d90a0f 100644
--- a/tests/ui/mir/mir_refs_correct.rs
+++ b/tests/ui/mir/mir_refs_correct.rs
@@ -1,6 +1,8 @@
 //@ run-pass
 //@ aux-build:mir_external_refs.rs
 
+#![allow(unpredictable_function_pointer_comparisons)]
+
 extern crate mir_external_refs as ext;
 
 struct S(#[allow(dead_code)] u8);
diff --git a/tests/ui/impl-not-adjacent-to-type.rs b/tests/ui/modules/impl-cross-module.rs
index ccf59ed4393..3ed8c18ff3c 100644
--- a/tests/ui/impl-not-adjacent-to-type.rs
+++ b/tests/ui/modules/impl-cross-module.rs
@@ -1,3 +1,5 @@
+//! Test implementing methods for types defined in other modules
+
 //@ run-pass
 
 mod foo {
diff --git a/tests/ui/nll/sugg-mut-for-binding-issue-137486.fixed b/tests/ui/nll/sugg-mut-for-binding-issue-137486.fixed
new file mode 100644
index 00000000000..ee9d9a373de
--- /dev/null
+++ b/tests/ui/nll/sugg-mut-for-binding-issue-137486.fixed
@@ -0,0 +1,23 @@
+//@ run-rustfix
+#![allow(unused_assignments)]
+
+use std::pin::Pin;
+fn main() {
+    let mut s = String::from("hello");
+    let mut ref_s = &mut s;
+
+    let mut binding = String::from("world");
+    ref_s = &mut binding; //~ ERROR temporary value dropped while borrowed [E0716]
+
+    print!("r1 = {}", ref_s);
+
+    let mut val: u8 = 5;
+    let mut s = Pin::new(&mut val);
+    let mut ref_s = &mut s;
+
+    let mut val2: u8 = 10;
+    let mut binding = Pin::new(&mut val2);
+    ref_s = &mut binding; //~ ERROR temporary value dropped while borrowed [E0716]
+
+    print!("r1 = {}", ref_s);
+}
diff --git a/tests/ui/nll/sugg-mut-for-binding-issue-137486.rs b/tests/ui/nll/sugg-mut-for-binding-issue-137486.rs
new file mode 100644
index 00000000000..8f7ea756107
--- /dev/null
+++ b/tests/ui/nll/sugg-mut-for-binding-issue-137486.rs
@@ -0,0 +1,21 @@
+//@ run-rustfix
+#![allow(unused_assignments)]
+
+use std::pin::Pin;
+fn main() {
+    let mut s = String::from("hello");
+    let mut ref_s = &mut s;
+
+    ref_s = &mut String::from("world"); //~ ERROR temporary value dropped while borrowed [E0716]
+
+    print!("r1 = {}", ref_s);
+
+    let mut val: u8 = 5;
+    let mut s = Pin::new(&mut val);
+    let mut ref_s = &mut s;
+
+    let mut val2: u8 = 10;
+    ref_s = &mut Pin::new(&mut val2); //~ ERROR temporary value dropped while borrowed [E0716]
+
+    print!("r1 = {}", ref_s);
+}
diff --git a/tests/ui/nll/sugg-mut-for-binding-issue-137486.stderr b/tests/ui/nll/sugg-mut-for-binding-issue-137486.stderr
new file mode 100644
index 00000000000..8432725f60a
--- /dev/null
+++ b/tests/ui/nll/sugg-mut-for-binding-issue-137486.stderr
@@ -0,0 +1,37 @@
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/sugg-mut-for-binding-issue-137486.rs:9:18
+   |
+LL |     ref_s = &mut String::from("world");
+   |                  ^^^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
+   |                  |
+   |                  creates a temporary value which is freed while still in use
+LL |
+LL |     print!("r1 = {}", ref_s);
+   |                       ----- borrow later used here
+   |
+help: consider using a `let` binding to create a longer lived value
+   |
+LL ~     let mut binding = String::from("world");
+LL ~     ref_s = &mut binding;
+   |
+
+error[E0716]: temporary value dropped while borrowed
+  --> $DIR/sugg-mut-for-binding-issue-137486.rs:18:18
+   |
+LL |     ref_s = &mut Pin::new(&mut val2);
+   |                  ^^^^^^^^^^^^^^^^^^^- temporary value is freed at the end of this statement
+   |                  |
+   |                  creates a temporary value which is freed while still in use
+LL |
+LL |     print!("r1 = {}", ref_s);
+   |                       ----- borrow later used here
+   |
+help: consider using a `let` binding to create a longer lived value
+   |
+LL ~     let mut binding = Pin::new(&mut val2);
+LL ~     ref_s = &mut binding;
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0716`.
diff --git a/tests/ui/nullable-pointer-iotareduction.rs b/tests/ui/nullable-pointer-iotareduction.rs
index fa837dab51b..1b73164c9fc 100644
--- a/tests/ui/nullable-pointer-iotareduction.rs
+++ b/tests/ui/nullable-pointer-iotareduction.rs
@@ -8,6 +8,8 @@
 // trying to get assert failure messages that at least identify which case
 // failed.
 
+#![allow(unpredictable_function_pointer_comparisons)]
+
 enum E<T> { Thing(isize, T), #[allow(dead_code)] Nothing((), ((), ()), [i8; 0]) }
 impl<T> E<T> {
     fn is_none(&self) -> bool {
diff --git a/tests/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/tests/ui/object-lifetime/object-lifetime-default-from-box-error.stderr
index 15b36925c47..05eb611081a 100644
--- a/tests/ui/object-lifetime/object-lifetime-default-from-box-error.stderr
+++ b/tests/ui/object-lifetime/object-lifetime-default-from-box-error.stderr
@@ -21,11 +21,13 @@ LL |     ss.r
 error[E0621]: explicit lifetime required in the type of `ss`
   --> $DIR/object-lifetime-default-from-box-error.rs:33:5
    |
-LL | fn store1<'b>(ss: &mut SomeStruct, b: Box<dyn SomeTrait+'b>) {
-   |                   --------------- help: add explicit lifetime `'b` to the type of `ss`: `&mut SomeStruct<'b>`
-...
 LL |     ss.r = b;
    |     ^^^^ lifetime `'b` required
+   |
+help: add explicit lifetime `'b` to the type of `ss`
+   |
+LL | fn store1<'b>(ss: &mut SomeStruct<'b>, b: Box<dyn SomeTrait+'b>) {
+   |                                  ++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/on-unimplemented/feature-gate-on-unimplemented.rs b/tests/ui/on-unimplemented/feature-gate-on-unimplemented.rs
index 3cc50e3499a..436caab5d64 100644
--- a/tests/ui/on-unimplemented/feature-gate-on-unimplemented.rs
+++ b/tests/ui/on-unimplemented/feature-gate-on-unimplemented.rs
@@ -1,8 +1,9 @@
 // Test that `#[rustc_on_unimplemented]` is gated by `rustc_attrs` feature gate.
 
 #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"]
-//~^ ERROR this is an internal attribute that will never be stable
-trait Foo<Bar>
-{}
+//~^ ERROR use of an internal attribute [E0658]
+//~| NOTE the `#[rustc_on_unimplemented]` attribute is an internal implementation detail that will never be stable
+//~| NOTE see `#[diagnostic::on_unimplemented]` for the stable equivalent of this attribute
+trait Foo<Bar> {}
 
 fn main() {}
diff --git a/tests/ui/on-unimplemented/feature-gate-on-unimplemented.stderr b/tests/ui/on-unimplemented/feature-gate-on-unimplemented.stderr
index 2733f7478f0..d1983088af8 100644
--- a/tests/ui/on-unimplemented/feature-gate-on-unimplemented.stderr
+++ b/tests/ui/on-unimplemented/feature-gate-on-unimplemented.stderr
@@ -1,11 +1,12 @@
-error[E0658]: this is an internal attribute that will never be stable
+error[E0658]: use of an internal attribute
   --> $DIR/feature-gate-on-unimplemented.rs:3:1
    |
 LL | #[rustc_on_unimplemented = "test error `{Self}` with `{Bar}`"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: the `#[rustc_on_unimplemented]` attribute is an internal implementation detail that will never be stable
+   = note: see `#[diagnostic::on_unimplemented]` for the stable equivalent of this attribute
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/block-no-opening-brace.rs b/tests/ui/parser/block-no-opening-brace.rs
index b08c830bfc7..ea5a98ff6fc 100644
--- a/tests/ui/parser/block-no-opening-brace.rs
+++ b/tests/ui/parser/block-no-opening-brace.rs
@@ -27,10 +27,10 @@ fn in_try() {
         let x = 0;
 }
 
-// FIXME(#80931)
 fn in_async() {
     async
-        let x = 0; //~ ERROR expected one of `move`, `use`, `|`, or `||`, found keyword `let`
+        let x = 0;
+    //~^ ERROR expected one of `move`, `use`, `{`, `|`, or `||`, found keyword `let`
 }
 
 // FIXME(#78168)
diff --git a/tests/ui/parser/block-no-opening-brace.stderr b/tests/ui/parser/block-no-opening-brace.stderr
index f51ee92626f..cf9eeba573d 100644
--- a/tests/ui/parser/block-no-opening-brace.stderr
+++ b/tests/ui/parser/block-no-opening-brace.stderr
@@ -43,11 +43,11 @@ error: expected expression, found reserved keyword `try`
 LL |     try
    |     ^^^ expected expression
 
-error: expected one of `move`, `use`, `|`, or `||`, found keyword `let`
-  --> $DIR/block-no-opening-brace.rs:33:9
+error: expected one of `move`, `use`, `{`, `|`, or `||`, found keyword `let`
+  --> $DIR/block-no-opening-brace.rs:32:9
    |
 LL |     async
-   |          - expected one of `move`, `use`, `|`, or `||`
+   |          - expected one of `move`, `use`, `{`, `|`, or `||`
 LL |         let x = 0;
    |         ^^^ unexpected token
 
diff --git a/tests/ui/parser/macro/issue-33569.rs b/tests/ui/parser/macro/issue-33569.rs
index 069d181e962..e0a5352ab06 100644
--- a/tests/ui/parser/macro/issue-33569.rs
+++ b/tests/ui/parser/macro/issue-33569.rs
@@ -2,7 +2,6 @@ macro_rules! foo {
     { $+ } => { //~ ERROR expected identifier, found `+`
                 //~^ ERROR missing fragment specifier
                 //~| ERROR missing fragment specifier
-                //~| WARN this was previously accepted
         $(x)(y) //~ ERROR expected one of: `*`, `+`, or `?`
     }
 }
diff --git a/tests/ui/parser/macro/issue-33569.stderr b/tests/ui/parser/macro/issue-33569.stderr
index d1b6abfeeeb..0d53c04c1c9 100644
--- a/tests/ui/parser/macro/issue-33569.stderr
+++ b/tests/ui/parser/macro/issue-33569.stderr
@@ -5,7 +5,7 @@ LL |     { $+ } => {
    |        ^
 
 error: expected one of: `*`, `+`, or `?`
-  --> $DIR/issue-33569.rs:6:13
+  --> $DIR/issue-33569.rs:5:13
    |
 LL |         $(x)(y)
    |             ^^^
@@ -15,27 +15,19 @@ error: missing fragment specifier
    |
 LL |     { $+ } => {
    |        ^
-
-error: missing fragment specifier
-  --> $DIR/issue-33569.rs:2:8
    |
-LL |     { $+ } => {
-   |        ^
+   = note: fragment specifiers must be provided
+   = help: valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`, along with `expr_2021` and `pat_param` for edition compatibility
+help: try adding a specifier here
    |
-   = 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 #40107 <https://github.com/rust-lang/rust/issues/40107>
-   = note: `#[deny(missing_fragment_specifier)]` on by default
+LL |     { $+:spec } => {
+   |         +++++
 
-error: aborting due to 4 previous errors
-
-Future incompatibility report: Future breakage diagnostic:
 error: missing fragment specifier
   --> $DIR/issue-33569.rs:2:8
    |
 LL |     { $+ } => {
    |        ^
-   |
-   = 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 #40107 <https://github.com/rust-lang/rust/issues/40107>
-   = note: `#[deny(missing_fragment_specifier)]` on by default
+
+error: aborting due to 4 previous errors
 
diff --git a/tests/ui/parser/misspelled-keywords/async-move.stderr b/tests/ui/parser/misspelled-keywords/async-move.stderr
index 2507326fb28..26449a17f78 100644
--- a/tests/ui/parser/misspelled-keywords/async-move.stderr
+++ b/tests/ui/parser/misspelled-keywords/async-move.stderr
@@ -1,8 +1,8 @@
-error: expected one of `move`, `use`, `|`, or `||`, found `Move`
+error: expected one of `move`, `use`, `{`, `|`, or `||`, found `Move`
   --> $DIR/async-move.rs:4:11
    |
 LL |     async Move {}
-   |           ^^^^ expected one of `move`, `use`, `|`, or `||`
+   |           ^^^^ expected one of `move`, `use`, `{`, `|`, or `||`
    |
 help: write keyword `move` in lowercase
    |
diff --git a/tests/ui/print-calling-conventions.stdout b/tests/ui/print-calling-conventions.stdout
index feee8cc3aa9..7b5ae495660 100644
--- a/tests/ui/print-calling-conventions.stdout
+++ b/tests/ui/print-calling-conventions.stdout
@@ -9,6 +9,7 @@ avr-interrupt
 avr-non-blocking-interrupt
 cdecl
 cdecl-unwind
+custom
 efiapi
 fastcall
 fastcall-unwind
diff --git a/tests/ui/proc-macro/derive-helper-legacy-limits.stderr b/tests/ui/proc-macro/derive-helper-legacy-limits.stderr
index f5cd455435d..df3c5c47ddb 100644
--- a/tests/ui/proc-macro/derive-helper-legacy-limits.stderr
+++ b/tests/ui/proc-macro/derive-helper-legacy-limits.stderr
@@ -3,6 +3,12 @@ error: cannot find attribute `empty_helper` in this scope
    |
 LL | #[empty_helper]
    |   ^^^^^^^^^^^^
+   |
+help: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute
+   |
+LL + #[derive(Empty)]
+LL | struct S2;
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/proc-macro/derive-helper-shadowing.stderr b/tests/ui/proc-macro/derive-helper-shadowing.stderr
index f284b1c54dd..1206778bb23 100644
--- a/tests/ui/proc-macro/derive-helper-shadowing.stderr
+++ b/tests/ui/proc-macro/derive-helper-shadowing.stderr
@@ -16,6 +16,7 @@ error: cannot find attribute `empty_helper` in this scope
 LL |             #[derive(GenHelperUse)]
    |                      ^^^^^^^^^^^^
    |
+   = note: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute
    = note: this error originates in the derive macro `GenHelperUse` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider importing this attribute macro through its public re-export
    |
@@ -31,6 +32,7 @@ LL |         #[empty_helper]
 LL |             gen_helper_use!();
    |             ----------------- in this macro invocation
    |
+   = note: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute
    = note: this error originates in the macro `gen_helper_use` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider importing this attribute macro through its public re-export
    |
diff --git a/tests/ui/proc-macro/disappearing-resolution.stderr b/tests/ui/proc-macro/disappearing-resolution.stderr
index 734e0cd2ab6..6c0f1a52915 100644
--- a/tests/ui/proc-macro/disappearing-resolution.stderr
+++ b/tests/ui/proc-macro/disappearing-resolution.stderr
@@ -3,6 +3,12 @@ error: cannot find attribute `empty_helper` in this scope
    |
 LL | #[empty_helper]
    |   ^^^^^^^^^^^^
+   |
+help: `empty_helper` is an attribute that can be used by the derive macro `Empty`, you might be missing a `derive` attribute
+   |
+LL + #[derive(Empty)]
+LL | struct S;
+   |
 
 error[E0603]: derive macro import `Empty` is private
   --> $DIR/disappearing-resolution.rs:11:8
diff --git a/tests/ui/regions/regions-glb-free-free.stderr b/tests/ui/regions/regions-glb-free-free.stderr
index 727669f2683..6ea09e3e1d7 100644
--- a/tests/ui/regions/regions-glb-free-free.stderr
+++ b/tests/ui/regions/regions-glb-free-free.stderr
@@ -1,8 +1,6 @@
 error[E0621]: explicit lifetime required in the type of `s`
   --> $DIR/regions-glb-free-free.rs:15:13
    |
-LL |           pub fn set_desc(self, s: &str) -> Flag<'a> {
-   |                                    ---- help: add explicit lifetime `'a` to the type of `s`: `&'a str`
 LL | /             Flag {
 LL | |                 name: self.name,
 LL | |                 desc: s,
@@ -10,6 +8,11 @@ LL | |                 max_count: self.max_count,
 LL | |                 value: self.value
 LL | |             }
    | |_____________^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to the type of `s`
+   |
+LL |         pub fn set_desc(self, s: &'a str) -> Flag<'a> {
+   |                                   ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/regions/regions-infer-at-fn-not-param.stderr b/tests/ui/regions/regions-infer-at-fn-not-param.stderr
index 4c7660276f2..58ff2586a82 100644
--- a/tests/ui/regions/regions-infer-at-fn-not-param.stderr
+++ b/tests/ui/regions/regions-infer-at-fn-not-param.stderr
@@ -2,9 +2,12 @@ error[E0621]: explicit lifetime required in the type of `p`
   --> $DIR/regions-infer-at-fn-not-param.rs:13:57
    |
 LL | fn take1<'a>(p: Parameterized1) -> Parameterized1<'a> { p }
-   |                 --------------                          ^ lifetime `'a` required
-   |                 |
-   |                 help: add explicit lifetime `'a` to the type of `p`: `Parameterized1<'a>`
+   |                                                         ^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to the type of `p`
+   |
+LL | fn take1<'a>(p: Parameterized1<'a>) -> Parameterized1<'a> { p }
+   |                               ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/resolve/auxiliary/issue-80079.rs b/tests/ui/resolve/auxiliary/issue-80079.rs
index 190ca75aba8..bfae5c5a24e 100644
--- a/tests/ui/resolve/auxiliary/issue-80079.rs
+++ b/tests/ui/resolve/auxiliary/issue-80079.rs
@@ -1,7 +1,7 @@
 #![crate_type = "lib"]
 
 pub mod public {
-    use private_import;
+    use crate::private_import;
 
     // should not be suggested since it is private
     struct Foo;
diff --git a/tests/ui/resolve/auxiliary/privacy-struct-ctor.rs b/tests/ui/resolve/auxiliary/privacy-struct-ctor.rs
index 6d0bc728524..ac157a82e17 100644
--- a/tests/ui/resolve/auxiliary/privacy-struct-ctor.rs
+++ b/tests/ui/resolve/auxiliary/privacy-struct-ctor.rs
@@ -2,7 +2,7 @@ pub mod m {
     pub struct S(u8);
 
     pub mod n {
-        pub(in m) struct Z(pub(in m::n) u8);
+        pub(in crate::m) struct Z(pub(in crate::m::n) u8);
     }
 }
 
diff --git a/tests/ui/resolve/extern-prelude-fail.rs b/tests/ui/resolve/extern-prelude-fail.rs
index c0716f1ebf5..7d0df03e57b 100644
--- a/tests/ui/resolve/extern-prelude-fail.rs
+++ b/tests/ui/resolve/extern-prelude-fail.rs
@@ -1,3 +1,4 @@
+//@ edition: 2015
 //@ compile-flags:--extern extern_prelude
 //@ aux-build:extern-prelude.rs
 
diff --git a/tests/ui/resolve/extern-prelude-fail.stderr b/tests/ui/resolve/extern-prelude-fail.stderr
index 199a31244c0..b9668154f44 100644
--- a/tests/ui/resolve/extern-prelude-fail.stderr
+++ b/tests/ui/resolve/extern-prelude-fail.stderr
@@ -1,5 +1,5 @@
 error[E0432]: unresolved import `extern_prelude`
-  --> $DIR/extern-prelude-fail.rs:7:9
+  --> $DIR/extern-prelude-fail.rs:8:9
    |
 LL |     use extern_prelude::S;
    |         ^^^^^^^^^^^^^^ use of unresolved module or unlinked crate `extern_prelude`
@@ -10,7 +10,7 @@ LL + extern crate extern_prelude;
    |
 
 error[E0433]: failed to resolve: use of unresolved module or unlinked crate `extern_prelude`
-  --> $DIR/extern-prelude-fail.rs:8:15
+  --> $DIR/extern-prelude-fail.rs:9:15
    |
 LL |     let s = ::extern_prelude::S;
    |               ^^^^^^^^^^^^^^ use of unresolved module or unlinked crate `extern_prelude`
diff --git a/tests/ui/resolve/global-scope-resolution.rs b/tests/ui/resolve/global-scope-resolution.rs
new file mode 100644
index 00000000000..176bab36da7
--- /dev/null
+++ b/tests/ui/resolve/global-scope-resolution.rs
@@ -0,0 +1,21 @@
+//! Test global scope resolution with :: operator
+
+//@ run-pass
+
+pub fn f() -> isize {
+    return 1;
+}
+
+pub mod foo {
+    pub fn f() -> isize {
+        return 2;
+    }
+    pub fn g() {
+        assert_eq!(f(), 2);
+        assert_eq!(::f(), 1);
+    }
+}
+
+pub fn main() {
+    return foo::g();
+}
diff --git a/tests/ui/resolve/issue-42944.rs b/tests/ui/resolve/issue-42944.rs
index 7e439c10b7b..24aa110329b 100644
--- a/tests/ui/resolve/issue-42944.rs
+++ b/tests/ui/resolve/issue-42944.rs
@@ -3,7 +3,7 @@ mod foo {
 }
 
 mod bar {
-    use foo::Bx;
+    use crate::foo::Bx;
 
     fn foo() {
         Bx(());
diff --git a/tests/ui/resolve/issue-5035.rs b/tests/ui/resolve/issue-5035.rs
index 82c4bc0d5ef..a9e2509dde9 100644
--- a/tests/ui/resolve/issue-5035.rs
+++ b/tests/ui/resolve/issue-5035.rs
@@ -4,7 +4,7 @@ trait I {}
 type K = dyn I;
 impl K for isize {} //~ ERROR expected trait, found type alias `K`
 
-use ImportError; //~ ERROR unresolved import `ImportError` [E0432]
+use crate::ImportError; //~ ERROR unresolved import `crate::ImportError` [E0432]
                  //~^ NOTE no `ImportError` in the root
 impl ImportError for () {} // check that this is not an additional error (cf. issue #35142)
 
diff --git a/tests/ui/resolve/issue-5035.stderr b/tests/ui/resolve/issue-5035.stderr
index f5717438fc8..b26c962c9bb 100644
--- a/tests/ui/resolve/issue-5035.stderr
+++ b/tests/ui/resolve/issue-5035.stderr
@@ -1,8 +1,8 @@
-error[E0432]: unresolved import `ImportError`
+error[E0432]: unresolved import `crate::ImportError`
   --> $DIR/issue-5035.rs:7:5
    |
-LL | use ImportError;
-   |     ^^^^^^^^^^^ no `ImportError` in the root
+LL | use crate::ImportError;
+   |     ^^^^^^^^^^^^^^^^^^ no `ImportError` in the root
 
 error[E0404]: expected trait, found type alias `K`
   --> $DIR/issue-5035.rs:5:6
diff --git a/tests/ui/resolve/nonexistent-macro.rs b/tests/ui/resolve/nonexistent-macro.rs
new file mode 100644
index 00000000000..663075473a1
--- /dev/null
+++ b/tests/ui/resolve/nonexistent-macro.rs
@@ -0,0 +1,6 @@
+//! Test error handling for undefined macro calls
+
+fn main() {
+    iamnotanextensionthatexists!("");
+    //~^ ERROR cannot find macro `iamnotanextensionthatexists` in this scope
+}
diff --git a/tests/ui/resolve/nonexistent-macro.stderr b/tests/ui/resolve/nonexistent-macro.stderr
new file mode 100644
index 00000000000..7e89e07bf30
--- /dev/null
+++ b/tests/ui/resolve/nonexistent-macro.stderr
@@ -0,0 +1,8 @@
+error: cannot find macro `iamnotanextensionthatexists` in this scope
+  --> $DIR/nonexistent-macro.rs:4:5
+   |
+LL |     iamnotanextensionthatexists!("");
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/resolve/privacy-enum-ctor.rs b/tests/ui/resolve/privacy-enum-ctor.rs
index f0d2cf8c04e..3f79b12a267 100644
--- a/tests/ui/resolve/privacy-enum-ctor.rs
+++ b/tests/ui/resolve/privacy-enum-ctor.rs
@@ -8,7 +8,7 @@ mod m {
     }
 
     pub mod n {
-        pub(in m) enum Z {
+        pub(in crate::m) enum Z {
             Fn(u8),
             Struct {
                 s: u8,
@@ -17,7 +17,7 @@ mod m {
         }
     }
 
-    use m::n::Z; // OK, only the type is imported
+    use crate::m::n::Z; // OK, only the type is imported
 
     fn f() {
         n::Z;
diff --git a/tests/ui/resolve/privacy-enum-ctor.stderr b/tests/ui/resolve/privacy-enum-ctor.stderr
index f349b9391d1..4ec1b6b97bd 100644
--- a/tests/ui/resolve/privacy-enum-ctor.stderr
+++ b/tests/ui/resolve/privacy-enum-ctor.stderr
@@ -7,7 +7,7 @@ LL |         n::Z;
 note: the enum is defined here
   --> $DIR/privacy-enum-ctor.rs:11:9
    |
-LL | /         pub(in m) enum Z {
+LL | /         pub(in crate::m) enum Z {
 LL | |             Fn(u8),
 LL | |             Struct {
 LL | |                 s: u8,
@@ -35,7 +35,7 @@ LL |         Z;
 note: the enum is defined here
   --> $DIR/privacy-enum-ctor.rs:11:9
    |
-LL | /         pub(in m) enum Z {
+LL | /         pub(in crate::m) enum Z {
 LL | |             Fn(u8),
 LL | |             Struct {
 LL | |                 s: u8,
@@ -154,8 +154,8 @@ LL |     let _: Z = m::n::Z;
 note: enum `m::Z` exists but is inaccessible
   --> $DIR/privacy-enum-ctor.rs:11:9
    |
-LL |         pub(in m) enum Z {
-   |         ^^^^^^^^^^^^^^^^ not accessible
+LL |         pub(in crate::m) enum Z {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ not accessible
 
 error[E0423]: expected value, found enum `m::n::Z`
   --> $DIR/privacy-enum-ctor.rs:57:16
@@ -166,7 +166,7 @@ LL |     let _: Z = m::n::Z;
 note: the enum is defined here
   --> $DIR/privacy-enum-ctor.rs:11:9
    |
-LL | /         pub(in m) enum Z {
+LL | /         pub(in crate::m) enum Z {
 LL | |             Fn(u8),
 LL | |             Struct {
 LL | |                 s: u8,
@@ -197,8 +197,8 @@ LL |     let _: Z = m::n::Z::Fn;
 note: enum `m::Z` exists but is inaccessible
   --> $DIR/privacy-enum-ctor.rs:11:9
    |
-LL |         pub(in m) enum Z {
-   |         ^^^^^^^^^^^^^^^^ not accessible
+LL |         pub(in crate::m) enum Z {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ not accessible
 
 error[E0412]: cannot find type `Z` in this scope
   --> $DIR/privacy-enum-ctor.rs:64:12
@@ -212,8 +212,8 @@ LL |     let _: Z = m::n::Z::Struct;
 note: enum `m::Z` exists but is inaccessible
   --> $DIR/privacy-enum-ctor.rs:11:9
    |
-LL |         pub(in m) enum Z {
-   |         ^^^^^^^^^^^^^^^^ not accessible
+LL |         pub(in crate::m) enum Z {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ not accessible
 
 error[E0412]: cannot find type `Z` in this scope
   --> $DIR/privacy-enum-ctor.rs:68:12
@@ -227,8 +227,8 @@ LL |     let _: Z = m::n::Z::Unit {};
 note: enum `m::Z` exists but is inaccessible
   --> $DIR/privacy-enum-ctor.rs:11:9
    |
-LL |         pub(in m) enum Z {
-   |         ^^^^^^^^^^^^^^^^ not accessible
+LL |         pub(in crate::m) enum Z {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^ not accessible
 
 error[E0603]: enum `Z` is private
   --> $DIR/privacy-enum-ctor.rs:57:22
@@ -239,8 +239,8 @@ LL |     let _: Z = m::n::Z;
 note: the enum `Z` is defined here
   --> $DIR/privacy-enum-ctor.rs:11:9
    |
-LL |         pub(in m) enum Z {
-   |         ^^^^^^^^^^^^^^^^
+LL |         pub(in crate::m) enum Z {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: enum `Z` is private
   --> $DIR/privacy-enum-ctor.rs:61:22
@@ -253,8 +253,8 @@ LL |     let _: Z = m::n::Z::Fn;
 note: the enum `Z` is defined here
   --> $DIR/privacy-enum-ctor.rs:11:9
    |
-LL |         pub(in m) enum Z {
-   |         ^^^^^^^^^^^^^^^^
+LL |         pub(in crate::m) enum Z {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: enum `Z` is private
   --> $DIR/privacy-enum-ctor.rs:64:22
@@ -265,8 +265,8 @@ LL |     let _: Z = m::n::Z::Struct;
 note: the enum `Z` is defined here
   --> $DIR/privacy-enum-ctor.rs:11:9
    |
-LL |         pub(in m) enum Z {
-   |         ^^^^^^^^^^^^^^^^
+LL |         pub(in crate::m) enum Z {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0603]: enum `Z` is private
   --> $DIR/privacy-enum-ctor.rs:68:22
@@ -279,8 +279,8 @@ LL |     let _: Z = m::n::Z::Unit {};
 note: the enum `Z` is defined here
   --> $DIR/privacy-enum-ctor.rs:11:9
    |
-LL |         pub(in m) enum Z {
-   |         ^^^^^^^^^^^^^^^^
+LL |         pub(in crate::m) enum Z {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0308]: mismatched types
   --> $DIR/privacy-enum-ctor.rs:27:20
diff --git a/tests/ui/resolve/privacy-struct-ctor.rs b/tests/ui/resolve/privacy-struct-ctor.rs
index da0e9f2fc04..70c751999b7 100644
--- a/tests/ui/resolve/privacy-struct-ctor.rs
+++ b/tests/ui/resolve/privacy-struct-ctor.rs
@@ -9,10 +9,10 @@ mod m {
     }
 
     pub mod n {
-        pub(in m) struct Z(pub(in m::n) u8);
+        pub(in crate::m) struct Z(pub(in crate::m::n) u8);
     }
 
-    use m::n::Z; // OK, only the type is imported
+    use crate::m::n::Z; // OK, only the type is imported
 
     fn f() {
         n::Z;
diff --git a/tests/ui/resolve/privacy-struct-ctor.stderr b/tests/ui/resolve/privacy-struct-ctor.stderr
index 1d8c741c964..0a6b1b46afa 100644
--- a/tests/ui/resolve/privacy-struct-ctor.stderr
+++ b/tests/ui/resolve/privacy-struct-ctor.stderr
@@ -42,8 +42,8 @@ LL |     pub struct S(u8);
 error[E0603]: tuple struct constructor `Z` is private
   --> $DIR/privacy-struct-ctor.rs:18:12
    |
-LL |         pub(in m) struct Z(pub(in m::n) u8);
-   |                            --------------- a constructor is private if any of the fields is private
+LL |         pub(in crate::m) struct Z(pub(in crate::m::n) u8);
+   |                                   ---------------------- a constructor is private if any of the fields is private
 ...
 LL |         n::Z;
    |            ^ private tuple struct constructor
@@ -51,12 +51,12 @@ LL |         n::Z;
 note: the tuple struct constructor `Z` is defined here
   --> $DIR/privacy-struct-ctor.rs:12:9
    |
-LL |         pub(in m) struct Z(pub(in m::n) u8);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         pub(in crate::m) struct Z(pub(in crate::m::n) u8);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider making the field publicly accessible
    |
-LL -         pub(in m) struct Z(pub(in m::n) u8);
-LL +         pub(in m) struct Z(pub u8);
+LL -         pub(in crate::m) struct Z(pub(in crate::m::n) u8);
+LL +         pub(in crate::m) struct Z(pub u8);
    |
 
 error[E0603]: tuple struct constructor `S` is private
@@ -100,8 +100,8 @@ LL |     pub struct S(pub u8);
 error[E0603]: tuple struct constructor `Z` is private
   --> $DIR/privacy-struct-ctor.rs:35:11
    |
-LL |         pub(in m) struct Z(pub(in m::n) u8);
-   |                            --------------- a constructor is private if any of the fields is private
+LL |         pub(in crate::m) struct Z(pub(in crate::m::n) u8);
+   |                                   ---------------------- a constructor is private if any of the fields is private
 ...
 LL |     m::n::Z;
    |           ^ private tuple struct constructor
@@ -109,12 +109,12 @@ LL |     m::n::Z;
 note: the tuple struct constructor `Z` is defined here
   --> $DIR/privacy-struct-ctor.rs:12:9
    |
-LL |         pub(in m) struct Z(pub(in m::n) u8);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         pub(in crate::m) struct Z(pub(in crate::m::n) u8);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 help: consider making the field publicly accessible
    |
-LL -         pub(in m) struct Z(pub(in m::n) u8);
-LL +         pub(in m) struct Z(pub u8);
+LL -         pub(in crate::m) struct Z(pub(in crate::m::n) u8);
+LL +         pub(in crate::m) struct Z(pub u8);
    |
 
 error[E0603]: tuple struct constructor `S` is private
@@ -140,16 +140,16 @@ error[E0603]: tuple struct constructor `Z` is private
 LL |     xcrate::m::n::Z;
    |                   ^ private tuple struct constructor
    |
-  ::: $DIR/auxiliary/privacy-struct-ctor.rs:5:28
+  ::: $DIR/auxiliary/privacy-struct-ctor.rs:5:35
    |
-LL |         pub(in m) struct Z(pub(in m::n) u8);
-   |                            --------------- a constructor is private if any of the fields is private
+LL |         pub(in crate::m) struct Z(pub(in crate::m::n) u8);
+   |                                   ---------------------- a constructor is private if any of the fields is private
    |
 note: the tuple struct constructor `Z` is defined here
   --> $DIR/auxiliary/privacy-struct-ctor.rs:5:9
    |
-LL |         pub(in m) struct Z(pub(in m::n) u8);
-   |         ^^^^^^^^^^^^^^^^^^
+LL |         pub(in crate::m) struct Z(pub(in crate::m::n) u8);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 10 previous errors
 
diff --git a/tests/ui/resolve/resolve-bad-visibility.rs b/tests/ui/resolve/resolve-bad-visibility.rs
index 7d48bb97b10..81635611fca 100644
--- a/tests/ui/resolve/resolve-bad-visibility.rs
+++ b/tests/ui/resolve/resolve-bad-visibility.rs
@@ -1,3 +1,4 @@
+//@ edition: 2015
 enum E {}
 trait Tr {}
 
diff --git a/tests/ui/resolve/resolve-bad-visibility.stderr b/tests/ui/resolve/resolve-bad-visibility.stderr
index ac7e1c735b1..c7bbdfbd249 100644
--- a/tests/ui/resolve/resolve-bad-visibility.stderr
+++ b/tests/ui/resolve/resolve-bad-visibility.stderr
@@ -1,23 +1,23 @@
 error[E0577]: expected module, found enum `E`
-  --> $DIR/resolve-bad-visibility.rs:4:8
+  --> $DIR/resolve-bad-visibility.rs:5:8
    |
 LL | pub(in E) struct S;
    |        ^ not a module
 
 error[E0577]: expected module, found trait `Tr`
-  --> $DIR/resolve-bad-visibility.rs:5:8
+  --> $DIR/resolve-bad-visibility.rs:6:8
    |
 LL | pub(in Tr) struct Z;
    |        ^^ not a module
 
 error[E0742]: visibilities can only be restricted to ancestor modules
-  --> $DIR/resolve-bad-visibility.rs:6:8
+  --> $DIR/resolve-bad-visibility.rs:7:8
    |
 LL | pub(in std::vec) struct F;
    |        ^^^^^^^^
 
 error[E0433]: failed to resolve: use of unresolved module or unlinked crate `nonexistent`
-  --> $DIR/resolve-bad-visibility.rs:7:8
+  --> $DIR/resolve-bad-visibility.rs:8:8
    |
 LL | pub(in nonexistent) struct G;
    |        ^^^^^^^^^^^ use of unresolved module or unlinked crate `nonexistent`
@@ -28,7 +28,7 @@ LL + extern crate nonexistent;
    |
 
 error[E0433]: failed to resolve: use of unresolved module or unlinked crate `too_soon`
-  --> $DIR/resolve-bad-visibility.rs:8:8
+  --> $DIR/resolve-bad-visibility.rs:9:8
    |
 LL | pub(in too_soon) struct H;
    |        ^^^^^^^^ use of unresolved module or unlinked crate `too_soon`
diff --git a/tests/ui/resolve/suggest-builder-fn.rs b/tests/ui/resolve/suggest-builder-fn.rs
index 0d9b35549a4..959675ef2c9 100644
--- a/tests/ui/resolve/suggest-builder-fn.rs
+++ b/tests/ui/resolve/suggest-builder-fn.rs
@@ -32,7 +32,7 @@ impl Bar {
 }
 
 mod SomeMod {
-    use Bar;
+    use crate::Bar;
 
     impl Bar {
         // Public method. Should be suggested
diff --git a/tests/ui/resolve/unresolved-segments-visibility.rs b/tests/ui/resolve/unresolved-segments-visibility.rs
index c26171f75d2..fc86b31adfc 100644
--- a/tests/ui/resolve/unresolved-segments-visibility.rs
+++ b/tests/ui/resolve/unresolved-segments-visibility.rs
@@ -5,7 +5,7 @@ extern crate alloc as b;
 
 mod foo {
     mod bar {
-        pub(in b::string::String::newy) extern crate alloc as e;
+        pub(in crate::b::string::String::newy) extern crate alloc as e;
         //~^ ERROR failed to resolve: `String` is a struct, not a module [E0433]
     }
 }
diff --git a/tests/ui/resolve/unresolved-segments-visibility.stderr b/tests/ui/resolve/unresolved-segments-visibility.stderr
index 09f3c50258d..082579c9fa1 100644
--- a/tests/ui/resolve/unresolved-segments-visibility.stderr
+++ b/tests/ui/resolve/unresolved-segments-visibility.stderr
@@ -1,8 +1,8 @@
 error[E0433]: failed to resolve: `String` is a struct, not a module
-  --> $DIR/unresolved-segments-visibility.rs:8:27
+  --> $DIR/unresolved-segments-visibility.rs:8:34
    |
-LL |         pub(in b::string::String::newy) extern crate alloc as e;
-   |                           ^^^^^^ `String` is a struct, not a module
+LL |         pub(in crate::b::string::String::newy) extern crate alloc as e;
+   |                                  ^^^^^^ `String` is a struct, not a module
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rust-2018/edition-lint-fully-qualified-paths.fixed b/tests/ui/rust-2018/edition-lint-fully-qualified-paths.fixed
index fbe415e2e10..d685c4944ba 100644
--- a/tests/ui/rust-2018/edition-lint-fully-qualified-paths.fixed
+++ b/tests/ui/rust-2018/edition-lint-fully-qualified-paths.fixed
@@ -1,3 +1,4 @@
+//@ edition: 2015
 //@ run-rustfix
 
 #![deny(absolute_paths_not_starting_with_crate)]
diff --git a/tests/ui/rust-2018/edition-lint-fully-qualified-paths.rs b/tests/ui/rust-2018/edition-lint-fully-qualified-paths.rs
index 72a212453cd..7a5ecf2720a 100644
--- a/tests/ui/rust-2018/edition-lint-fully-qualified-paths.rs
+++ b/tests/ui/rust-2018/edition-lint-fully-qualified-paths.rs
@@ -1,3 +1,4 @@
+//@ edition: 2015
 //@ run-rustfix
 
 #![deny(absolute_paths_not_starting_with_crate)]
diff --git a/tests/ui/rust-2018/edition-lint-fully-qualified-paths.stderr b/tests/ui/rust-2018/edition-lint-fully-qualified-paths.stderr
index 036b9ccab4f..c0a322edcd6 100644
--- a/tests/ui/rust-2018/edition-lint-fully-qualified-paths.stderr
+++ b/tests/ui/rust-2018/edition-lint-fully-qualified-paths.stderr
@@ -1,5 +1,5 @@
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-fully-qualified-paths.rs:18:25
+  --> $DIR/edition-lint-fully-qualified-paths.rs:19:25
    |
 LL |     let _: <foo::Baz as ::foo::Foo>::Bar = ();
    |                         ^^^^^^^^^^ help: use `crate`: `crate::foo::Foo`
@@ -7,13 +7,13 @@ LL |     let _: <foo::Baz as ::foo::Foo>::Bar = ();
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 note: the lint level is defined here
-  --> $DIR/edition-lint-fully-qualified-paths.rs:3:9
+  --> $DIR/edition-lint-fully-qualified-paths.rs:4:9
    |
 LL | #![deny(absolute_paths_not_starting_with_crate)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-fully-qualified-paths.rs:18:25
+  --> $DIR/edition-lint-fully-qualified-paths.rs:19:25
    |
 LL |     let _: <foo::Baz as ::foo::Foo>::Bar = ();
    |                         ^^^^^^^^^^ help: use `crate`: `crate::foo::Foo`
@@ -23,7 +23,7 @@ LL |     let _: <foo::Baz as ::foo::Foo>::Bar = ();
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-fully-qualified-paths.rs:24:13
+  --> $DIR/edition-lint-fully-qualified-paths.rs:25:13
    |
 LL |     let _: <::foo::Baz as foo::Foo>::Bar = ();
    |             ^^^^^^^^^^ help: use `crate`: `crate::foo::Baz`
diff --git a/tests/ui/rust-2018/edition-lint-nested-empty-paths.fixed b/tests/ui/rust-2018/edition-lint-nested-empty-paths.fixed
index 7ec421099c7..4a584a55e64 100644
--- a/tests/ui/rust-2018/edition-lint-nested-empty-paths.fixed
+++ b/tests/ui/rust-2018/edition-lint-nested-empty-paths.fixed
@@ -1,3 +1,4 @@
+//@ edition: 2015
 //@ run-rustfix
 
 #![deny(absolute_paths_not_starting_with_crate)]
diff --git a/tests/ui/rust-2018/edition-lint-nested-empty-paths.rs b/tests/ui/rust-2018/edition-lint-nested-empty-paths.rs
index 135908c8aef..2baafbd9704 100644
--- a/tests/ui/rust-2018/edition-lint-nested-empty-paths.rs
+++ b/tests/ui/rust-2018/edition-lint-nested-empty-paths.rs
@@ -1,3 +1,4 @@
+//@ edition: 2015
 //@ run-rustfix
 
 #![deny(absolute_paths_not_starting_with_crate)]
diff --git a/tests/ui/rust-2018/edition-lint-nested-empty-paths.stderr b/tests/ui/rust-2018/edition-lint-nested-empty-paths.stderr
index 4174c2fa9ad..041572be844 100644
--- a/tests/ui/rust-2018/edition-lint-nested-empty-paths.stderr
+++ b/tests/ui/rust-2018/edition-lint-nested-empty-paths.stderr
@@ -1,5 +1,5 @@
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-nested-empty-paths.rs:16:5
+  --> $DIR/edition-lint-nested-empty-paths.rs:17:5
    |
 LL | use foo::{bar::{baz::{}}};
    |     ^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{baz::{}}}`
@@ -7,13 +7,13 @@ LL | use foo::{bar::{baz::{}}};
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 note: the lint level is defined here
-  --> $DIR/edition-lint-nested-empty-paths.rs:3:9
+  --> $DIR/edition-lint-nested-empty-paths.rs:4:9
    |
 LL | #![deny(absolute_paths_not_starting_with_crate)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-nested-empty-paths.rs:20:5
+  --> $DIR/edition-lint-nested-empty-paths.rs:21:5
    |
 LL | use foo::{bar::{XX, baz::{}}};
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{XX, baz::{}}}`
@@ -22,7 +22,7 @@ LL | use foo::{bar::{XX, baz::{}}};
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-nested-empty-paths.rs:20:5
+  --> $DIR/edition-lint-nested-empty-paths.rs:21:5
    |
 LL | use foo::{bar::{XX, baz::{}}};
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{XX, baz::{}}}`
@@ -32,7 +32,7 @@ LL | use foo::{bar::{XX, baz::{}}};
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-nested-empty-paths.rs:26:5
+  --> $DIR/edition-lint-nested-empty-paths.rs:27:5
    |
 LL | use foo::{bar::{baz::{}, baz1::{}}};
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{baz::{}, baz1::{}}}`
@@ -41,7 +41,7 @@ LL | use foo::{bar::{baz::{}, baz1::{}}};
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-nested-empty-paths.rs:26:5
+  --> $DIR/edition-lint-nested-empty-paths.rs:27:5
    |
 LL | use foo::{bar::{baz::{}, baz1::{}}};
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{bar::{baz::{}, baz1::{}}}`
diff --git a/tests/ui/rust-2018/edition-lint-nested-paths.fixed b/tests/ui/rust-2018/edition-lint-nested-paths.fixed
index 93ccb2fe6af..bf0038c3be4 100644
--- a/tests/ui/rust-2018/edition-lint-nested-paths.fixed
+++ b/tests/ui/rust-2018/edition-lint-nested-paths.fixed
@@ -1,3 +1,4 @@
+//@ edition: 2015
 //@ run-rustfix
 
 #![deny(absolute_paths_not_starting_with_crate)]
diff --git a/tests/ui/rust-2018/edition-lint-nested-paths.rs b/tests/ui/rust-2018/edition-lint-nested-paths.rs
index 1c1d21dbab9..87dc51a3745 100644
--- a/tests/ui/rust-2018/edition-lint-nested-paths.rs
+++ b/tests/ui/rust-2018/edition-lint-nested-paths.rs
@@ -1,3 +1,4 @@
+//@ edition: 2015
 //@ run-rustfix
 
 #![deny(absolute_paths_not_starting_with_crate)]
diff --git a/tests/ui/rust-2018/edition-lint-nested-paths.stderr b/tests/ui/rust-2018/edition-lint-nested-paths.stderr
index d059a2533a9..4a70bb7e5c8 100644
--- a/tests/ui/rust-2018/edition-lint-nested-paths.stderr
+++ b/tests/ui/rust-2018/edition-lint-nested-paths.stderr
@@ -1,5 +1,5 @@
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-nested-paths.rs:5:5
+  --> $DIR/edition-lint-nested-paths.rs:6:5
    |
 LL | use foo::{a, b};
    |     ^^^^^^^^^^^ help: use `crate`: `crate::foo::{a, b}`
@@ -7,13 +7,13 @@ LL | use foo::{a, b};
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 note: the lint level is defined here
-  --> $DIR/edition-lint-nested-paths.rs:3:9
+  --> $DIR/edition-lint-nested-paths.rs:4:9
    |
 LL | #![deny(absolute_paths_not_starting_with_crate)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-nested-paths.rs:5:5
+  --> $DIR/edition-lint-nested-paths.rs:6:5
    |
 LL | use foo::{a, b};
    |     ^^^^^^^^^^^ help: use `crate`: `crate::foo::{a, b}`
@@ -23,7 +23,7 @@ LL | use foo::{a, b};
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-nested-paths.rs:22:13
+  --> $DIR/edition-lint-nested-paths.rs:23:13
    |
 LL |         use foo::{self as x, c};
    |             ^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{self as x, c}`
@@ -32,7 +32,7 @@ LL |         use foo::{self as x, c};
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-nested-paths.rs:22:13
+  --> $DIR/edition-lint-nested-paths.rs:23:13
    |
 LL |         use foo::{self as x, c};
    |             ^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::{self as x, c}`
diff --git a/tests/ui/rust-2018/edition-lint-paths.fixed b/tests/ui/rust-2018/edition-lint-paths.fixed
index 014bf91886f..9664b461161 100644
--- a/tests/ui/rust-2018/edition-lint-paths.fixed
+++ b/tests/ui/rust-2018/edition-lint-paths.fixed
@@ -1,3 +1,4 @@
+//@ edition: 2015
 //@ aux-build:edition-lint-paths.rs
 //@ run-rustfix
 
diff --git a/tests/ui/rust-2018/edition-lint-paths.rs b/tests/ui/rust-2018/edition-lint-paths.rs
index 0ecd090c1df..39cdad3ab98 100644
--- a/tests/ui/rust-2018/edition-lint-paths.rs
+++ b/tests/ui/rust-2018/edition-lint-paths.rs
@@ -1,3 +1,4 @@
+//@ edition: 2015
 //@ aux-build:edition-lint-paths.rs
 //@ run-rustfix
 
diff --git a/tests/ui/rust-2018/edition-lint-paths.stderr b/tests/ui/rust-2018/edition-lint-paths.stderr
index 553a3bfdaa8..fde17338d98 100644
--- a/tests/ui/rust-2018/edition-lint-paths.stderr
+++ b/tests/ui/rust-2018/edition-lint-paths.stderr
@@ -1,5 +1,5 @@
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-paths.rs:11:9
+  --> $DIR/edition-lint-paths.rs:12:9
    |
 LL |     use bar::Bar;
    |         ^^^^^^^^ help: use `crate`: `crate::bar::Bar`
@@ -7,13 +7,13 @@ LL |     use bar::Bar;
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 note: the lint level is defined here
-  --> $DIR/edition-lint-paths.rs:4:9
+  --> $DIR/edition-lint-paths.rs:5:9
    |
 LL | #![deny(absolute_paths_not_starting_with_crate)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-paths.rs:18:9
+  --> $DIR/edition-lint-paths.rs:19:9
    |
 LL |     use bar;
    |         ^^^ help: use `crate`: `crate::bar`
@@ -22,7 +22,7 @@ LL |     use bar;
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-paths.rs:24:9
+  --> $DIR/edition-lint-paths.rs:25:9
    |
 LL |     use {main, Bar as SomethingElse};
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::{main, Bar as SomethingElse}`
@@ -31,7 +31,7 @@ LL |     use {main, Bar as SomethingElse};
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-paths.rs:24:9
+  --> $DIR/edition-lint-paths.rs:25:9
    |
 LL |     use {main, Bar as SomethingElse};
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::{main, Bar as SomethingElse}`
@@ -41,7 +41,7 @@ LL |     use {main, Bar as SomethingElse};
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-paths.rs:24:9
+  --> $DIR/edition-lint-paths.rs:25:9
    |
 LL |     use {main, Bar as SomethingElse};
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::{main, Bar as SomethingElse}`
@@ -51,7 +51,7 @@ LL |     use {main, Bar as SomethingElse};
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-paths.rs:39:5
+  --> $DIR/edition-lint-paths.rs:40:5
    |
 LL | use bar::Bar;
    |     ^^^^^^^^ help: use `crate`: `crate::bar::Bar`
@@ -60,7 +60,7 @@ LL | use bar::Bar;
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-paths.rs:51:9
+  --> $DIR/edition-lint-paths.rs:52:9
    |
 LL |     use *;
    |         ^ help: use `crate`: `crate::*`
@@ -69,7 +69,7 @@ LL |     use *;
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-paths.rs:56:6
+  --> $DIR/edition-lint-paths.rs:57:6
    |
 LL | impl ::foo::SomeTrait for u32 {}
    |      ^^^^^^^^^^^^^^^^ help: use `crate`: `crate::foo::SomeTrait`
@@ -78,7 +78,7 @@ LL | impl ::foo::SomeTrait for u32 {}
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/edition-lint-paths.rs:61:13
+  --> $DIR/edition-lint-paths.rs:62:13
    |
 LL |     let x = ::bar::Bar;
    |             ^^^^^^^^^^ help: use `crate`: `crate::bar::Bar`
diff --git a/tests/ui/rust-2018/extern-crate-rename.fixed b/tests/ui/rust-2018/extern-crate-rename.fixed
index 36b52802990..b6b665f537e 100644
--- a/tests/ui/rust-2018/extern-crate-rename.fixed
+++ b/tests/ui/rust-2018/extern-crate-rename.fixed
@@ -1,3 +1,4 @@
+//@ edition: 2015
 //@ aux-build:edition-lint-paths.rs
 //@ run-rustfix
 
diff --git a/tests/ui/rust-2018/extern-crate-rename.rs b/tests/ui/rust-2018/extern-crate-rename.rs
index 725e3aaa072..3257ab876e1 100644
--- a/tests/ui/rust-2018/extern-crate-rename.rs
+++ b/tests/ui/rust-2018/extern-crate-rename.rs
@@ -1,3 +1,4 @@
+//@ edition: 2015
 //@ aux-build:edition-lint-paths.rs
 //@ run-rustfix
 
diff --git a/tests/ui/rust-2018/extern-crate-rename.stderr b/tests/ui/rust-2018/extern-crate-rename.stderr
index 6b251208030..36986c89c62 100644
--- a/tests/ui/rust-2018/extern-crate-rename.stderr
+++ b/tests/ui/rust-2018/extern-crate-rename.stderr
@@ -1,5 +1,5 @@
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/extern-crate-rename.rs:11:5
+  --> $DIR/extern-crate-rename.rs:12:5
    |
 LL | use my_crate::foo;
    |     ^^^^^^^^^^^^^ help: use `crate`: `crate::my_crate::foo`
@@ -7,7 +7,7 @@ LL | use my_crate::foo;
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 note: the lint level is defined here
-  --> $DIR/extern-crate-rename.rs:7:9
+  --> $DIR/extern-crate-rename.rs:8:9
    |
 LL | #![deny(absolute_paths_not_starting_with_crate)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rust-2018/extern-crate-submod.fixed b/tests/ui/rust-2018/extern-crate-submod.fixed
index dc864d87039..8657960e972 100644
--- a/tests/ui/rust-2018/extern-crate-submod.fixed
+++ b/tests/ui/rust-2018/extern-crate-submod.fixed
@@ -1,3 +1,4 @@
+//@ edition: 2015
 //@ aux-build:edition-lint-paths.rs
 //@ run-rustfix
 
diff --git a/tests/ui/rust-2018/extern-crate-submod.rs b/tests/ui/rust-2018/extern-crate-submod.rs
index f15bc6bced8..bf0a38d2b34 100644
--- a/tests/ui/rust-2018/extern-crate-submod.rs
+++ b/tests/ui/rust-2018/extern-crate-submod.rs
@@ -1,3 +1,4 @@
+//@ edition: 2015
 //@ aux-build:edition-lint-paths.rs
 //@ run-rustfix
 
diff --git a/tests/ui/rust-2018/extern-crate-submod.stderr b/tests/ui/rust-2018/extern-crate-submod.stderr
index 0d45d32d568..85e26d72a67 100644
--- a/tests/ui/rust-2018/extern-crate-submod.stderr
+++ b/tests/ui/rust-2018/extern-crate-submod.stderr
@@ -1,5 +1,5 @@
 error: absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
-  --> $DIR/extern-crate-submod.rs:18:5
+  --> $DIR/extern-crate-submod.rs:19:5
    |
 LL | use m::edition_lint_paths::foo;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `crate`: `crate::m::edition_lint_paths::foo`
@@ -7,7 +7,7 @@ LL | use m::edition_lint_paths::foo;
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
    = note: for more information, see issue #53130 <https://github.com/rust-lang/rust/issues/53130>
 note: the lint level is defined here
-  --> $DIR/extern-crate-submod.rs:8:9
+  --> $DIR/extern-crate-submod.rs:9:9
    |
 LL | #![deny(absolute_paths_not_starting_with_crate)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rust-2018/try-ident.fixed b/tests/ui/rust-2018/try-ident.fixed
index b1c446e1022..b514c6d0756 100644
--- a/tests/ui/rust-2018/try-ident.fixed
+++ b/tests/ui/rust-2018/try-ident.fixed
@@ -1,3 +1,4 @@
+//@ edition: 2015
 //@ run-rustfix
 //@ check-pass
 
diff --git a/tests/ui/rust-2018/try-ident.rs b/tests/ui/rust-2018/try-ident.rs
index 8e62f698e25..2b8bb9234e5 100644
--- a/tests/ui/rust-2018/try-ident.rs
+++ b/tests/ui/rust-2018/try-ident.rs
@@ -1,3 +1,4 @@
+//@ edition: 2015
 //@ run-rustfix
 //@ check-pass
 
diff --git a/tests/ui/rust-2018/try-ident.stderr b/tests/ui/rust-2018/try-ident.stderr
index eaf4c235697..aca623d7d48 100644
--- a/tests/ui/rust-2018/try-ident.stderr
+++ b/tests/ui/rust-2018/try-ident.stderr
@@ -1,5 +1,5 @@
 warning: `try` is a keyword in the 2018 edition
-  --> $DIR/try-ident.rs:7:5
+  --> $DIR/try-ident.rs:8:5
    |
 LL |     try();
    |     ^^^ help: you can use a raw identifier to stay compatible: `r#try`
@@ -7,14 +7,14 @@ LL |     try();
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 note: the lint level is defined here
-  --> $DIR/try-ident.rs:4:9
+  --> $DIR/try-ident.rs:5:9
    |
 LL | #![warn(rust_2018_compatibility)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^
    = note: `#[warn(keyword_idents_2018)]` implied by `#[warn(rust_2018_compatibility)]`
 
 warning: `try` is a keyword in the 2018 edition
-  --> $DIR/try-ident.rs:12:4
+  --> $DIR/try-ident.rs:13:4
    |
 LL | fn try() {
    |    ^^^ help: you can use a raw identifier to stay compatible: `r#try`
diff --git a/tests/ui/rust-2018/try-macro.fixed b/tests/ui/rust-2018/try-macro.fixed
index 98c48d6b96f..f2d8cf2bd9a 100644
--- a/tests/ui/rust-2018/try-macro.fixed
+++ b/tests/ui/rust-2018/try-macro.fixed
@@ -1,5 +1,6 @@
 // Test that `try!` macros are rewritten.
 
+//@ edition: 2015
 //@ run-rustfix
 //@ check-pass
 
diff --git a/tests/ui/rust-2018/try-macro.rs b/tests/ui/rust-2018/try-macro.rs
index 99480b2a3ec..fec8eaa1786 100644
--- a/tests/ui/rust-2018/try-macro.rs
+++ b/tests/ui/rust-2018/try-macro.rs
@@ -1,5 +1,6 @@
 // Test that `try!` macros are rewritten.
 
+//@ edition: 2015
 //@ run-rustfix
 //@ check-pass
 
diff --git a/tests/ui/rust-2018/try-macro.stderr b/tests/ui/rust-2018/try-macro.stderr
index 095c755539d..20105e1868f 100644
--- a/tests/ui/rust-2018/try-macro.stderr
+++ b/tests/ui/rust-2018/try-macro.stderr
@@ -1,5 +1,5 @@
 warning: `try` is a keyword in the 2018 edition
-  --> $DIR/try-macro.rs:12:5
+  --> $DIR/try-macro.rs:13:5
    |
 LL |     try!(x);
    |     ^^^ help: you can use a raw identifier to stay compatible: `r#try`
@@ -7,7 +7,7 @@ LL |     try!(x);
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 note: the lint level is defined here
-  --> $DIR/try-macro.rs:6:9
+  --> $DIR/try-macro.rs:7:9
    |
 LL | #![warn(rust_2018_compatibility)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/rustdoc/feature-gate-doc_primitive.rs b/tests/ui/rustdoc/feature-gate-doc_primitive.rs
index 78fcd90752e..dbf92f19378 100644
--- a/tests/ui/rustdoc/feature-gate-doc_primitive.rs
+++ b/tests/ui/rustdoc/feature-gate-doc_primitive.rs
@@ -1,5 +1,7 @@
 #[rustc_doc_primitive = "usize"]
-//~^ ERROR `rustc_doc_primitive` is a rustc internal attribute
+//~^ ERROR use of an internal attribute [E0658]
+//~| NOTE the `#[rustc_doc_primitive]` attribute is an internal implementation detail that will never be stable
+//~| NOTE the `#[rustc_doc_primitive]` attribute is used by the standard library to provide a way to generate documentation for primitive types
 /// Some docs
 mod usize {}
 
diff --git a/tests/ui/rustdoc/feature-gate-doc_primitive.stderr b/tests/ui/rustdoc/feature-gate-doc_primitive.stderr
index e74b1322b25..0b1af78b504 100644
--- a/tests/ui/rustdoc/feature-gate-doc_primitive.stderr
+++ b/tests/ui/rustdoc/feature-gate-doc_primitive.stderr
@@ -1,11 +1,12 @@
-error[E0658]: `rustc_doc_primitive` is a rustc internal attribute
+error[E0658]: use of an internal attribute
   --> $DIR/feature-gate-doc_primitive.rs:1:1
    |
 LL | #[rustc_doc_primitive = "usize"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: the `#[rustc_doc_primitive]` attribute is an internal implementation detail that will never be stable
+   = note: the `#[rustc_doc_primitive]` attribute is used by the standard library to provide a way to generate documentation for primitive types
 
 error: aborting due to 1 previous error
 
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/self/self-shadowing-import.rs b/tests/ui/self/self-shadowing-import.rs
index 85574daad5f..78d04e0713a 100644
--- a/tests/ui/self/self-shadowing-import.rs
+++ b/tests/ui/self/self-shadowing-import.rs
@@ -9,7 +9,7 @@ mod a {
 }
 
 mod c {
-    use a::b::a;
+    use crate::a::b::a;
     pub fn bar() { assert_eq!(a::foo(), 1); }
 }
 
diff --git a/tests/ui/sepcomp/auxiliary/sepcomp_lib.rs b/tests/ui/sepcomp/auxiliary/sepcomp_lib.rs
index 59efb3f790b..a0d91c5dc87 100644
--- a/tests/ui/sepcomp/auxiliary/sepcomp_lib.rs
+++ b/tests/ui/sepcomp/auxiliary/sepcomp_lib.rs
@@ -13,8 +13,8 @@ pub mod b {
 }
 
 pub mod c {
-    use a::one;
-    use b::two;
+    use crate::a::one;
+    use crate::b::two;
     pub fn three() -> usize {
         one() + two()
     }
diff --git a/tests/ui/sepcomp/sepcomp-extern.rs b/tests/ui/sepcomp/sepcomp-extern.rs
index 6acd3a1eede..d0756c5f19a 100644
--- a/tests/ui/sepcomp/sepcomp-extern.rs
+++ b/tests/ui/sepcomp/sepcomp-extern.rs
@@ -16,13 +16,13 @@ fn call1() -> usize {
 
 mod a {
     pub fn call2() -> usize {
-        unsafe { ::foo() }
+        unsafe { crate::foo() }
     }
 }
 
 mod b {
     pub fn call3() -> usize {
-        unsafe { ::foo() }
+        unsafe { crate::foo() }
     }
 }
 
diff --git a/tests/ui/sepcomp/sepcomp-fns-backwards.rs b/tests/ui/sepcomp/sepcomp-fns-backwards.rs
index 35326d19d6e..c671771babb 100644
--- a/tests/ui/sepcomp/sepcomp-fns-backwards.rs
+++ b/tests/ui/sepcomp/sepcomp-fns-backwards.rs
@@ -12,13 +12,13 @@ fn pad() -> usize { 0 }
 
 mod b {
     pub fn three() -> usize {
-        ::one() + ::a::two()
+        crate::one() + crate::a::two()
     }
 }
 
 mod a {
     pub fn two() -> usize {
-        ::one() + ::one()
+        crate::one() + crate::one()
     }
 }
 
diff --git a/tests/ui/sepcomp/sepcomp-fns.rs b/tests/ui/sepcomp/sepcomp-fns.rs
index 399193e69b6..1486a2471b8 100644
--- a/tests/ui/sepcomp/sepcomp-fns.rs
+++ b/tests/ui/sepcomp/sepcomp-fns.rs
@@ -13,13 +13,13 @@ fn one() -> usize { 1 }
 
 mod a {
     pub fn two() -> usize {
-        ::one() + ::one()
+        crate::one() + crate::one()
     }
 }
 
 mod b {
     pub fn three() -> usize {
-        ::one() + ::a::two()
+        crate::one() + crate::a::two()
     }
 }
 
diff --git a/tests/ui/sepcomp/sepcomp-statics.rs b/tests/ui/sepcomp/sepcomp-statics.rs
index 580bb628da6..3fe897f3c30 100644
--- a/tests/ui/sepcomp/sepcomp-statics.rs
+++ b/tests/ui/sepcomp/sepcomp-statics.rs
@@ -15,13 +15,13 @@ mod b {
     // that `a` and `b` don't go into the same compilation unit.
     fn pad() -> usize { 0 }
 
-    pub static THREE: usize = ::ONE + ::a::TWO;
+    pub static THREE: usize = crate::ONE + crate::a::TWO;
 }
 
 mod a {
     fn pad() -> usize { 0 }
 
-    pub const TWO: usize = ::ONE + ::ONE;
+    pub const TWO: usize = crate::ONE + crate::ONE;
 }
 
 fn main() {
diff --git a/tests/ui/sepcomp/sepcomp-unwind.rs b/tests/ui/sepcomp/sepcomp-unwind.rs
index 8c25278bb7e..95591676b5e 100644
--- a/tests/ui/sepcomp/sepcomp-unwind.rs
+++ b/tests/ui/sepcomp/sepcomp-unwind.rs
@@ -26,10 +26,10 @@ mod a {
 
 mod b {
     pub fn g() {
-        ::a::f();
+        crate::a::f();
     }
 }
 
 fn main() {
-    thread::spawn(move|| { ::b::g() }).join().unwrap_err();
+    thread::spawn(move|| { b::g() }).join().unwrap_err();
 }
diff --git a/tests/ui/shadowed-use-visibility.rs b/tests/ui/shadowed-use-visibility.rs
index 66181267f98..5ce4103b559 100644
--- a/tests/ui/shadowed-use-visibility.rs
+++ b/tests/ui/shadowed-use-visibility.rs
@@ -5,7 +5,7 @@ mod foo {
     pub fn f() {}
 
     pub use self::f as bar;
-    use foo as bar;
+    use crate::foo as bar;
 }
 
 fn main() {
diff --git a/tests/ui/shadowed/shadowed-trait-methods.rs b/tests/ui/shadowed/shadowed-trait-methods.rs
index f9c25d97913..6cc5159fd08 100644
--- a/tests/ui/shadowed/shadowed-trait-methods.rs
+++ b/tests/ui/shadowed/shadowed-trait-methods.rs
@@ -5,7 +5,7 @@ mod foo {
     impl T for () {}
 }
 
-mod bar { pub use foo::T; }
+mod bar { pub use crate::foo::T; }
 
 fn main() {
     pub use bar::*;
diff --git a/tests/ui/shadowed/shadowed-use-visibility.rs b/tests/ui/shadowed/shadowed-use-visibility.rs
index 6b801972f41..070aeaf1467 100644
--- a/tests/ui/shadowed/shadowed-use-visibility.rs
+++ b/tests/ui/shadowed/shadowed-use-visibility.rs
@@ -1,15 +1,15 @@
 mod foo {
     pub fn f() {}
 
-    use foo as bar;
+    use crate::foo as bar;
     pub use self::f as bar;
 }
 
 mod bar {
-    use foo::bar::f as g; //~ ERROR module import `bar` is private
+    use crate::foo::bar::f as g; //~ ERROR module import `bar` is private
 
-    use foo as f;
-    pub use foo::*;
+    use crate::foo as f;
+    pub use crate::foo::*;
 }
 
 use bar::f::f; //~ ERROR module import `f` is private
diff --git a/tests/ui/shadowed/shadowed-use-visibility.stderr b/tests/ui/shadowed/shadowed-use-visibility.stderr
index 1a642ae6e8e..b062341dc8b 100644
--- a/tests/ui/shadowed/shadowed-use-visibility.stderr
+++ b/tests/ui/shadowed/shadowed-use-visibility.stderr
@@ -1,14 +1,14 @@
 error[E0603]: module import `bar` is private
-  --> $DIR/shadowed-use-visibility.rs:9:14
+  --> $DIR/shadowed-use-visibility.rs:9:21
    |
-LL |     use foo::bar::f as g;
-   |              ^^^ private module import
+LL |     use crate::foo::bar::f as g;
+   |                     ^^^ private module import
    |
 note: the module import `bar` is defined here...
   --> $DIR/shadowed-use-visibility.rs:4:9
    |
-LL |     use foo as bar;
-   |         ^^^^^^^^^^
+LL |     use crate::foo as bar;
+   |         ^^^^^^^^^^^^^^^^^
 note: ...and refers to the module `foo` which is defined here
   --> $DIR/shadowed-use-visibility.rs:1:1
    |
@@ -24,8 +24,8 @@ LL | use bar::f::f;
 note: the module import `f` is defined here...
   --> $DIR/shadowed-use-visibility.rs:11:9
    |
-LL |     use foo as f;
-   |         ^^^^^^^^
+LL |     use crate::foo as f;
+   |         ^^^^^^^^^^^^^^^
 note: ...and refers to the module `foo` which is defined here
   --> $DIR/shadowed-use-visibility.rs:1:1
    |
diff --git a/tests/ui/simd/size-align.rs b/tests/ui/simd/size-align.rs
index ff23ea5980b..53acb686fb8 100644
--- a/tests/ui/simd/size-align.rs
+++ b/tests/ui/simd/size-align.rs
@@ -7,12 +7,12 @@
 
 use std::mem;
 
-/// `T` should satisfy `size_of T (mod min_align_of T) === 0` to be stored at `Vec<T>` properly
+/// `T` should satisfy `size_of T (mod align_of T) === 0` to be stored at `Vec<T>` properly
 /// Please consult the issue #20460
 fn check<T>() {
-    assert_eq!(mem::size_of::<T>() % mem::min_align_of::<T>(), 0);
-    assert_eq!(mem::size_of::<T>() % mem::min_align_of::<T>(), 0);
-    assert_eq!(mem::size_of::<T>() % mem::min_align_of::<T>(), 0);
+    assert_eq!(mem::size_of::<T>() % mem::align_of::<T>(), 0);
+    assert_eq!(mem::size_of::<T>() % mem::align_of::<T>(), 0);
+    assert_eq!(mem::size_of::<T>() % mem::align_of::<T>(), 0);
 }
 
 #[repr(simd)]
diff --git a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs
index 66a432be357..baa664d5933 100644
--- a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs
+++ b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs
@@ -1,3 +1,5 @@
+//@ edition: 2015
+
 #![warn(rust_2021_incompatible_closure_captures)]
 
 fn main() {}
diff --git a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr
index 5ecbedf1867..00b9a81b27d 100644
--- a/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr
+++ b/tests/ui/span/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.stderr
@@ -1,5 +1,5 @@
 error[E0670]: `async fn` is not permitted in Rust 2015
-  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:8:16
+  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:10:16
    |
 LL |     pub(crate) async fn new(
    |                ^^^^^ to use `async fn`, switch to Rust 2018 or later
@@ -8,7 +8,7 @@ LL |     pub(crate) async fn new(
    = note: for more on editions, read https://doc.rust-lang.org/edition-guide
 
 error[E0412]: cannot find type `Duration` in this scope
-  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:10:19
+  --> $DIR/drop-location-span-error-rust-2021-incompatible-closure-captures-96258.rs:12:19
    |
 LL |         interval: Duration,
    |                   ^^^^^^^^ not found in this scope
diff --git a/tests/ui/span/dropck_arr_cycle_checked.rs b/tests/ui/span/dropck_arr_cycle_checked.rs
index a14db5ff089..adecb3f5942 100644
--- a/tests/ui/span/dropck_arr_cycle_checked.rs
+++ b/tests/ui/span/dropck_arr_cycle_checked.rs
@@ -19,7 +19,7 @@ mod s {
 }
 
 mod id {
-    use s;
+    use crate::s;
     #[derive(Debug)]
     pub struct Id {
         orig_count: usize,
diff --git a/tests/ui/span/dropck_vec_cycle_checked.rs b/tests/ui/span/dropck_vec_cycle_checked.rs
index c5d21507d76..b015131caf1 100644
--- a/tests/ui/span/dropck_vec_cycle_checked.rs
+++ b/tests/ui/span/dropck_vec_cycle_checked.rs
@@ -16,7 +16,7 @@ mod s {
 }
 
 mod id {
-    use s;
+    use crate::s;
     #[derive(Debug)]
     pub struct Id {
         orig_count: usize,
diff --git a/tests/ui/span/vec-must-not-hide-type-from-dropck.rs b/tests/ui/span/vec-must-not-hide-type-from-dropck.rs
index 9bfbfab06a0..972ffef2e3c 100644
--- a/tests/ui/span/vec-must-not-hide-type-from-dropck.rs
+++ b/tests/ui/span/vec-must-not-hide-type-from-dropck.rs
@@ -31,7 +31,7 @@ mod s {
 }
 
 mod id {
-    use s;
+    use crate::s;
 
     /// Id represents a globally unique identifier (global across the
     /// current process, that is). When dropped, it automatically
diff --git a/tests/ui/span/visibility-ty-params.rs b/tests/ui/span/visibility-ty-params.rs
index 11c2cf44cb4..05d93e54636 100644
--- a/tests/ui/span/visibility-ty-params.rs
+++ b/tests/ui/span/visibility-ty-params.rs
@@ -3,11 +3,11 @@ macro_rules! m {
 }
 
 struct S<T>(T);
-m!{ S<u8> } //~ ERROR unexpected generic arguments in path
-            //~| ERROR failed to resolve: `S` is a struct, not a module [E0433]
+m!{ crate::S<u8> } //~ ERROR unexpected generic arguments in path
+                   //~| ERROR failed to resolve: `S` is a struct, not a module [E0433]
 
 mod m {
-    m!{ m<> } //~ ERROR unexpected generic arguments in path
+    m!{ crate::m<> } //~ ERROR unexpected generic arguments in path
 }
 
 fn main() {}
diff --git a/tests/ui/span/visibility-ty-params.stderr b/tests/ui/span/visibility-ty-params.stderr
index 97d05c4644e..7b02d79a1bc 100644
--- a/tests/ui/span/visibility-ty-params.stderr
+++ b/tests/ui/span/visibility-ty-params.stderr
@@ -1,20 +1,20 @@
 error: unexpected generic arguments in path
-  --> $DIR/visibility-ty-params.rs:6:6
+  --> $DIR/visibility-ty-params.rs:6:13
    |
-LL | m!{ S<u8> }
-   |      ^^^^
+LL | m!{ crate::S<u8> }
+   |             ^^^^
 
 error[E0433]: failed to resolve: `S` is a struct, not a module
-  --> $DIR/visibility-ty-params.rs:6:5
+  --> $DIR/visibility-ty-params.rs:6:12
    |
-LL | m!{ S<u8> }
-   |     ^ `S` is a struct, not a module
+LL | m!{ crate::S<u8> }
+   |            ^ `S` is a struct, not a module
 
 error: unexpected generic arguments in path
-  --> $DIR/visibility-ty-params.rs:10:10
+  --> $DIR/visibility-ty-params.rs:10:17
    |
-LL |     m!{ m<> }
-   |          ^^
+LL |     m!{ crate::m<> }
+   |                 ^^
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/auxiliary/pub-and-stability.rs b/tests/ui/stability-attribute/auxiliary/pub-and-stability.rs
index 8866233b61e..8866233b61e 100644
--- a/tests/ui/auxiliary/pub-and-stability.rs
+++ b/tests/ui/stability-attribute/auxiliary/pub-and-stability.rs
diff --git a/tests/ui/stability-attribute/renamed_feature.rs b/tests/ui/stability-attribute/renamed_feature.rs
new file mode 100644
index 00000000000..249c2abecff
--- /dev/null
+++ b/tests/ui/stability-attribute/renamed_feature.rs
@@ -0,0 +1,3 @@
+#![feature(try_trait)] //~ ERROR feature `try_trait` has been renamed to `try_trait_v2` [E0635]
+
+fn main() {}
diff --git a/tests/ui/stability-attribute/renamed_feature.stderr b/tests/ui/stability-attribute/renamed_feature.stderr
new file mode 100644
index 00000000000..293a2feffb2
--- /dev/null
+++ b/tests/ui/stability-attribute/renamed_feature.stderr
@@ -0,0 +1,9 @@
+error[E0635]: feature `try_trait` has been renamed to `try_trait_v2`
+  --> $DIR/renamed_feature.rs:1:12
+   |
+LL | #![feature(try_trait)]
+   |            ^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0635`.
diff --git a/tests/ui/explore-issue-38412.rs b/tests/ui/stability-attribute/stability-privacy-interaction.rs
index 2008b120faa..e02816ae1e7 100644
--- a/tests/ui/explore-issue-38412.rs
+++ b/tests/ui/stability-attribute/stability-privacy-interaction.rs
@@ -1,28 +1,39 @@
+//! Regression test for issue #38412: interaction between stability attributes and privacy
+//!
+//! Tests that the compiler correctly handles the interaction between feature gates
+//! and privacy/visibility rules. Specifically verifies that enabled unstable features
+//! are accessible while disabled ones are properly rejected.
+
 //@ aux-build:pub-and-stability.rs
 
-// A big point of this test is that we *enable* `unstable_declared`,
-// but do *not* enable `unstable_undeclared`. This way we can check
-// that the compiler is letting in uses of enabled feature-gated
-// stuff but still rejecting uses of disabled feature-gated stuff.
+// Enable `unstable_declared` but not `unstable_undeclared` to test
+// that the compiler allows enabled features but rejects disabled ones
 #![feature(unstable_declared)]
 
 extern crate pub_and_stability;
 use pub_and_stability::{Record, Trait, Tuple};
 
 fn main() {
-    // Okay
+    // Test struct field access patterns
     let Record { .. } = Record::new();
 
-    // Okay
-    let Record { a_stable_pub: _, a_unstable_declared_pub: _, .. } = Record::new();
+    let Record {
+        a_stable_pub: _,
+        a_unstable_declared_pub: _,
+        ..
+    } = Record::new();
 
-    let Record { a_stable_pub: _, a_unstable_declared_pub: _, a_unstable_undeclared_pub: _, .. } =
-        Record::new();
-    //~^^ ERROR use of unstable library feature `unstable_undeclared`
+    let Record {
+        a_stable_pub: _,
+        a_unstable_declared_pub: _,
+        a_unstable_undeclared_pub: _,  //~ ERROR use of unstable library feature `unstable_undeclared`
+        ..
+    } = Record::new();
 
     let r = Record::new();
     let t = Tuple::new();
 
+    // Test field access with different stability/privacy combinations
     r.a_stable_pub;
     r.a_unstable_declared_pub;
     r.a_unstable_undeclared_pub; //~ ERROR use of unstable library feature
@@ -37,10 +48,12 @@ fn main() {
     t.4;                         //~ ERROR is private
     t.5;                         //~ ERROR is private
 
+    // Test trait method access
     r.stable_trait_method();
     r.unstable_declared_trait_method();
     r.unstable_undeclared_trait_method(); //~ ERROR use of unstable library feature
 
+    // Test inherent method access
     r.stable();
     r.unstable_declared();
     r.unstable_undeclared();              //~ ERROR use of unstable library feature
@@ -49,6 +62,7 @@ fn main() {
     r.pub_mod();                          //~ ERROR `pub_mod` is private
     r.private();                          //~ ERROR `private` is private
 
+    // Repeat tests for tuple struct
     let t = Tuple::new();
     t.stable_trait_method();
     t.unstable_declared_trait_method();
diff --git a/tests/ui/explore-issue-38412.stderr b/tests/ui/stability-attribute/stability-privacy-interaction.stderr
index fca5c738d27..991b3dbe019 100644
--- a/tests/ui/explore-issue-38412.stderr
+++ b/tests/ui/stability-attribute/stability-privacy-interaction.stderr
@@ -1,15 +1,15 @@
 error[E0658]: use of unstable library feature `unstable_undeclared`
-  --> $DIR/explore-issue-38412.rs:19:63
+  --> $DIR/stability-privacy-interaction.rs:29:9
    |
-LL |     let Record { a_stable_pub: _, a_unstable_declared_pub: _, a_unstable_undeclared_pub: _, .. } =
-   |                                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         a_unstable_undeclared_pub: _,
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #38412 <https://github.com/rust-lang/rust/issues/38412> for more information
    = help: add `#![feature(unstable_undeclared)]` 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[E0658]: use of unstable library feature `unstable_undeclared`
-  --> $DIR/explore-issue-38412.rs:28:5
+  --> $DIR/stability-privacy-interaction.rs:39:5
    |
 LL |     r.a_unstable_undeclared_pub;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -19,25 +19,25 @@ LL |     r.a_unstable_undeclared_pub;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0616]: field `b_crate` of struct `Record` is private
-  --> $DIR/explore-issue-38412.rs:29:7
+  --> $DIR/stability-privacy-interaction.rs:40:7
    |
 LL |     r.b_crate;
    |       ^^^^^^^ private field
 
 error[E0616]: field `c_mod` of struct `Record` is private
-  --> $DIR/explore-issue-38412.rs:30:7
+  --> $DIR/stability-privacy-interaction.rs:41:7
    |
 LL |     r.c_mod;
    |       ^^^^^ private field
 
 error[E0616]: field `d_priv` of struct `Record` is private
-  --> $DIR/explore-issue-38412.rs:31:7
+  --> $DIR/stability-privacy-interaction.rs:42:7
    |
 LL |     r.d_priv;
    |       ^^^^^^ private field
 
 error[E0658]: use of unstable library feature `unstable_undeclared`
-  --> $DIR/explore-issue-38412.rs:35:5
+  --> $DIR/stability-privacy-interaction.rs:46:5
    |
 LL |     t.2;
    |     ^^^
@@ -47,25 +47,25 @@ LL |     t.2;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0616]: field `3` of struct `pub_and_stability::Tuple` is private
-  --> $DIR/explore-issue-38412.rs:36:7
+  --> $DIR/stability-privacy-interaction.rs:47:7
    |
 LL |     t.3;
    |       ^ private field
 
 error[E0616]: field `4` of struct `pub_and_stability::Tuple` is private
-  --> $DIR/explore-issue-38412.rs:37:7
+  --> $DIR/stability-privacy-interaction.rs:48:7
    |
 LL |     t.4;
    |       ^ private field
 
 error[E0616]: field `5` of struct `pub_and_stability::Tuple` is private
-  --> $DIR/explore-issue-38412.rs:38:7
+  --> $DIR/stability-privacy-interaction.rs:49:7
    |
 LL |     t.5;
    |       ^ private field
 
 error[E0658]: use of unstable library feature `unstable_undeclared`
-  --> $DIR/explore-issue-38412.rs:42:7
+  --> $DIR/stability-privacy-interaction.rs:54:7
    |
 LL |     r.unstable_undeclared_trait_method();
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -75,7 +75,7 @@ LL |     r.unstable_undeclared_trait_method();
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: use of unstable library feature `unstable_undeclared`
-  --> $DIR/explore-issue-38412.rs:46:7
+  --> $DIR/stability-privacy-interaction.rs:59:7
    |
 LL |     r.unstable_undeclared();
    |       ^^^^^^^^^^^^^^^^^^^
@@ -85,7 +85,7 @@ LL |     r.unstable_undeclared();
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0624]: method `pub_crate` is private
-  --> $DIR/explore-issue-38412.rs:48:7
+  --> $DIR/stability-privacy-interaction.rs:61:7
    |
 LL |     r.pub_crate();
    |       ^^^^^^^^^ private method
@@ -96,7 +96,7 @@ LL |         pub(crate) fn pub_crate(&self) -> i32 { self.d_priv }
    |         ------------------------------------- private method defined here
 
 error[E0624]: method `pub_mod` is private
-  --> $DIR/explore-issue-38412.rs:49:7
+  --> $DIR/stability-privacy-interaction.rs:62:7
    |
 LL |     r.pub_mod();
    |       ^^^^^^^ private method
@@ -107,7 +107,7 @@ LL |         pub(in crate::m) fn pub_mod(&self) -> i32 { self.d_priv }
    |         ----------------------------------------- private method defined here
 
 error[E0624]: method `private` is private
-  --> $DIR/explore-issue-38412.rs:50:7
+  --> $DIR/stability-privacy-interaction.rs:63:7
    |
 LL |     r.private();
    |       ^^^^^^^ private method
@@ -118,7 +118,7 @@ LL |         fn private(&self) -> i32 { self.d_priv }
    |         ------------------------ private method defined here
 
 error[E0658]: use of unstable library feature `unstable_undeclared`
-  --> $DIR/explore-issue-38412.rs:55:7
+  --> $DIR/stability-privacy-interaction.rs:69:7
    |
 LL |     t.unstable_undeclared_trait_method();
    |       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -128,7 +128,7 @@ LL |     t.unstable_undeclared_trait_method();
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: use of unstable library feature `unstable_undeclared`
-  --> $DIR/explore-issue-38412.rs:59:7
+  --> $DIR/stability-privacy-interaction.rs:73:7
    |
 LL |     t.unstable_undeclared();
    |       ^^^^^^^^^^^^^^^^^^^
@@ -138,7 +138,7 @@ LL |     t.unstable_undeclared();
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0624]: method `pub_crate` is private
-  --> $DIR/explore-issue-38412.rs:61:7
+  --> $DIR/stability-privacy-interaction.rs:75:7
    |
 LL |     t.pub_crate();
    |       ^^^^^^^^^ private method
@@ -149,7 +149,7 @@ LL |         pub(crate) fn pub_crate(&self) -> i32 { self.0 }
    |         ------------------------------------- private method defined here
 
 error[E0624]: method `pub_mod` is private
-  --> $DIR/explore-issue-38412.rs:62:7
+  --> $DIR/stability-privacy-interaction.rs:76:7
    |
 LL |     t.pub_mod();
    |       ^^^^^^^ private method
@@ -160,7 +160,7 @@ LL |         pub(in crate::m) fn pub_mod(&self) -> i32 { self.0 }
    |         ----------------------------------------- private method defined here
 
 error[E0624]: method `private` is private
-  --> $DIR/explore-issue-38412.rs:63:7
+  --> $DIR/stability-privacy-interaction.rs:77:7
    |
 LL |     t.private();
    |       ^^^^^^^ private method
diff --git a/tests/ui/static/auxiliary/static_priv_by_default.rs b/tests/ui/static/auxiliary/static_priv_by_default.rs
index 39f912066ec..fe9aef42feb 100644
--- a/tests/ui/static/auxiliary/static_priv_by_default.rs
+++ b/tests/ui/static/auxiliary/static_priv_by_default.rs
@@ -31,11 +31,11 @@ mod foo {
 }
 
 pub mod bar {
-    pub use foo::reexported_a as e;
-    pub use foo::reexported_b as f;
-    pub use foo::reexported_c as g;
-    pub use foo::reexported_d as h;
-    pub use foo::reexported_e as i;
+    pub use crate::foo::reexported_a as e;
+    pub use crate::foo::reexported_b as f;
+    pub use crate::foo::reexported_c as g;
+    pub use crate::foo::reexported_d as h;
+    pub use crate::foo::reexported_e as i;
 }
 
 pub static a: isize = 0;
diff --git a/tests/ui/static/static-extern-type.rs b/tests/ui/static/static-extern-type.rs
index 8b022a5c31c..2597c22ed7e 100644
--- a/tests/ui/static/static-extern-type.rs
+++ b/tests/ui/static/static-extern-type.rs
@@ -10,7 +10,7 @@ pub mod a {
 
 pub mod b {
     #[repr(transparent)]
-    pub struct TransparentType(::a::StartFn);
+    pub struct TransparentType(crate::a::StartFn);
     extern "C" {
         pub static start: TransparentType;
     }
@@ -18,7 +18,7 @@ pub mod b {
 
 pub mod c {
     #[repr(C)]
-    pub struct CType(u32, ::b::TransparentType);
+    pub struct CType(u32, crate::b::TransparentType);
     extern "C" {
         pub static start: CType;
     }
diff --git a/tests/ui/statics/auxiliary/static_fn_inline_xc_aux.rs b/tests/ui/statics/auxiliary/static_fn_inline_xc_aux.rs
index 8d0f7f61ced..a739e8f2dbe 100644
--- a/tests/ui/statics/auxiliary/static_fn_inline_xc_aux.rs
+++ b/tests/ui/statics/auxiliary/static_fn_inline_xc_aux.rs
@@ -5,7 +5,7 @@ pub mod num {
 }
 
 pub mod f64 {
-    impl ::num::Num2 for f64 {
+    impl crate::num::Num2 for f64 {
         #[inline]
         fn from_int2(n: isize) -> f64 { return n as f64;  }
     }
diff --git a/tests/ui/statics/auxiliary/static_fn_trait_xc_aux.rs b/tests/ui/statics/auxiliary/static_fn_trait_xc_aux.rs
index b8aed2c5f54..ab73bac3bf8 100644
--- a/tests/ui/statics/auxiliary/static_fn_trait_xc_aux.rs
+++ b/tests/ui/statics/auxiliary/static_fn_trait_xc_aux.rs
@@ -5,7 +5,7 @@ pub mod num {
 }
 
 pub mod f64 {
-    impl ::num::Num2 for f64 {
+    impl crate::num::Num2 for f64 {
         fn from_int2(n: isize) -> f64 { return n as f64;  }
     }
 }
diff --git a/tests/ui/statics/static-impl.rs b/tests/ui/statics/static-impl.rs
index 37f3cd13133..5c8d20da0c6 100644
--- a/tests/ui/statics/static-impl.rs
+++ b/tests/ui/statics/static-impl.rs
@@ -9,12 +9,12 @@ pub trait plus {
 }
 
 mod a {
-    use plus;
+    use crate::plus;
     impl plus for usize { fn plus(&self) -> isize { *self as isize + 20 } }
 }
 
 mod b {
-    use plus;
+    use crate::plus;
     impl plus for String { fn plus(&self) -> isize { 200 } }
 }
 
diff --git a/tests/ui/stats/auxiliary/include.rs b/tests/ui/stats/auxiliary/include.rs
new file mode 100644
index 00000000000..7fb7c781137
--- /dev/null
+++ b/tests/ui/stats/auxiliary/include.rs
@@ -0,0 +1,3 @@
+fn zzz(x: u32) -> u32 {
+    x
+}
diff --git a/tests/ui/stats/input-stats.stderr b/tests/ui/stats/input-stats.stderr
index f2598bd7eaf..88f91bef30b 100644
--- a/tests/ui/stats/input-stats.stderr
+++ b/tests/ui/stats/input-stats.stderr
@@ -82,10 +82,10 @@ hir-stats - Expr                      32 (NN.N%)             1
 hir-stats - Let                       32 (NN.N%)             1
 hir-stats - Semi                      32 (NN.N%)             1
 hir-stats FnDecl                   120 (NN.N%)             3            40
-hir-stats Attribute                128 (NN.N%)             4            32
 hir-stats FieldDef                 128 (NN.N%)             2            64
 hir-stats GenericArgs              144 (NN.N%)             3            48
 hir-stats Variant                  144 (NN.N%)             2            72
+hir-stats Attribute                160 (NN.N%)             4            40
 hir-stats GenericBound             256 (NN.N%)             4            64
 hir-stats - Trait                    256 (NN.N%)             4
 hir-stats Block                    288 (NN.N%)             6            48
@@ -117,5 +117,5 @@ hir-stats - Use                      352 (NN.N%)             4
 hir-stats Path                   1_040 (NN.N%)            26            40
 hir-stats PathSegment            1_776 (NN.N%)            37            48
 hir-stats ----------------------------------------------------------------
-hir-stats Total                  8_644                   172
+hir-stats Total                  8_676                   172
 hir-stats
diff --git a/tests/ui/stats/macro-stats.rs b/tests/ui/stats/macro-stats.rs
new file mode 100644
index 00000000000..ee265d682fd
--- /dev/null
+++ b/tests/ui/stats/macro-stats.rs
@@ -0,0 +1,130 @@
+//@ check-pass
+//@ compile-flags: -Zmacro-stats
+
+#[test]
+fn test_foo() {
+    let what = "this";
+    let how = "completely";
+    let when = "immediately";
+    println!("{what} disappears {how} and {when}");
+}
+
+#[rustfmt::skip] // non-macro attr, ignored by `-Zmacro-stats`
+fn rustfmt_skip() {
+    // Nothing to see here.
+}
+
+#[derive(Default, Clone, Copy, Hash)]
+enum E1 {
+    #[default] // non-macro attr, ignored by `-Zmacro-stats`
+    A,
+    B,
+}
+
+#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+struct E2 {
+    a: u32,
+    b: String,
+    c: Vec<bool>,
+}
+
+#[derive(Clone)] struct S0;
+#[derive(Clone)] struct S1(u32);
+#[derive(Clone)] struct S2(u32, u32);
+#[derive(Clone)] struct S3(u32, u32, u32);
+#[derive(Clone)] struct S4(u32, u32, u32, u32);
+#[derive(Clone)] struct S5(u32, u32, u32, u32, u32);
+
+macro_rules! u32 {
+    () => { u32 }
+}
+
+macro_rules! none {
+    () => { None }
+}
+fn opt(x: Option<u32>) {
+    match x {
+        Some(_) => {}
+        none!() => {}           // AstFragmentKind::Pat
+    }
+}
+
+macro_rules! this_is_a_really_really_long_macro_name {
+    ($t:ty) => {
+        fn f(_: $t) {}
+    }
+}
+this_is_a_really_really_long_macro_name!(u32!()); // AstFragmentKind::{Items,Ty}
+
+macro_rules! trait_tys {
+    () => {
+        type A;
+        type B;
+    }
+}
+trait Tr {
+    trait_tys!();               // AstFragmentKind::TraitItems
+}
+
+macro_rules! impl_const { () => { const X: u32 = 0; } }
+struct U;
+impl U {
+    impl_const!();              // AstFragmentKind::ImplItems
+}
+
+macro_rules! trait_impl_tys {
+    () => {
+        type A = u32;
+        type B = bool;
+    }
+}
+struct Tr1;
+impl Tr for Tr1 {
+    trait_impl_tys!();          // AstFragment::TraitImplItems
+}
+
+macro_rules! foreign_item {
+    () => { fn fc(a: u32) -> u32; }
+}
+extern "C" {
+    foreign_item!();            // AstFragment::ForeignItems
+}
+
+// Include macros are ignored by `-Zmacro-stats`.
+mod includes {
+    mod z1 {
+        include!("auxiliary/include.rs");
+    }
+    mod z2 {
+        std::include!("auxiliary/include.rs");
+    }
+
+    const B1: &[u8] = include_bytes!("auxiliary/include.rs");
+    const B2: &[u8] = std::include_bytes!("auxiliary/include.rs");
+
+    const S1: &str = include_str!("auxiliary/include.rs");
+    const S2: &str = std::include_str!("auxiliary/include.rs");
+}
+
+fn main() {
+    macro_rules! n99 {
+        () => { 99 }
+    }
+    let x = n99!() + n99!();    // AstFragmentKind::Expr
+
+    macro_rules! p {
+        () => {
+            // blah
+            let x = 1;
+            let y = x;
+            let _ = y;
+        }
+    }
+    p!();                       // AstFragmentKind::Stmts
+
+    macro_rules! q {
+        () => {};
+        ($($x:ident),*) => { $( let $x: u32 = 12345; )* };
+    }
+    q!(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z);
+}
diff --git a/tests/ui/stats/macro-stats.stderr b/tests/ui/stats/macro-stats.stderr
new file mode 100644
index 00000000000..f87e34622b9
--- /dev/null
+++ b/tests/ui/stats/macro-stats.stderr
@@ -0,0 +1,26 @@
+macro-stats ===================================================================================
+macro-stats MACRO EXPANSION STATS: macro_stats
+macro-stats Macro Name                         Uses      Lines  Avg Lines      Bytes  Avg Bytes
+macro-stats -----------------------------------------------------------------------------------
+macro-stats #[derive(Clone)]                      8         56        7.0      1_660      207.5
+macro-stats #[derive(PartialOrd)]                 1         16       16.0        654      654.0
+macro-stats #[derive(Hash)]                       2         15        7.5        547      273.5
+macro-stats #[derive(Ord)]                        1         14       14.0        489      489.0
+macro-stats q!                                    1         24       24.0        435      435.0
+macro-stats #[derive(Default)]                    2         14        7.0        367      183.5
+macro-stats #[derive(Eq)]                         1         10       10.0        312      312.0
+macro-stats #[derive(Debug)]                      1          7        7.0        261      261.0
+macro-stats #[derive(PartialEq)]                  1          8        8.0        247      247.0
+macro-stats #[derive(Copy)]                       1          1        1.0         46       46.0
+macro-stats p!                                    1          2        2.0         28       28.0
+macro-stats trait_impl_tys!                       1          1        1.0         11       11.0
+macro-stats foreign_item!                         1          0        0.0          6        6.0
+macro-stats impl_const!                           1          0        0.0          4        4.0
+macro-stats trait_tys!                            1          1        1.0          3        3.0
+macro-stats u32!                                  1          0        0.0         -3       -3.0
+macro-stats none!                                 1          0        0.0         -3       -3.0
+macro-stats n99!                                  2          0        0.0         -8       -4.0
+macro-stats this_is_a_really_really_long_macro_name!
+macro-stats                                       1          0        0.0        -30      -30.0
+macro-stats #[test]                               1         -6       -6.0       -158     -158.0
+macro-stats ===================================================================================
diff --git a/tests/ui/structs-enums/enum-alignment.rs b/tests/ui/structs-enums/enum-alignment.rs
index bb779b1e0cd..95f14e521b5 100644
--- a/tests/ui/structs-enums/enum-alignment.rs
+++ b/tests/ui/structs-enums/enum-alignment.rs
@@ -11,7 +11,7 @@ fn addr_of<T>(ptr: &T) -> usize {
 fn is_aligned<T>(ptr: &T) -> bool {
     unsafe {
         let addr: usize = mem::transmute(ptr);
-        (addr % mem::min_align_of::<T>()) == 0
+        (addr % mem::align_of::<T>()) == 0
     }
 }
 
diff --git a/tests/ui/structs-enums/issue-2718-a.rs b/tests/ui/structs-enums/issue-2718-a.rs
index 6c491584540..f799a82447f 100644
--- a/tests/ui/structs-enums/issue-2718-a.rs
+++ b/tests/ui/structs-enums/issue-2718-a.rs
@@ -3,7 +3,7 @@ pub struct SendPacket<T> {
 }
 
 mod pingpong {
-    use SendPacket;
+    use crate::SendPacket;
     pub type Ping = SendPacket<Pong>;
     pub struct Pong(SendPacket<Ping>);
     //~^ ERROR recursive type `Pong` has infinite size
diff --git a/tests/ui/structs-enums/namespaced-enum-glob-import.rs b/tests/ui/structs-enums/namespaced-enum-glob-import.rs
index e8a709d5bd0..82742a934c4 100644
--- a/tests/ui/structs-enums/namespaced-enum-glob-import.rs
+++ b/tests/ui/structs-enums/namespaced-enum-glob-import.rs
@@ -14,7 +14,7 @@ mod m2 {
 }
 
 mod m {
-    pub use m2::Foo::*;
+    pub use crate::m2::Foo::*;
 }
 
 fn _f(f: m2::Foo) {
diff --git a/tests/ui/structs-enums/rec-align-u32.rs b/tests/ui/structs-enums/rec-align-u32.rs
index 44879189739..b18cd11198e 100644
--- a/tests/ui/structs-enums/rec-align-u32.rs
+++ b/tests/ui/structs-enums/rec-align-u32.rs
@@ -34,12 +34,12 @@ pub fn main() {
         // Send it through the shape code
         let y = format!("{:?}", x);
 
-        println!("align inner = {:?}", intrinsics::min_align_of::<Inner>());
+        println!("align inner = {:?}", intrinsics::align_of::<Inner>());
         println!("size outer = {:?}", mem::size_of::<Outer>());
         println!("y = {:?}", y);
 
         // per clang/gcc the alignment of `inner` is 4 on x86.
-        assert_eq!(intrinsics::min_align_of::<Inner>(), m::align());
+        assert_eq!(intrinsics::align_of::<Inner>(), m::align());
 
         // per clang/gcc the size of `outer` should be 12
         // because `inner`s alignment was 4.
diff --git a/tests/ui/structs-enums/rec-align-u64.rs b/tests/ui/structs-enums/rec-align-u64.rs
index 0f7bb6b3505..df219892d73 100644
--- a/tests/ui/structs-enums/rec-align-u64.rs
+++ b/tests/ui/structs-enums/rec-align-u64.rs
@@ -84,12 +84,12 @@ pub fn main() {
 
         let y = format!("{:?}", x);
 
-        println!("align inner = {:?}", intrinsics::min_align_of::<Inner>());
+        println!("align inner = {:?}", intrinsics::align_of::<Inner>());
         println!("size outer = {:?}", mem::size_of::<Outer>());
         println!("y = {:?}", y);
 
         // per clang/gcc the alignment of `Inner` is 4 on x86.
-        assert_eq!(intrinsics::min_align_of::<Inner>(), m::m::align());
+        assert_eq!(intrinsics::align_of::<Inner>(), m::m::align());
 
         // per clang/gcc the size of `Outer` should be 12
         // because `Inner`s alignment was 4.
diff --git a/tests/ui/structs-enums/tag-align-dyn-u64.rs b/tests/ui/structs-enums/tag-align-dyn-u64.rs
index 5e7d918b4fb..5a4f0878c53 100644
--- a/tests/ui/structs-enums/tag-align-dyn-u64.rs
+++ b/tests/ui/structs-enums/tag-align-dyn-u64.rs
@@ -19,7 +19,7 @@ fn mk_rec() -> Rec {
 
 fn is_u64_aligned(u: &Tag<u64>) -> bool {
     let p: usize = unsafe { mem::transmute(u) };
-    let u64_align = std::mem::min_align_of::<u64>();
+    let u64_align = std::mem::align_of::<u64>();
     return (p & (u64_align - 1)) == 0;
 }
 
diff --git a/tests/ui/structs-enums/tag-align-dyn-variants.rs b/tests/ui/structs-enums/tag-align-dyn-variants.rs
index c0574f3354e..019f1a82895 100644
--- a/tests/ui/structs-enums/tag-align-dyn-variants.rs
+++ b/tests/ui/structs-enums/tag-align-dyn-variants.rs
@@ -34,7 +34,7 @@ fn variant_data_is_aligned<A,B>(amnt: usize, u: &Tag<A,B>) -> bool {
 }
 
 pub fn main() {
-    let u64_align = std::mem::min_align_of::<u64>();
+    let u64_align = std::mem::align_of::<u64>();
     let x = mk_rec(22u64, 23u64);
     assert!(is_aligned(u64_align, &x.tA));
     assert!(variant_data_is_aligned(u64_align, &x.tA));
diff --git a/tests/ui/structs-enums/tag-align-u64.rs b/tests/ui/structs-enums/tag-align-u64.rs
index 8ab9f242822..e274cc0e157 100644
--- a/tests/ui/structs-enums/tag-align-u64.rs
+++ b/tests/ui/structs-enums/tag-align-u64.rs
@@ -19,7 +19,7 @@ fn mk_rec() -> Rec {
 
 fn is_u64_aligned(u: &Tag) -> bool {
     let p: usize = unsafe { mem::transmute(u) };
-    let u64_align = std::mem::min_align_of::<u64>();
+    let u64_align = std::mem::align_of::<u64>();
     return (p & (u64_align - 1)) == 0;
 }
 
diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs
index 2893bbc8b71..63fe5ebaea4 100644
--- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs
+++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs
@@ -1,16 +1,15 @@
-#![allow(bare_trait_objects)]
 trait A: Sized {
-    fn f(a: A) -> A;
+    fn f(a: dyn A) -> dyn A;
     //~^ ERROR associated item referring to unboxed trait object for its own trait
     //~| ERROR the trait `A` is not dyn compatible
 }
 trait B {
-    fn f(a: B) -> B;
+    fn f(a: dyn B) -> dyn B;
     //~^ ERROR associated item referring to unboxed trait object for its own trait
     //~| ERROR the trait `B` is not dyn compatible
 }
 trait C {
-    fn f(&self, a: C) -> C;
+    fn f(&self, a: dyn C) -> dyn C;
 }
 
 fn main() {}
diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr
index f4b669d7fcd..e8384afed7a 100644
--- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr
+++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr
@@ -1,26 +1,26 @@
 error: associated item referring to unboxed trait object for its own trait
-  --> $DIR/dyn-incompatible-trait-should-use-self.rs:3:13
+  --> $DIR/dyn-incompatible-trait-should-use-self.rs:2:13
    |
 LL | trait A: Sized {
    |       - in this trait
-LL |     fn f(a: A) -> A;
-   |             ^     ^
+LL |     fn f(a: dyn A) -> dyn A;
+   |             ^^^^^     ^^^^^
    |
 help: you might have meant to use `Self` to refer to the implementing type
    |
-LL -     fn f(a: A) -> A;
+LL -     fn f(a: dyn A) -> dyn A;
 LL +     fn f(a: Self) -> Self;
    |
 
 error[E0038]: the trait `A` is not dyn compatible
-  --> $DIR/dyn-incompatible-trait-should-use-self.rs:3:13
+  --> $DIR/dyn-incompatible-trait-should-use-self.rs:2:13
    |
-LL |     fn f(a: A) -> A;
-   |             ^ `A` is not dyn compatible
+LL |     fn f(a: dyn A) -> dyn A;
+   |             ^^^^^ `A` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
       for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/dyn-incompatible-trait-should-use-self.rs:2:10
+  --> $DIR/dyn-incompatible-trait-should-use-self.rs:1:10
    |
 LL | trait A: Sized {
    |       -  ^^^^^ ...because it requires `Self: Sized`
@@ -28,41 +28,41 @@ LL | trait A: Sized {
    |       this trait is not dyn compatible...
 
 error: associated item referring to unboxed trait object for its own trait
-  --> $DIR/dyn-incompatible-trait-should-use-self.rs:8:13
+  --> $DIR/dyn-incompatible-trait-should-use-self.rs:7:13
    |
 LL | trait B {
    |       - in this trait
-LL |     fn f(a: B) -> B;
-   |             ^     ^
+LL |     fn f(a: dyn B) -> dyn B;
+   |             ^^^^^     ^^^^^
    |
 help: you might have meant to use `Self` to refer to the implementing type
    |
-LL -     fn f(a: B) -> B;
+LL -     fn f(a: dyn B) -> dyn B;
 LL +     fn f(a: Self) -> Self;
    |
 
 error[E0038]: the trait `B` is not dyn compatible
-  --> $DIR/dyn-incompatible-trait-should-use-self.rs:8:13
+  --> $DIR/dyn-incompatible-trait-should-use-self.rs:7:13
    |
-LL |     fn f(a: B) -> B;
-   |             ^ `B` is not dyn compatible
+LL |     fn f(a: dyn B) -> dyn B;
+   |             ^^^^^ `B` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
       for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/dyn-incompatible-trait-should-use-self.rs:8:8
+  --> $DIR/dyn-incompatible-trait-should-use-self.rs:7:8
    |
 LL | trait B {
    |       - this trait is not dyn compatible...
-LL |     fn f(a: B) -> B;
+LL |     fn f(a: dyn B) -> dyn B;
    |        ^ ...because associated function `f` has no `self` parameter
 help: consider turning `f` into a method by giving it a `&self` argument
    |
-LL |     fn f(&self, a: B) -> B;
+LL |     fn f(&self, a: dyn B) -> dyn B;
    |          ++++++
 help: alternatively, consider constraining `f` so it does not apply to trait objects
    |
-LL |     fn f(a: B) -> B where Self: Sized;
-   |                     +++++++++++++++++
+LL |     fn f(a: dyn B) -> dyn B where Self: Sized;
+   |                             +++++++++++++++++
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.rs b/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.rs
index efa296db47c..d10b3bec543 100644
--- a/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.rs
+++ b/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.rs
@@ -1,4 +1,5 @@
 // Regression test for ICE #125876
+//@ edition: 2015
 
 fn main() {
     std::ptr::from_ref(num).cast_mut().as_deref();
diff --git a/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.stderr b/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.stderr
index f943688e657..696151b6ee2 100644
--- a/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.stderr
+++ b/tests/ui/suggestions/ice-unwrap-probe-many-result-125876.stderr
@@ -1,11 +1,11 @@
 error[E0425]: cannot find value `num` in this scope
-  --> $DIR/ice-unwrap-probe-many-result-125876.rs:4:24
+  --> $DIR/ice-unwrap-probe-many-result-125876.rs:5:24
    |
 LL |     std::ptr::from_ref(num).cast_mut().as_deref();
    |                        ^^^ not found in this scope
 
 warning: type annotations needed
-  --> $DIR/ice-unwrap-probe-many-result-125876.rs:4:29
+  --> $DIR/ice-unwrap-probe-many-result-125876.rs:5:29
    |
 LL |     std::ptr::from_ref(num).cast_mut().as_deref();
    |                             ^^^^^^^^
@@ -15,7 +15,7 @@ LL |     std::ptr::from_ref(num).cast_mut().as_deref();
    = note: `#[warn(tyvar_behind_raw_pointer)]` on by default
 
 warning: type annotations needed
-  --> $DIR/ice-unwrap-probe-many-result-125876.rs:4:40
+  --> $DIR/ice-unwrap-probe-many-result-125876.rs:5:40
    |
 LL |     std::ptr::from_ref(num).cast_mut().as_deref();
    |                                        ^^^^^^^^
@@ -24,7 +24,7 @@ LL |     std::ptr::from_ref(num).cast_mut().as_deref();
    = note: for more information, see issue #46906 <https://github.com/rust-lang/rust/issues/46906>
 
 error[E0599]: no method named `as_deref` found for raw pointer `*mut _` in the current scope
-  --> $DIR/ice-unwrap-probe-many-result-125876.rs:4:40
+  --> $DIR/ice-unwrap-probe-many-result-125876.rs:5:40
    |
 LL |     std::ptr::from_ref(num).cast_mut().as_deref();
    |                                        ^^^^^^^^
diff --git a/tests/ui/suggestions/issue-116434-2015.rs b/tests/ui/suggestions/issue-116434-2015.rs
index 1518765152f..bad9d02321c 100644
--- a/tests/ui/suggestions/issue-116434-2015.rs
+++ b/tests/ui/suggestions/issue-116434-2015.rs
@@ -1,3 +1,5 @@
+//@ edition: 2015
+
 trait Foo {
     type Clone;
     fn foo() -> Clone;
diff --git a/tests/ui/suggestions/issue-116434-2015.stderr b/tests/ui/suggestions/issue-116434-2015.stderr
index 07a254432a2..a0a99cc560d 100644
--- a/tests/ui/suggestions/issue-116434-2015.stderr
+++ b/tests/ui/suggestions/issue-116434-2015.stderr
@@ -1,5 +1,5 @@
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/issue-116434-2015.rs:3:17
+  --> $DIR/issue-116434-2015.rs:5:17
    |
 LL |     fn foo() -> Clone;
    |                 ^^^^^
@@ -13,7 +13,7 @@ LL |     fn foo() -> dyn Clone;
    |                 +++
 
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/issue-116434-2015.rs:3:17
+  --> $DIR/issue-116434-2015.rs:5:17
    |
 LL |     fn foo() -> Clone;
    |                 ^^^^^
@@ -27,7 +27,7 @@ LL |     fn foo() -> dyn Clone;
    |                 +++
 
 error[E0038]: the trait `Clone` is not dyn compatible
-  --> $DIR/issue-116434-2015.rs:3:17
+  --> $DIR/issue-116434-2015.rs:5:17
    |
 LL |     fn foo() -> Clone;
    |                 ^^^^^ `Clone` is not dyn compatible
@@ -41,7 +41,7 @@ LL |     fn foo() -> Self::Clone;
    |                 ++++++
 
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/issue-116434-2015.rs:18:20
+  --> $DIR/issue-116434-2015.rs:20:20
    |
 LL |     fn handle() -> DbHandle;
    |                    ^^^^^^^^
@@ -54,7 +54,7 @@ LL |     fn handle() -> dyn DbHandle;
    |                    +++
 
 warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/issue-116434-2015.rs:18:20
+  --> $DIR/issue-116434-2015.rs:20:20
    |
 LL |     fn handle() -> DbHandle;
    |                    ^^^^^^^^
@@ -68,14 +68,14 @@ LL |     fn handle() -> dyn DbHandle;
    |                    +++
 
 error[E0038]: the trait `DbHandle` is not dyn compatible
-  --> $DIR/issue-116434-2015.rs:18:20
+  --> $DIR/issue-116434-2015.rs:20:20
    |
 LL |     fn handle() -> DbHandle;
    |                    ^^^^^^^^ `DbHandle` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
       for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/issue-116434-2015.rs:14:17
+  --> $DIR/issue-116434-2015.rs:16:17
    |
 LL | trait DbHandle: Sized {}
    |       --------  ^^^^^ ...because it requires `Self: Sized`
diff --git a/tests/ui/suggestions/issue-61963.rs b/tests/ui/suggestions/issue-61963.rs
index 2fafe629db9..77e4b21f5db 100644
--- a/tests/ui/suggestions/issue-61963.rs
+++ b/tests/ui/suggestions/issue-61963.rs
@@ -1,3 +1,4 @@
+//@ edition: 2015
 //@ proc-macro: issue-61963.rs
 //@ proc-macro: issue-61963-1.rs
 #![deny(bare_trait_objects)]
diff --git a/tests/ui/suggestions/issue-61963.stderr b/tests/ui/suggestions/issue-61963.stderr
index 734c88f3fd6..ef11efe5c74 100644
--- a/tests/ui/suggestions/issue-61963.stderr
+++ b/tests/ui/suggestions/issue-61963.stderr
@@ -1,5 +1,5 @@
 error: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/issue-61963.rs:22:14
+  --> $DIR/issue-61963.rs:23:14
    |
 LL |     bar: Box<Bar>,
    |              ^^^
@@ -7,7 +7,7 @@ LL |     bar: Box<Bar>,
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
 note: the lint level is defined here
-  --> $DIR/issue-61963.rs:3:9
+  --> $DIR/issue-61963.rs:4:9
    |
 LL | #![deny(bare_trait_objects)]
    |         ^^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ LL |     bar: Box<dyn Bar>,
    |              +++
 
 error: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/issue-61963.rs:18:1
+  --> $DIR/issue-61963.rs:19:1
    |
 LL | pub struct Foo {
    | ^^^
diff --git a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
index 41cb2ee46bb..0aa33d3b6fb 100644
--- a/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
+++ b/tests/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr
@@ -101,15 +101,17 @@ LL + fn bat<'b, 'a, G: 'a + 'b, T>(g: G, dest: &'b mut T) -> impl FnOnce() + 'b
 error[E0621]: explicit lifetime required in the type of `dest`
   --> $DIR/missing-lifetimes-in-signature.rs:73:5
    |
-LL |   fn bat<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ + 'a
-   |                                    ------ help: add explicit lifetime `'a` to the type of `dest`: `&'a mut T`
-...
 LL | /     move || {
 LL | |
 LL | |
 LL | |         *dest = g.get();
 LL | |     }
    | |_____^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to the type of `dest`
+   |
+LL | fn bat<'a, G: 'a, T>(g: G, dest: &'a mut T) -> impl FnOnce() + '_ + 'a
+   |                                   ++
 
 error[E0309]: the parameter type `G` may not live long enough
   --> $DIR/missing-lifetimes-in-signature.rs:85:5
diff --git a/tests/ui/suggestions/missing-lifetime-specifier.rs b/tests/ui/suggestions/missing-lifetime-specifier.rs
index a957477897d..88d9736a071 100644
--- a/tests/ui/suggestions/missing-lifetime-specifier.rs
+++ b/tests/ui/suggestions/missing-lifetime-specifier.rs
@@ -7,7 +7,6 @@
 // Different number of duplicated diagnostics on different targets
 //@ compile-flags: -Zdeduplicate-diagnostics=yes
 
-#![allow(bare_trait_objects)]
 use std::cell::RefCell;
 use std::collections::HashMap;
 
@@ -28,7 +27,7 @@ thread_local! {
     //~^ ERROR missing lifetime specifiers
 }
 thread_local! {
-    static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
+    static b: RefCell<HashMap<i32, Vec<Vec<&dyn Bar>>>> = RefCell::new(HashMap::new());
     //~^ ERROR missing lifetime specifiers
 }
 thread_local! {
@@ -36,7 +35,7 @@ thread_local! {
     //~^ ERROR missing lifetime specifiers
 }
 thread_local! {
-    static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
+    static d: RefCell<HashMap<i32, Vec<Vec<&dyn Tar<i32>>>>> = RefCell::new(HashMap::new());
     //~^ ERROR missing lifetime specifiers
 }
 
@@ -45,8 +44,9 @@ thread_local! {
     //~^ ERROR union takes 2 lifetime arguments but 1 lifetime argument
 }
 thread_local! {
-    static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
-    //~^ ERROR trait takes 2 lifetime arguments but 1 lifetime argument was supplied
+    static f: RefCell<HashMap<i32, Vec<Vec<&dyn Tar<'static, i32>>>>> =
+        RefCell::new(HashMap::new());
+    //~^^ ERROR trait takes 2 lifetime arguments but 1 lifetime argument was supplied
     //~| ERROR missing lifetime specifier
 }
 
diff --git a/tests/ui/suggestions/missing-lifetime-specifier.stderr b/tests/ui/suggestions/missing-lifetime-specifier.stderr
index 1fdbf3b0c79..b8c58155e63 100644
--- a/tests/ui/suggestions/missing-lifetime-specifier.stderr
+++ b/tests/ui/suggestions/missing-lifetime-specifier.stderr
@@ -1,5 +1,5 @@
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:27:44
+  --> $DIR/missing-lifetime-specifier.rs:26:44
    |
 LL |     static a: RefCell<HashMap<i32, Vec<Vec<Foo>>>> = RefCell::new(HashMap::new());
    |                                            ^^^ expected 2 lifetime parameters
@@ -11,21 +11,21 @@ LL |     static a: RefCell<HashMap<i32, Vec<Vec<Foo<'static, 'static>>>>> = RefC
    |                                               ++++++++++++++++++
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:31:44
+  --> $DIR/missing-lifetime-specifier.rs:30:44
    |
-LL |     static b: RefCell<HashMap<i32, Vec<Vec<&Bar>>>> = RefCell::new(HashMap::new());
-   |                                            ^^^^ expected 2 lifetime parameters
+LL |     static b: RefCell<HashMap<i32, Vec<Vec<&dyn Bar>>>> = RefCell::new(HashMap::new());
+   |                                            ^    ^^^ expected 2 lifetime parameters
    |                                            |
    |                                            expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
-LL |     static b: RefCell<HashMap<i32, Vec<Vec<&'static Bar<'static, 'static>>>>> = RefCell::new(HashMap::new());
-   |                                             +++++++    ++++++++++++++++++
+LL |     static b: RefCell<HashMap<i32, Vec<Vec<&'static dyn Bar<'static, 'static>>>>> = RefCell::new(HashMap::new());
+   |                                             +++++++        ++++++++++++++++++
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:35:47
+  --> $DIR/missing-lifetime-specifier.rs:34:47
    |
 LL |     static c: RefCell<HashMap<i32, Vec<Vec<Qux<i32>>>>> = RefCell::new(HashMap::new());
    |                                               ^ expected 2 lifetime parameters
@@ -37,33 +37,38 @@ LL |     static c: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> =
    |                                                +++++++++++++++++
 
 error[E0106]: missing lifetime specifiers
-  --> $DIR/missing-lifetime-specifier.rs:39:44
+  --> $DIR/missing-lifetime-specifier.rs:38:44
    |
-LL |     static d: RefCell<HashMap<i32, Vec<Vec<&Tar<i32>>>>> = RefCell::new(HashMap::new());
-   |                                            ^   ^ expected 2 lifetime parameters
+LL |     static d: RefCell<HashMap<i32, Vec<Vec<&dyn Tar<i32>>>>> = RefCell::new(HashMap::new());
+   |                                            ^       ^ expected 2 lifetime parameters
    |                                            |
    |                                            expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
-LL |     static d: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
-   |                                             +++++++     +++++++++++++++++
+LL |     static d: RefCell<HashMap<i32, Vec<Vec<&'static dyn Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
+   |                                             +++++++         +++++++++++++++++
 
 error[E0106]: missing lifetime specifier
-  --> $DIR/missing-lifetime-specifier.rs:48:44
+  --> $DIR/missing-lifetime-specifier.rs:47:44
    |
-LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
+LL |     static f: RefCell<HashMap<i32, Vec<Vec<&dyn Tar<'static, i32>>>>> =
    |                                            ^ expected named lifetime parameter
    |
    = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
 help: consider using the `'static` lifetime, but this is uncommon unless you're returning a borrowed value from a `const` or a `static`
    |
-LL |     static f: RefCell<HashMap<i32, Vec<Vec<&'static Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
+LL |     static f: RefCell<HashMap<i32, Vec<Vec<&'static dyn Tar<'static, i32>>>>> =
    |                                             +++++++
+help: instead, you are more likely to want to return an owned value
+   |
+LL -     static f: RefCell<HashMap<i32, Vec<Vec<&dyn Tar<'static, i32>>>>> =
+LL +     static f: RefCell<HashMap<i32, Vec<Vec<dyn Tar<'static, i32>>>>> =
+   |
 
 error[E0107]: union takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:44:44
+  --> $DIR/missing-lifetime-specifier.rs:43:44
    |
 LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell::new(HashMap::new());
    |                                            ^^^ ------- supplied 1 lifetime argument
@@ -71,7 +76,7 @@ LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, i32>>>>> = RefCell:
    |                                            expected 2 lifetime arguments
    |
 note: union defined here, with 2 lifetime parameters: `'t`, `'k`
-  --> $DIR/missing-lifetime-specifier.rs:20:11
+  --> $DIR/missing-lifetime-specifier.rs:19:11
    |
 LL | pub union Qux<'t, 'k, I> {
    |           ^^^ --  --
@@ -81,22 +86,22 @@ LL |     static e: RefCell<HashMap<i32, Vec<Vec<Qux<'static, 'static, i32>>>>> =
    |                                                       +++++++++
 
 error[E0107]: trait takes 2 lifetime arguments but 1 lifetime argument was supplied
-  --> $DIR/missing-lifetime-specifier.rs:48:45
+  --> $DIR/missing-lifetime-specifier.rs:47:49
    |
-LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, i32>>>>> = RefCell::new(HashMap::new());
-   |                                             ^^^ ------- supplied 1 lifetime argument
-   |                                             |
-   |                                             expected 2 lifetime arguments
+LL |     static f: RefCell<HashMap<i32, Vec<Vec<&dyn Tar<'static, i32>>>>> =
+   |                                                 ^^^ ------- supplied 1 lifetime argument
+   |                                                 |
+   |                                                 expected 2 lifetime arguments
    |
 note: trait defined here, with 2 lifetime parameters: `'t`, `'k`
-  --> $DIR/missing-lifetime-specifier.rs:24:7
+  --> $DIR/missing-lifetime-specifier.rs:23:7
    |
 LL | trait Tar<'t, 'k, I> {}
    |       ^^^ --  --
 help: add missing lifetime argument
    |
-LL |     static f: RefCell<HashMap<i32, Vec<Vec<&Tar<'static, 'static, i32>>>>> = RefCell::new(HashMap::new());
-   |                                                        +++++++++
+LL |     static f: RefCell<HashMap<i32, Vec<Vec<&dyn Tar<'static, 'static, i32>>>>> =
+   |                                                            +++++++++
 
 error: aborting due to 7 previous errors
 
diff --git a/tests/ui/symbol-names/impl1.rs b/tests/ui/symbol-names/impl1.rs
index 694cd89bd80..0fdf5645479 100644
--- a/tests/ui/symbol-names/impl1.rs
+++ b/tests/ui/symbol-names/impl1.rs
@@ -26,7 +26,7 @@ mod foo {
 }
 
 mod bar {
-    use foo::Foo;
+    use crate::foo::Foo;
 
     impl Foo {
         #[rustc_symbol_name]
diff --git a/tests/ui/symbol-names/issue-53912.rs b/tests/ui/symbol-names/issue-53912.rs
index 194416cdb70..ba28316b0bf 100644
--- a/tests/ui/symbol-names/issue-53912.rs
+++ b/tests/ui/symbol-names/issue-53912.rs
@@ -12,13 +12,13 @@ mod llvm {
 mod foo {
     pub(crate) struct Foo<T>(T);
 
-    impl Foo<::llvm::Foo> {
+    impl Foo<crate::llvm::Foo> {
         pub(crate) fn foo() {
             for _ in 0..0 {
-                for _ in &[::dummy()] {
-                    ::dummy();
-                    ::dummy();
-                    ::dummy();
+                for _ in &[crate::dummy()] {
+                    crate::dummy();
+                    crate::dummy();
+                    crate::dummy();
                 }
             }
         }
diff --git a/tests/ui/symbol-names/issue-60925.rs b/tests/ui/symbol-names/issue-60925.rs
index ca0f21b7a78..24969fc6641 100644
--- a/tests/ui/symbol-names/issue-60925.rs
+++ b/tests/ui/symbol-names/issue-60925.rs
@@ -17,7 +17,7 @@ mod llvm {
 mod foo {
     pub(crate) struct Foo<T>(T);
 
-    impl Foo<::llvm::Foo> {
+    impl Foo<crate::llvm::Foo> {
         #[rustc_symbol_name]
         //[legacy]~^ ERROR symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo
         //[legacy]~| ERROR demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo
@@ -27,10 +27,10 @@ mod foo {
             //[v0]~| ERROR demangling-alt(<issue_60925::foo::Foo<issue_60925::llvm::Foo>>::foo)
         pub(crate) fn foo() {
             for _ in 0..0 {
-                for _ in &[::dummy()] {
-                    ::dummy();
-                    ::dummy();
-                    ::dummy();
+                for _ in &[crate::dummy()] {
+                    crate::dummy();
+                    crate::dummy();
+                    crate::dummy();
                 }
             }
         }
diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature.stderr
new file mode 100644
index 00000000000..e2b6078b7a8
--- /dev/null
+++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature.stderr
@@ -0,0 +1,7 @@
+warning: target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `x86-retpoline` target modifier flag instead
+   |
+   = note: 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 #116344 <https://github.com/rust-lang/rust/issues/116344>
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr
new file mode 100644
index 00000000000..2a0f5f01aef
--- /dev/null
+++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature1.stderr
@@ -0,0 +1,7 @@
+warning: target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `retpoline-external-thunk` target modifier flag instead
+   |
+   = note: 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 #116344 <https://github.com/rust-lang/rust/issues/116344>
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr
new file mode 100644
index 00000000000..f7b6cb16447
--- /dev/null
+++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature2.stderr
@@ -0,0 +1,7 @@
+warning: target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead
+   |
+   = note: 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 #116344 <https://github.com/rust-lang/rust/issues/116344>
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr
new file mode 100644
index 00000000000..4f2cd1d1a52
--- /dev/null
+++ b/tests/ui/target-feature/retpoline-target-feature-flag.by_feature3.stderr
@@ -0,0 +1,7 @@
+warning: target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead
+   |
+   = note: 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 #116344 <https://github.com/rust-lang/rust/issues/116344>
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/target-feature/retpoline-target-feature-flag.rs b/tests/ui/target-feature/retpoline-target-feature-flag.rs
new file mode 100644
index 00000000000..3e614a4236c
--- /dev/null
+++ b/tests/ui/target-feature/retpoline-target-feature-flag.rs
@@ -0,0 +1,23 @@
+//@ revisions: by_flag by_feature1 by_feature2 by_feature3
+//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib
+//@ needs-llvm-components: x86
+//@ [by_flag]compile-flags: -Zretpoline
+
+//@ [by_feature1]compile-flags: -Ctarget-feature=+retpoline-external-thunk
+//@ [by_feature2]compile-flags: -Ctarget-feature=+retpoline-indirect-branches
+//@ [by_feature3]compile-flags: -Ctarget-feature=+retpoline-indirect-calls
+//@ [by_flag]build-pass
+// For now this is just a warning.
+//@ [by_feature1]build-pass
+//@ [by_feature2]build-pass
+//@ [by_feature3]build-pass
+#![feature(no_core, lang_items)]
+#![no_std]
+#![no_core]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+//[by_feature1]~? WARN target feature `retpoline-external-thunk` cannot be enabled with `-Ctarget-feature`: use `retpoline-external-thunk` target modifier flag instead
+//[by_feature2]~? WARN target feature `retpoline-indirect-branches` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead
+//[by_feature3]~? WARN target feature `retpoline-indirect-calls` cannot be enabled with `-Ctarget-feature`: use `retpoline` target modifier flag instead
diff --git a/tests/ui/threads-sendsync/thread-local-syntax.rs b/tests/ui/threads-sendsync/thread-local-syntax.rs
index 2cf91f0c1f7..9492e1c93e2 100644
--- a/tests/ui/threads-sendsync/thread-local-syntax.rs
+++ b/tests/ui/threads-sendsync/thread-local-syntax.rs
@@ -13,7 +13,7 @@ mod foo {
 
             // look at these restrictions!!
             pub(crate) static BAZ: usize = 0;
-            pub(in foo) static QUUX: usize = 0;
+            pub(in crate::foo) static QUUX: usize = 0;
         }
         thread_local!(static SPLOK: u32 = 0);
     }
diff --git a/tests/ui/tool-attributes/diagnostic_item.rs b/tests/ui/tool-attributes/diagnostic_item.rs
index 26a52ce60cf..806b140feba 100644
--- a/tests/ui/tool-attributes/diagnostic_item.rs
+++ b/tests/ui/tool-attributes/diagnostic_item.rs
@@ -1,3 +1,5 @@
-#[rustc_diagnostic_item = "foomp"] //~ ERROR compiler internal support for linting
+#[rustc_diagnostic_item = "foomp"]
+//~^ ERROR use of an internal attribute [E0658]
+//~| NOTE the `#[rustc_diagnostic_item]` attribute allows the compiler to reference types from the standard library for diagnostic purposes
 struct Foomp;
 fn main() {}
diff --git a/tests/ui/tool-attributes/diagnostic_item.stderr b/tests/ui/tool-attributes/diagnostic_item.stderr
index c6ae5a38594..d37044281a1 100644
--- a/tests/ui/tool-attributes/diagnostic_item.stderr
+++ b/tests/ui/tool-attributes/diagnostic_item.stderr
@@ -1,11 +1,11 @@
-error[E0658]: diagnostic items compiler internal support for linting
+error[E0658]: use of an internal attribute
   --> $DIR/diagnostic_item.rs:1:1
    |
 LL | #[rustc_diagnostic_item = "foomp"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: the `#[rustc_diagnostic_item]` attribute allows the compiler to reference types from the standard library for diagnostic purposes
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/track-diagnostics/track.stderr b/tests/ui/track-diagnostics/track.stderr
index d2908bb9177..527c0d1b898 100644
--- a/tests/ui/track-diagnostics/track.stderr
+++ b/tests/ui/track-diagnostics/track.stderr
@@ -10,7 +10,7 @@ error[E0268]: `break` outside of a loop or labeled block
    |
 LL |     break rust
    |     ^^^^^^^^^^ cannot `break` outside of a loop or labeled block
--Ztrack-diagnostics: created at compiler/rustc_passes/src/loops.rs:LL:CC
+-Ztrack-diagnostics: created at compiler/rustc_hir_typeck/src/loops.rs:LL:CC
 
 error: internal compiler error: It looks like you're trying to break rust; would you like some ICE?
   --> $DIR/track.rs:LL:CC
diff --git a/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.fixed b/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.fixed
index e6aac1708ce..6354676bb25 100644
--- a/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.fixed
+++ b/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.fixed
@@ -1,3 +1,4 @@
+//@ edition: 2015
 //@ run-rustfix
 #![allow(non_snake_case)]
 mod A {
diff --git a/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.rs b/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.rs
index d5c557dc9c7..c3b3a00aa6d 100644
--- a/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.rs
+++ b/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.rs
@@ -1,3 +1,4 @@
+//@ edition: 2015
 //@ run-rustfix
 #![allow(non_snake_case)]
 mod A {
diff --git a/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr b/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr
index e2a72697501..4fb0dcc7901 100644
--- a/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr
+++ b/tests/ui/trait-bounds/shadowed-path-in-trait-bound-suggestion.stderr
@@ -1,5 +1,5 @@
 error[E0405]: cannot find trait `Trait` in `A`
-  --> $DIR/shadowed-path-in-trait-bound-suggestion.rs:9:24
+  --> $DIR/shadowed-path-in-trait-bound-suggestion.rs:10:24
    |
 LL |     pub struct A<H: A::Trait>(pub H);
    |                        ^^^^^ not found in `A`
diff --git a/tests/ui/traits/auxiliary/traitimpl.rs b/tests/ui/traits/auxiliary/traitimpl.rs
index fda5314cdbf..2544a96048b 100644
--- a/tests/ui/traits/auxiliary/traitimpl.rs
+++ b/tests/ui/traits/auxiliary/traitimpl.rs
@@ -2,6 +2,6 @@
 
 pub trait Bar<'a> : 'a {}
 
-impl<'a> Bar<'a> {
+impl<'a> dyn Bar<'a> {
     pub fn bar(&self) {}
 }
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/traits/const-traits/inherent-impl.rs b/tests/ui/traits/const-traits/inherent-impl.rs
index afd0d137bb4..07b23adf9e1 100644
--- a/tests/ui/traits/const-traits/inherent-impl.rs
+++ b/tests/ui/traits/const-traits/inherent-impl.rs
@@ -7,7 +7,7 @@ trait T {}
 impl const S {}
 //~^ ERROR inherent impls cannot be `const`
 
-impl const T {}
+impl const dyn T {}
 //~^ ERROR inherent impls cannot be `const`
 
 fn main() {}
diff --git a/tests/ui/traits/const-traits/inherent-impl.stderr b/tests/ui/traits/const-traits/inherent-impl.stderr
index 8c55627031d..e4ec1e807b0 100644
--- a/tests/ui/traits/const-traits/inherent-impl.stderr
+++ b/tests/ui/traits/const-traits/inherent-impl.stderr
@@ -11,8 +11,8 @@ LL | impl const S {}
 error: inherent impls cannot be `const`
   --> $DIR/inherent-impl.rs:10:12
    |
-LL | impl const T {}
-   |      ----- ^ inherent impl for this type
+LL | impl const dyn T {}
+   |      ----- ^^^^^ inherent impl for this type
    |      |
    |      `const` because of this
    |
diff --git a/tests/ui/traits/const-traits/mbe-dyn-const-2015.rs b/tests/ui/traits/const-traits/mbe-dyn-const-2015.rs
index 9d65a2ac302..fadfbe66788 100644
--- a/tests/ui/traits/const-traits/mbe-dyn-const-2015.rs
+++ b/tests/ui/traits/const-traits/mbe-dyn-const-2015.rs
@@ -1,6 +1,7 @@
 // Ensure that the introduction of const trait bound didn't regress this code in Rust 2015.
 // See also `mbe-const-trait-bound-theoretical-regression.rs`.
 
+//@ edition: 2015
 //@ check-pass
 
 macro_rules! check {
diff --git a/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.rs b/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.rs
index 27e70556b7a..47cc9f5f960 100644
--- a/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.rs
+++ b/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.rs
@@ -1,5 +1,7 @@
 #[rustc_must_implement_one_of(eq, neq)]
-//~^ ERROR the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait, it's currently in experimental form and should be changed before being exposed outside of the std
+//~^ ERROR use of an internal attribute [E0658]
+//~| NOTE the `#[rustc_must_implement_one_of]` attribute is an internal implementation detail that will never be stable
+//~| NOTE the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait. Its syntax and semantics are highly experimental and will be subject to change before stabilization
 trait Equal {
     fn eq(&self, other: &Self) -> bool {
         !self.neq(other)
diff --git a/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.stderr b/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.stderr
index 162c3d36cb1..4d44ceff98a 100644
--- a/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.stderr
+++ b/tests/ui/traits/default-method/rustc_must_implement_one_of_gated.stderr
@@ -1,11 +1,12 @@
-error[E0658]: the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait, it's currently in experimental form and should be changed before being exposed outside of the std
+error[E0658]: use of an internal attribute
   --> $DIR/rustc_must_implement_one_of_gated.rs:1:1
    |
 LL | #[rustc_must_implement_one_of(eq, neq)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = note: the `#[rustc_must_implement_one_of]` attribute is an internal implementation detail that will never be stable
+   = note: the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait. Its syntax and semantics are highly experimental and will be subject to change before stabilization
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/traits/impl-2.rs b/tests/ui/traits/impl-2.rs
index c6f60a9081c..41fa1cd334f 100644
--- a/tests/ui/traits/impl-2.rs
+++ b/tests/ui/traits/impl-2.rs
@@ -10,7 +10,7 @@ pub mod Foo {
 }
 
 mod Bar {
-    impl<'a> dyn (::Foo::Trait) + 'a {
+    impl<'a> dyn (crate::Foo::Trait) + 'a {
         fn bar(&self) { self.foo() }
     }
 }
diff --git a/tests/ui/traits/item-privacy.rs b/tests/ui/traits/item-privacy.rs
index 9f75e6e4c12..b8724399e32 100644
--- a/tests/ui/traits/item-privacy.rs
+++ b/tests/ui/traits/item-privacy.rs
@@ -15,9 +15,9 @@ mod method {
         fn c(&self) { }
     }
 
-    impl A for ::S {}
-    impl B for ::S {}
-    impl C for ::S {}
+    impl A for crate::S {}
+    impl B for crate::S {}
+    impl C for crate::S {}
 }
 
 mod assoc_const {
@@ -33,9 +33,9 @@ mod assoc_const {
         const C: u8 = 0;
     }
 
-    impl A for ::S {}
-    impl B for ::S {}
-    impl C for ::S {}
+    impl A for crate::S {}
+    impl B for crate::S {}
+    impl C for crate::S {}
 }
 
 mod assoc_ty {
@@ -51,9 +51,9 @@ mod assoc_ty {
         type C = u8;
     }
 
-    impl A for ::S {}
-    impl B for ::S {}
-    impl C for ::S {}
+    impl A for crate::S {}
+    impl B for crate::S {}
+    impl C for crate::S {}
 }
 
 fn check_method() {
diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs
index ea6df938704..14f0cbcc8b7 100644
--- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs
+++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.rs
@@ -13,9 +13,9 @@ fn main() {
 }
 
 fn weird0() -> impl Sized + !Sized {}
-//~^ ERROR type mismatch resolving
+//~^ ERROR the trait bound `(): !Sized` is not satisfied
 fn weird1() -> impl !Sized + Sized {}
-//~^ ERROR type mismatch resolving
+//~^ ERROR the trait bound `(): !Sized` is not satisfied
 fn weird2() -> impl !Sized {}
-//~^ ERROR type mismatch resolving
+//~^ ERROR the trait bound `(): !Sized` is not satisfied
 //~| ERROR the size for values of type
diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr
index 41d9e74f807..3ba3d8d8bd5 100644
--- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr
+++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-bound.stderr
@@ -7,23 +7,23 @@ LL | fn weird2() -> impl !Sized {}
    = help: the trait `Sized` is not implemented for `impl !Sized`
    = note: the return type of a function must have a statically known size
 
-error[E0271]: type mismatch resolving `impl !Sized + Sized == ()`
+error[E0277]: the trait bound `(): !Sized` is not satisfied
   --> $DIR/opaque-type-unsatisfied-bound.rs:15:16
    |
 LL | fn weird0() -> impl Sized + !Sized {}
-   |                ^^^^^^^^^^^^^^^^^^^ types differ
+   |                ^^^^^^^^^^^^^^^^^^^ the trait bound `(): !Sized` is not satisfied
 
-error[E0271]: type mismatch resolving `impl !Sized + Sized == ()`
+error[E0277]: the trait bound `(): !Sized` is not satisfied
   --> $DIR/opaque-type-unsatisfied-bound.rs:17:16
    |
 LL | fn weird1() -> impl !Sized + Sized {}
-   |                ^^^^^^^^^^^^^^^^^^^ types differ
+   |                ^^^^^^^^^^^^^^^^^^^ the trait bound `(): !Sized` is not satisfied
 
-error[E0271]: type mismatch resolving `impl !Sized == ()`
+error[E0277]: the trait bound `(): !Sized` is not satisfied
   --> $DIR/opaque-type-unsatisfied-bound.rs:19:16
    |
 LL | fn weird2() -> impl !Sized {}
-   |                ^^^^^^^^^^^ types differ
+   |                ^^^^^^^^^^^ the trait bound `(): !Sized` is not satisfied
 
 error[E0277]: the trait bound `impl !Trait: Trait` is not satisfied
   --> $DIR/opaque-type-unsatisfied-bound.rs:12:13
@@ -41,5 +41,4 @@ LL | fn consume(_: impl Trait) {}
 
 error: aborting due to 5 previous errors
 
-Some errors have detailed explanations: E0271, E0277.
-For more information about an error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs
index ce42bce0ad4..39422914afc 100644
--- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs
+++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.rs
@@ -3,6 +3,6 @@
 #![feature(negative_bounds, unboxed_closures)]
 
 fn produce() -> impl !Fn<(u32,)> {}
-//~^ ERROR type mismatch resolving
+//~^ ERROR the trait bound `(): !Fn(u32)` is not satisfied
 
 fn main() {}
diff --git a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr
index e1b84e0df7a..760e5aa62f2 100644
--- a/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr
+++ b/tests/ui/traits/negative-bounds/opaque-type-unsatisfied-fn-bound.stderr
@@ -1,9 +1,9 @@
-error[E0271]: type mismatch resolving `impl !Fn<(u32,)> == ()`
+error[E0277]: the trait bound `(): !Fn(u32)` is not satisfied
   --> $DIR/opaque-type-unsatisfied-fn-bound.rs:5:17
    |
 LL | fn produce() -> impl !Fn<(u32,)> {}
-   |                 ^^^^^^^^^^^^^^^^ types differ
+   |                 ^^^^^^^^^^^^^^^^ the trait bound `(): !Fn(u32)` is not satisfied
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0271`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.is_send.stderr b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.is_send.stderr
index 736c8c10da9..6d2bbd8b08b 100644
--- a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.is_send.stderr
+++ b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.is_send.stderr
@@ -1,9 +1,16 @@
-error[E0284]: type annotations needed: cannot satisfy `Foo == _`
+error[E0283]: type annotations needed: cannot satisfy `Foo: Send`
   --> $DIR/dont-type_of-tait-in-defining-scope.rs:16:18
    |
 LL |     needs_send::<Foo>();
-   |                  ^^^ cannot satisfy `Foo == _`
+   |                  ^^^
+   |
+   = note: cannot satisfy `Foo: Send`
+note: required by a bound in `needs_send`
+  --> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18
+   |
+LL | fn needs_send<T: Send>() {}
+   |                  ^^^^ required by this bound in `needs_send`
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0284`.
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.not_send.stderr b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.not_send.stderr
index 736c8c10da9..6d2bbd8b08b 100644
--- a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.not_send.stderr
+++ b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.not_send.stderr
@@ -1,9 +1,16 @@
-error[E0284]: type annotations needed: cannot satisfy `Foo == _`
+error[E0283]: type annotations needed: cannot satisfy `Foo: Send`
   --> $DIR/dont-type_of-tait-in-defining-scope.rs:16:18
    |
 LL |     needs_send::<Foo>();
-   |                  ^^^ cannot satisfy `Foo == _`
+   |                  ^^^
+   |
+   = note: cannot satisfy `Foo: Send`
+note: required by a bound in `needs_send`
+  --> $DIR/dont-type_of-tait-in-defining-scope.rs:12:18
+   |
+LL | fn needs_send<T: Send>() {}
+   |                  ^^^^ required by this bound in `needs_send`
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0284`.
+For more information about this error, try `rustc --explain E0283`.
diff --git a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.rs b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.rs
index 2a08a3b2b94..fddf892e1ef 100644
--- a/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.rs
+++ b/tests/ui/traits/next-solver/opaques/dont-type_of-tait-in-defining-scope.rs
@@ -14,7 +14,7 @@ fn needs_send<T: Send>() {}
 #[define_opaque(Foo)]
 fn test(_: Foo) {
     needs_send::<Foo>();
-    //~^ ERROR type annotations needed: cannot satisfy `Foo == _`
+    //~^ ERROR type annotations needed
 }
 
 #[define_opaque(Foo)]
diff --git a/tests/ui/traits/static-method-overwriting.rs b/tests/ui/traits/static-method-overwriting.rs
index 7a2a51a4b99..28edcde4c49 100644
--- a/tests/ui/traits/static-method-overwriting.rs
+++ b/tests/ui/traits/static-method-overwriting.rs
@@ -9,7 +9,7 @@ mod base {
         dummy: (),
     }
 
-    impl ::base::HasNew for Foo {
+    impl crate::base::HasNew for Foo {
         fn new() -> Foo {
             println!("Foo");
             Foo { dummy: () }
@@ -20,7 +20,7 @@ mod base {
         dummy: (),
     }
 
-    impl ::base::HasNew for Bar {
+    impl crate::base::HasNew for Bar {
         fn new() -> Bar {
             println!("Bar");
             Bar { dummy: () }
diff --git a/tests/ui/transmutability/references/reject_extension.stderr b/tests/ui/transmutability/references/reject_extension.stderr
index 182106acf12..a5f67785094 100644
--- a/tests/ui/transmutability/references/reject_extension.stderr
+++ b/tests/ui/transmutability/references/reject_extension.stderr
@@ -2,7 +2,7 @@ error[E0277]: `&Packed<Two>` cannot be safely transmuted into `&Packed<Four>`
   --> $DIR/reject_extension.rs:48:37
    |
 LL |     assert::is_transmutable::<&Src, &Dst>();
-   |                                     ^^^^ the referent size of `&Packed<Two>` (2 bytes) is smaller than that of `&Packed<Four>` (4 bytes)
+   |                                     ^^^^ the size of `Packed<Two>` (2 bytes) is smaller than that of `Packed<Four>` (4 bytes)
    |
 note: required by a bound in `is_transmutable`
   --> $DIR/reject_extension.rs:13:14
diff --git a/tests/ui/transmutability/references/unit-to-u8.stderr b/tests/ui/transmutability/references/unit-to-u8.stderr
index bc9f286e097..35d1179f451 100644
--- a/tests/ui/transmutability/references/unit-to-u8.stderr
+++ b/tests/ui/transmutability/references/unit-to-u8.stderr
@@ -2,7 +2,7 @@ error[E0277]: `&Unit` cannot be safely transmuted into `&u8`
   --> $DIR/unit-to-u8.rs:22:52
    |
 LL |     assert::is_maybe_transmutable::<&'static Unit, &'static u8>();
-   |                                                    ^^^^^^^^^^^ the referent size of `&Unit` (0 bytes) is smaller than that of `&u8` (1 bytes)
+   |                                                    ^^^^^^^^^^^ the size of `Unit` (0 bytes) is smaller than that of `u8` (1 bytes)
    |
 note: required by a bound in `is_maybe_transmutable`
   --> $DIR/unit-to-u8.rs:9:14
diff --git a/tests/ui/transmutability/references/unsafecell.rs b/tests/ui/transmutability/references/unsafecell.rs
index 4001f139770..b0db4af45f5 100644
--- a/tests/ui/transmutability/references/unsafecell.rs
+++ b/tests/ui/transmutability/references/unsafecell.rs
@@ -38,10 +38,10 @@ fn mut_to_mut() {
 }
 
 fn mut_to_ref() {
-    // We don't care about `UnsafeCell` for transmutations in the form `&mut T
-    // -> &U`, because downgrading a `&mut T` to a `&U` deactivates `&mut T` for
-    // the lifetime of `&U`.
-    assert::is_maybe_transmutable::<&'static mut u8, &'static UnsafeCell<u8>>();
-    assert::is_maybe_transmutable::<&'static mut UnsafeCell<u8>, &'static u8>();
-    assert::is_maybe_transmutable::<&'static mut UnsafeCell<u8>, &'static UnsafeCell<u8>>();
+    // `&mut UnsafeCell` is irrelevant in the source.
+    assert::is_maybe_transmutable::<&'static mut UnsafeCell<bool>, &'static u8>();
+    // `&UnsafeCell` in forbidden in the destination, since the destination can be used to
+    // invalidate a shadowed source reference.
+    assert::is_maybe_transmutable::<&'static mut bool, &'static UnsafeCell<u8>>(); //~ ERROR: cannot be safely transmuted
+    assert::is_maybe_transmutable::<&'static mut UnsafeCell<bool>, &'static UnsafeCell<u8>>(); //~ ERROR: cannot be safely transmuted
 }
diff --git a/tests/ui/transmutability/references/unsafecell.stderr b/tests/ui/transmutability/references/unsafecell.stderr
index 6664d8a7d6f..02a0935e84e 100644
--- a/tests/ui/transmutability/references/unsafecell.stderr
+++ b/tests/ui/transmutability/references/unsafecell.stderr
@@ -28,6 +28,36 @@ LL |     where
 LL |         Dst: TransmuteFrom<Src, { Assume::SAFETY }>
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
 
-error: aborting due to 2 previous errors
+error[E0277]: `&mut bool` cannot be safely transmuted into `&UnsafeCell<u8>`
+  --> $DIR/unsafecell.rs:45:56
+   |
+LL |     assert::is_maybe_transmutable::<&'static mut bool, &'static UnsafeCell<u8>>();
+   |                                                        ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `UnsafeCell<u8>`
+   |
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/unsafecell.rs:12:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this function
+LL |     where
+LL |         Dst: TransmuteFrom<Src, { Assume::SAFETY }>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error[E0277]: `&mut UnsafeCell<bool>` cannot be safely transmuted into `&UnsafeCell<u8>`
+  --> $DIR/unsafecell.rs:46:68
+   |
+LL |     assert::is_maybe_transmutable::<&'static mut UnsafeCell<bool>, &'static UnsafeCell<u8>>();
+   |                                                                    ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Freeze` is not implemented for `UnsafeCell<u8>`
+   |
+note: required by a bound in `is_maybe_transmutable`
+  --> $DIR/unsafecell.rs:12:14
+   |
+LL |     pub fn is_maybe_transmutable<Src, Dst>()
+   |            --------------------- required by a bound in this function
+LL |     where
+LL |         Dst: TransmuteFrom<Src, { Assume::SAFETY }>
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/tuple/tuple-struct-fields/test.rs b/tests/ui/tuple/tuple-struct-fields/test.rs
index 00677090d78..29aabf4579b 100644
--- a/tests/ui/tuple/tuple-struct-fields/test.rs
+++ b/tests/ui/tuple/tuple-struct-fields/test.rs
@@ -1,6 +1,6 @@
 mod foo {
     type T = ();
-    struct S1(pub(in foo) (), pub(T), pub(crate) (), pub(((), T)));
+    struct S1(pub(in crate::foo) (), pub(T), pub(crate) (), pub(((), T)));
     struct S2(pub((foo)) ());
     //~^ ERROR expected one of `)` or `,`, found `(`
     //~| ERROR cannot find type `foo` in this scope
diff --git a/tests/ui/tuple/tuple-struct-fields/test2.rs b/tests/ui/tuple/tuple-struct-fields/test2.rs
index 2b2a2c127e9..544d486752c 100644
--- a/tests/ui/tuple/tuple-struct-fields/test2.rs
+++ b/tests/ui/tuple/tuple-struct-fields/test2.rs
@@ -1,7 +1,7 @@
 macro_rules! define_struct {
     ($t:ty) => {
         struct S1(pub $t);
-        struct S2(pub (in foo) ());
+        struct S2(pub (in crate::foo) ());
         struct S3(pub $t ());
         //~^ ERROR expected one of `)` or `,`, found `(`
     }
diff --git a/tests/ui/tuple/tuple-struct-fields/test3.rs b/tests/ui/tuple/tuple-struct-fields/test3.rs
index 98d19426e77..b5f98a65fa6 100644
--- a/tests/ui/tuple/tuple-struct-fields/test3.rs
+++ b/tests/ui/tuple/tuple-struct-fields/test3.rs
@@ -1,7 +1,7 @@
 macro_rules! define_struct {
     ($t:ty) => {
         struct S1(pub($t));
-        struct S2(pub (in foo) ());
+        struct S2(pub (in crate::foo) ());
         struct S3(pub($t) ());
         //~^ ERROR expected one of `)` or `,`, found `(`
     }
diff --git a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr
index 9e83de5375f..f7e0245bc83 100644
--- a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr
+++ b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.next.stderr
@@ -7,7 +7,7 @@ LL | impl<In, Out> Trait<Bar, In> for Out {
 LL | impl<In, Out> Trait<(), In> for Out {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
 
-error[E0284]: type annotations needed: cannot satisfy `Bar == _`
+error[E0282]: type annotations needed
   --> $DIR/issue-84660-unsoundness.rs:24:37
    |
 LL |       fn convert(_i: In) -> Self::Out {
@@ -16,9 +16,9 @@ LL | |
 LL | |
 LL | |         unreachable!();
 LL | |     }
-   | |_____^ cannot satisfy `Bar == _`
+   | |_____^ cannot infer type
 
 error: aborting due to 2 previous errors
 
-Some errors have detailed explanations: E0119, E0284.
+Some errors have detailed explanations: E0119, E0282.
 For more information about an error, try `rustc --explain E0119`.
diff --git a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs
index 7a540d2a574..a385138b295 100644
--- a/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs
+++ b/tests/ui/type-alias-impl-trait/issue-84660-unsoundness.rs
@@ -22,7 +22,7 @@ impl<In, Out> Trait<Bar, In> for Out {
     type Out = Out;
     #[define_opaque(Bar)]
     fn convert(_i: In) -> Self::Out {
-        //[next]~^  ERROR: type annotations needed: cannot satisfy `Bar == _`
+        //[next]~^  ERROR: type annotations needed
         //[current]~^^ ERROR: item does not constrain `Bar::{opaque#0}`
         unreachable!();
     }
diff --git a/tests/ui/type-alias-impl-trait/nested-tait-inference2.next.stderr b/tests/ui/type-alias-impl-trait/nested-tait-inference2.next.stderr
index b733739e4c8..d2127976e7d 100644
--- a/tests/ui/type-alias-impl-trait/nested-tait-inference2.next.stderr
+++ b/tests/ui/type-alias-impl-trait/nested-tait-inference2.next.stderr
@@ -1,9 +1,9 @@
-error[E0284]: type annotations needed: cannot satisfy `impl Foo<FooX> == ()`
+error[E0282]: type annotations needed
   --> $DIR/nested-tait-inference2.rs:20:5
    |
 LL |     ()
-   |     ^^ cannot satisfy `impl Foo<FooX> == ()`
+   |     ^^ cannot infer type
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0284`.
+For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/type-alias-impl-trait/nested-tait-inference2.rs b/tests/ui/type-alias-impl-trait/nested-tait-inference2.rs
index 4aeecb9140c..606336178e5 100644
--- a/tests/ui/type-alias-impl-trait/nested-tait-inference2.rs
+++ b/tests/ui/type-alias-impl-trait/nested-tait-inference2.rs
@@ -18,7 +18,7 @@ impl Foo<u32> for () {}
 fn foo() -> impl Foo<FooX> {
     //[current]~^ ERROR: the trait bound `(): Foo<FooX>` is not satisfied
     ()
-    //[next]~^ ERROR: cannot satisfy `impl Foo<FooX> == ()`
+    //[next]~^ ERROR: type annotations needed
 }
 
 fn main() {}
diff --git a/tests/ui/type/auxiliary/crate_a1.rs b/tests/ui/type/auxiliary/crate_a1.rs
index 616493193fd..f8ee9ae15c1 100644
--- a/tests/ui/type/auxiliary/crate_a1.rs
+++ b/tests/ui/type/auxiliary/crate_a1.rs
@@ -2,10 +2,10 @@ pub struct Foo;
 
 pub trait Bar {}
 
-pub fn bar() -> Box<Bar> {
+pub fn bar() -> Box<dyn Bar> {
     unimplemented!()
 }
 
 
 pub fn try_foo(x: Foo){}
-pub fn try_bar(x: Box<Bar>){}
+pub fn try_bar(x: Box<dyn Bar>){}
diff --git a/tests/ui/type/auxiliary/crate_a2.rs b/tests/ui/type/auxiliary/crate_a2.rs
index 57a7685b77c..fe22598e63e 100644
--- a/tests/ui/type/auxiliary/crate_a2.rs
+++ b/tests/ui/type/auxiliary/crate_a2.rs
@@ -2,6 +2,6 @@ pub struct Foo;
 
 pub trait Bar {}
 
-pub fn bar() -> Box<Bar> {
+pub fn bar() -> Box<dyn Bar> {
     unimplemented!()
 }
diff --git a/tests/ui/type/issue-7607-2.rs b/tests/ui/type/issue-7607-2.rs
index ebc4fe1c2d3..53fafdf9489 100644
--- a/tests/ui/type/issue-7607-2.rs
+++ b/tests/ui/type/issue-7607-2.rs
@@ -6,7 +6,7 @@ pub mod a {
 }
 
 pub mod b {
-    use a::Foo;
+    use crate::a::Foo;
     impl Foo {
         fn bar(&self) { }
     }
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;
diff --git a/tests/ui/type/type-mismatch-same-crate-name.stderr b/tests/ui/type/type-mismatch-same-crate-name.stderr
index 7b791549f56..8fafbfaa934 100644
--- a/tests/ui/type/type-mismatch-same-crate-name.stderr
+++ b/tests/ui/type/type-mismatch-same-crate-name.stderr
@@ -59,7 +59,7 @@ LL |         extern crate crate_a1 as a;
 note: function defined here
   --> $DIR/auxiliary/crate_a1.rs:11:8
    |
-LL | pub fn try_bar(x: Box<Bar>){}
+LL | pub fn try_bar(x: Box<dyn Bar>){}
    |        ^^^^^^^
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/typeck/issue-114529-illegal-break-with-value.stderr b/tests/ui/typeck/issue-114529-illegal-break-with-value.stderr
index de993df722c..872c506c7f1 100644
--- a/tests/ui/typeck/issue-114529-illegal-break-with-value.stderr
+++ b/tests/ui/typeck/issue-114529-illegal-break-with-value.stderr
@@ -1,4 +1,22 @@
 error[E0571]: `break` with value from a `while` loop
+  --> $DIR/issue-114529-illegal-break-with-value.rs:22:9
+   |
+LL |       while true {
+   |       ---------- you can't `break` with a value in a `while` loop
+LL | /         break (|| {
+LL | |             let local = 9;
+LL | |         });
+   | |__________^ can only break with a value inside `loop` or breakable block
+   |
+help: use `break` on its own without a value inside this `while` loop
+   |
+LL -         break (|| {
+LL -             let local = 9;
+LL -         });
+LL +         break;
+   |
+
+error[E0571]: `break` with value from a `while` loop
   --> $DIR/issue-114529-illegal-break-with-value.rs:9:13
    |
 LL |         while true {
@@ -26,24 +44,6 @@ LL -             break v;
 LL +             break;
    |
 
-error[E0571]: `break` with value from a `while` loop
-  --> $DIR/issue-114529-illegal-break-with-value.rs:22:9
-   |
-LL |       while true {
-   |       ---------- you can't `break` with a value in a `while` loop
-LL | /         break (|| {
-LL | |             let local = 9;
-LL | |         });
-   | |__________^ can only break with a value inside `loop` or breakable block
-   |
-help: use `break` on its own without a value inside this `while` loop
-   |
-LL -         break (|| {
-LL -             let local = 9;
-LL -         });
-LL +         break;
-   |
-
 error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0571`.
diff --git a/tests/ui/underscore-imports/basic.rs b/tests/ui/underscore-imports/basic.rs
index 624ecb47ca6..8d8ff5c47bc 100644
--- a/tests/ui/underscore-imports/basic.rs
+++ b/tests/ui/underscore-imports/basic.rs
@@ -18,25 +18,25 @@ mod m {
         fn tr2_is_in_scope(&self) {}
     }
 
-    impl Tr1 for ::S {}
-    impl Tr2 for ::S {}
+    impl Tr1 for crate::S {}
+    impl Tr2 for crate::S {}
 }
 
 mod unused {
-    use m::Tr1 as _; //~ WARN unused import
-    use S as _; //~ WARN unused import
+    use crate::m::Tr1 as _; //~ WARN unused import
+    use crate::S as _; //~ WARN unused import
     extern crate core as _; // OK
 }
 
 mod outer {
     mod middle {
-        pub use m::Tr1 as _;
-        pub use m::Tr2 as _; // OK, no name conflict
+        pub use crate::m::Tr1 as _;
+        pub use crate::m::Tr2 as _; // OK, no name conflict
         struct Tr1; // OK, no name conflict
         fn check() {
             // Both traits are in scope
-            ::S.tr1_is_in_scope();
-            ::S.tr2_is_in_scope();
+            crate::S.tr1_is_in_scope();
+            crate::S.tr2_is_in_scope();
         }
 
         mod inner {
@@ -44,8 +44,8 @@ mod outer {
             use super::*;
             fn check() {
                 // Both traits are in scope
-                ::S.tr1_is_in_scope();
-                ::S.tr2_is_in_scope();
+                crate::S.tr1_is_in_scope();
+                crate::S.tr2_is_in_scope();
             }
         }
     }
@@ -54,8 +54,8 @@ mod outer {
     use self::middle::*;
     fn check() {
         // Both traits are in scope
-        ::S.tr1_is_in_scope();
-        ::S.tr2_is_in_scope();
+        crate::S.tr1_is_in_scope();
+        crate::S.tr2_is_in_scope();
     }
 }
 
diff --git a/tests/ui/underscore-imports/basic.stderr b/tests/ui/underscore-imports/basic.stderr
index c51493562eb..666d07349df 100644
--- a/tests/ui/underscore-imports/basic.stderr
+++ b/tests/ui/underscore-imports/basic.stderr
@@ -1,8 +1,8 @@
-warning: unused import: `m::Tr1 as _`
+warning: unused import: `crate::m::Tr1 as _`
   --> $DIR/basic.rs:26:9
    |
-LL |     use m::Tr1 as _;
-   |         ^^^^^^^^^^^
+LL |     use crate::m::Tr1 as _;
+   |         ^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/basic.rs:4:9
@@ -10,11 +10,11 @@ note: the lint level is defined here
 LL | #![warn(unused_imports, unused_extern_crates)]
    |         ^^^^^^^^^^^^^^
 
-warning: unused import: `S as _`
+warning: unused import: `crate::S as _`
   --> $DIR/basic.rs:27:9
    |
-LL |     use S as _;
-   |         ^^^^^^
+LL |     use crate::S as _;
+   |         ^^^^^^^^^^^^^
 
 warning: 2 warnings emitted
 
diff --git a/tests/ui/unpretty/exhaustive.expanded.stdout b/tests/ui/unpretty/exhaustive.expanded.stdout
index 9712ba58e62..cd1a5d0af08 100644
--- a/tests/ui/unpretty/exhaustive.expanded.stdout
+++ b/tests/ui/unpretty/exhaustive.expanded.stdout
@@ -190,7 +190,7 @@ mod expressions {
         (static async || value);
         (static async move || value);
         || -> u8 { value };
-        1 + (|| {});
+        1 + || {};
     }
 
     /// ExprKind::Block
diff --git a/tests/ui/unresolved/unresolved-import-recovery.rs b/tests/ui/unresolved/unresolved-import-recovery.rs
index 0b0653378cb..8657bb661a8 100644
--- a/tests/ui/unresolved/unresolved-import-recovery.rs
+++ b/tests/ui/unresolved/unresolved-import-recovery.rs
@@ -1,7 +1,7 @@
 // Check that unresolved imports do not create additional errors and ICEs
 
 mod m {
-    pub use unresolved; //~ ERROR unresolved import `unresolved`
+    pub use crate::unresolved; //~ ERROR unresolved import `crate::unresolved`
 
     fn f() {
         let unresolved = 0; // OK
diff --git a/tests/ui/unresolved/unresolved-import-recovery.stderr b/tests/ui/unresolved/unresolved-import-recovery.stderr
index 1c006049756..ec41c9e79d7 100644
--- a/tests/ui/unresolved/unresolved-import-recovery.stderr
+++ b/tests/ui/unresolved/unresolved-import-recovery.stderr
@@ -1,8 +1,8 @@
-error[E0432]: unresolved import `unresolved`
+error[E0432]: unresolved import `crate::unresolved`
   --> $DIR/unresolved-import-recovery.rs:4:13
    |
-LL |     pub use unresolved;
-   |             ^^^^^^^^^^ no `unresolved` in the root
+LL |     pub use crate::unresolved;
+   |             ^^^^^^^^^^^^^^^^^ no `unresolved` in the root
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr b/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr
index b7cbe1a5cf4..2f01331db9a 100644
--- a/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr
+++ b/tests/ui/unsafe/break-inside-unsafe-block-issue-128604.stderr
@@ -1,10 +1,4 @@
 error[E0268]: `break` outside of a loop or labeled block
-  --> $DIR/break-inside-unsafe-block-issue-128604.rs:2:28
-   |
-LL |     let a = ["_"; unsafe { break; 1 + 2 }];
-   |                            ^^^^^ cannot `break` outside of a loop or labeled block
-
-error[E0268]: `break` outside of a loop or labeled block
   --> $DIR/break-inside-unsafe-block-issue-128604.rs:14:9
    |
 LL |         break;
@@ -37,6 +31,12 @@ LL |         unsafe {
 LL ~             break 'block;
    |
 
+error[E0268]: `break` outside of a loop or labeled block
+  --> $DIR/break-inside-unsafe-block-issue-128604.rs:2:28
+   |
+LL |     let a = ["_"; unsafe { break; 1 + 2 }];
+   |                            ^^^^^ cannot `break` outside of a loop or labeled block
+
 error: aborting due to 4 previous errors
 
 For more information about this error, try `rustc --explain E0268`.
diff --git a/tests/ui/unsized/unsized3-rpass.rs b/tests/ui/unsized/unsized3-rpass.rs
index ff35051774b..03aa1a538ea 100644
--- a/tests/ui/unsized/unsized3-rpass.rs
+++ b/tests/ui/unsized/unsized3-rpass.rs
@@ -37,7 +37,7 @@ impl Tr for St {
 }
 
 struct Qux<'a> {
-    f: Tr + 'a,
+    f: dyn Tr + 'a,
 }
 
 pub fn main() {
@@ -85,7 +85,7 @@ pub fn main() {
         }
 
         let obj: Box<St> = Box::new(St { f: 42 });
-        let obj: &Tr = &*obj;
+        let obj: &dyn Tr = &*obj;
         let data: Box<_> = Box::new(Qux_ { f: St { f: 234 } });
         let x: &Qux = &*ptr::from_raw_parts::<Qux>(&*data as *const _, ptr::metadata(obj));
         assert_eq!(x.f.foo(), 234);
diff --git a/tests/ui/use/use-mod/use-mod-4.rs b/tests/ui/use/use-mod/use-mod-4.rs
index 46ae8ddadc0..34ce7c71957 100644
--- a/tests/ui/use/use-mod/use-mod-4.rs
+++ b/tests/ui/use/use-mod/use-mod-4.rs
@@ -1,4 +1,4 @@
-use foo::self; //~ ERROR unresolved import `foo`
+use crate::foo::self; //~ ERROR unresolved import `crate::foo`
 //~^ ERROR `self` imports are only allowed within a { } list
 
 use std::mem::self;
diff --git a/tests/ui/use/use-mod/use-mod-4.stderr b/tests/ui/use/use-mod/use-mod-4.stderr
index 0b4fbadb458..d4621296c0d 100644
--- a/tests/ui/use/use-mod/use-mod-4.stderr
+++ b/tests/ui/use/use-mod/use-mod-4.stderr
@@ -1,18 +1,18 @@
 error[E0429]: `self` imports are only allowed within a { } list
-  --> $DIR/use-mod-4.rs:1:8
+  --> $DIR/use-mod-4.rs:1:15
    |
-LL | use foo::self;
-   |        ^^^^^^
+LL | use crate::foo::self;
+   |               ^^^^^^
    |
 help: consider importing the module directly
    |
-LL - use foo::self;
-LL + use foo;
+LL - use crate::foo::self;
+LL + use crate::foo;
    |
 help: alternatively, use the multi-path `use` syntax to import `self`
    |
-LL | use foo::{self};
-   |          +    +
+LL | use crate::foo::{self};
+   |                 +    +
 
 error[E0429]: `self` imports are only allowed within a { } list
   --> $DIR/use-mod-4.rs:4:13
@@ -30,11 +30,11 @@ help: alternatively, use the multi-path `use` syntax to import `self`
 LL | use std::mem::{self};
    |               +    +
 
-error[E0432]: unresolved import `foo`
+error[E0432]: unresolved import `crate::foo`
   --> $DIR/use-mod-4.rs:1:5
    |
-LL | use foo::self;
-   |     ^^^^^^^^^ no `foo` in the root
+LL | use crate::foo::self;
+   |     ^^^^^^^^^^^^^^^^ no `foo` in the root
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/variance/variance-trait-matching.stderr b/tests/ui/variance/variance-trait-matching.stderr
index 9c72fe239dd..495669668c5 100644
--- a/tests/ui/variance/variance-trait-matching.stderr
+++ b/tests/ui/variance/variance-trait-matching.stderr
@@ -1,11 +1,13 @@
 error[E0621]: explicit lifetime required in the type of `get`
   --> $DIR/variance-trait-matching.rs:24:5
    |
-LL | fn get<'a, G>(get: &G) -> i32
-   |                    -- help: add explicit lifetime `'a` to the type of `get`: `&'a G`
-...
 LL |     pick(get, &22)
    |     ^^^^^^^^^^^^^^ lifetime `'a` required
+   |
+help: add explicit lifetime `'a` to the type of `get`
+   |
+LL | fn get<'a, G>(get: &'a G) -> i32
+   |                     ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/warnings/no-explicit-path-issue-122509.rs b/tests/ui/warnings/no-explicit-path-issue-122509.rs
index 4e8eefde5da..5be4b174076 100644
--- a/tests/ui/warnings/no-explicit-path-issue-122509.rs
+++ b/tests/ui/warnings/no-explicit-path-issue-122509.rs
@@ -7,13 +7,13 @@ fn one() -> usize {
 
 pub mod a {
     pub fn two() -> usize {
-        ::one() + ::one()
+        crate::one() + crate::one()
     }
 }
 
 pub mod b {
     pub fn three() -> usize {
-        ::one() + ::a::two()
+        crate::one() + crate::a::two()
     }
 }
 
diff --git a/tests/ui/weird-exprs.rs b/tests/ui/weird-exprs.rs
index b24e754a4ec..7db92d46067 100644
--- a/tests/ui/weird-exprs.rs
+++ b/tests/ui/weird-exprs.rs
@@ -105,7 +105,7 @@ fn u8(u8: u8) {
 
             u8!(u8);
             let &u8: &u8 = u8::u8(&8u8);
-            ::u8(0u8);
+            crate::u8(0u8);
             u8
         });
     }
diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs
index a95e10b7265..53f07a94fd1 100644
--- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs
+++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.rs
@@ -1,17 +1,11 @@
-trait Trait<const N: Trait = bar> {
+trait Trait<const N: dyn Trait = bar> {
     //~^ ERROR cannot find value `bar` in this scope
     //~| ERROR cycle detected when computing type of `Trait::N`
-    //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
-    //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
-    fn fnc<const N: Trait = u32>(&self) -> Trait {
+    fn fnc<const N: dyn Trait = u32>(&self) -> dyn Trait {
         //~^ ERROR the name `N` is already used for a generic parameter in this item's generic parameters
         //~| ERROR expected value, found builtin type `u32`
         //~| ERROR defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
         //~| ERROR associated item referring to unboxed trait object for its own trait
-        //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
-        //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
-        //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects]
-        //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
         bar
         //~^ ERROR cannot find value `bar` in this scope
     }
diff --git a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr
index 59eef0c6327..a085dd6ac57 100644
--- a/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr
+++ b/tests/ui/wf/ice-hir-wf-check-anon-const-issue-122199.stderr
@@ -1,106 +1,66 @@
 error[E0403]: the name `N` is already used for a generic parameter in this item's generic parameters
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:18
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:4:18
    |
-LL | trait Trait<const N: Trait = bar> {
+LL | trait Trait<const N: dyn Trait = bar> {
    |                   - first use of `N`
 ...
-LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
+LL |     fn fnc<const N: dyn Trait = u32>(&self) -> dyn Trait {
    |                  ^ already used
 
 error[E0425]: cannot find value `bar` in this scope
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:30
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:34
    |
-LL | trait Trait<const N: Trait = bar> {
-   |                              ^^^ not found in this scope
+LL | trait Trait<const N: dyn Trait = bar> {
+   |                                  ^^^ not found in this scope
 
 error[E0423]: expected value, found builtin type `u32`
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:29
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:4:33
    |
-LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
-   |                             ^^^ not a value
+LL |     fn fnc<const N: dyn Trait = u32>(&self) -> dyn Trait {
+   |                                 ^^^ not a value
 
 error[E0425]: cannot find value `bar` in this scope
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:15:9
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:9:9
    |
 LL |         bar
    |         ^^^ not found in this scope
 
-warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:22
-   |
-LL | trait Trait<const N: Trait = bar> {
-   |                      ^^^^^
-   |
-   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
-   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-   = note: `#[warn(bare_trait_objects)]` on by default
-help: if this is a dyn-compatible trait, use `dyn`
-   |
-LL | trait Trait<const N: dyn Trait = bar> {
-   |                      +++
-
 error[E0391]: cycle detected when computing type of `Trait::N`
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:22
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:26
    |
-LL | trait Trait<const N: Trait = bar> {
-   |                      ^^^^^
+LL | trait Trait<const N: dyn Trait = bar> {
+   |                          ^^^^^
    |
    = note: ...which immediately requires computing type of `Trait::N` again
 note: cycle used when computing explicit predicates of trait `Trait`
   --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:1:1
    |
-LL | trait Trait<const N: Trait = bar> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | trait Trait<const N: dyn Trait = bar> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
 
 error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:12
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:4:12
    |
-LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
-   |            ^^^^^^^^^^^^^^^^^^^^
-
-warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:44
-   |
-LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
-   |                                            ^^^^^
-   |
-   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
-   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-help: if this is a dyn-compatible trait, use `dyn`
-   |
-LL |     fn fnc<const N: Trait = u32>(&self) -> dyn Trait {
-   |                                            +++
-
-warning: trait objects without an explicit `dyn` are deprecated
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:21
-   |
-LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
-   |                     ^^^^^
-   |
-   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021!
-   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/warnings-promoted-to-error.html>
-help: if this is a dyn-compatible trait, use `dyn`
-   |
-LL |     fn fnc<const N: dyn Trait = u32>(&self) -> Trait {
-   |                     +++
+LL |     fn fnc<const N: dyn Trait = u32>(&self) -> dyn Trait {
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: associated item referring to unboxed trait object for its own trait
-  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:6:44
+  --> $DIR/ice-hir-wf-check-anon-const-issue-122199.rs:4:48
    |
-LL | trait Trait<const N: Trait = bar> {
+LL | trait Trait<const N: dyn Trait = bar> {
    |       ----- in this trait
 ...
-LL |     fn fnc<const N: Trait = u32>(&self) -> Trait {
-   |                                            ^^^^^
+LL |     fn fnc<const N: dyn Trait = u32>(&self) -> dyn Trait {
+   |                                                ^^^^^^^^^
    |
 help: you might have meant to use `Self` to refer to the implementing type
    |
-LL -     fn fnc<const N: Trait = u32>(&self) -> Trait {
-LL +     fn fnc<const N: Trait = u32>(&self) -> Self {
+LL -     fn fnc<const N: dyn Trait = u32>(&self) -> dyn Trait {
+LL +     fn fnc<const N: dyn Trait = u32>(&self) -> Self {
    |
 
-error: aborting due to 7 previous errors; 3 warnings emitted
+error: aborting due to 7 previous errors
 
 Some errors have detailed explanations: E0391, E0403, E0423, E0425.
 For more information about an error, try `rustc --explain E0391`.
diff --git a/triagebot.toml b/triagebot.toml
index 15c56f8861f..e5af77b6d44 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -44,29 +44,6 @@ remove_labels = ["S-waiting-on-author"]
 # Those labels are added when PR author requests a review from an assignee
 add_labels = ["S-waiting-on-review"]
 
-[ping.icebreakers-llvm]
-message = """\
-Hey LLVM ICE-breakers! This bug has been identified as a good
-"LLVM ICE-breaking candidate". In case it's useful, here are some
-[instructions] for tackling these sorts of bugs. Maybe take a look?
-Thanks! <3
-
-[instructions]: https://rustc-dev-guide.rust-lang.org/notification-groups/llvm.html
-"""
-label = "ICEBreaker-LLVM"
-
-[ping.icebreakers-cleanup-crew]
-alias = ["cleanup", "cleanups", "cleanup-crew", "shrink", "reduce", "bisect"]
-message = """\
-Hey Cleanup Crew ICE-breakers! This bug has been identified as a good
-"Cleanup ICE-breaking candidate". In case it's useful, here are some
-[instructions] for tackling these sorts of bugs. Maybe take a look?
-Thanks! <3
-
-[instructions]: https://rustc-dev-guide.rust-lang.org/notification-groups/cleanup-crew.html
-"""
-label = "ICEBreaker-Cleanup-Crew"
-
 [ping.windows]
 message = """\
 Hey Windows Group! This bug has been identified as a good "Windows candidate".
@@ -729,6 +706,41 @@ don't know
 ]
 message_on_remove = "PR #{number}'s stable-nomination has been removed."
 
+[notify-zulip."beta-nominated".bootstrap]
+required_labels = ["T-bootstrap"]
+zulip_stream = 507486 # #t-infra/bootstrap/backports
+topic = "#{number}: beta-nominated"
+message_on_add = [
+    """\
+@*T-bootstrap* PR #{number} "{title}" has been nominated for beta backport.
+""",
+    """\
+/poll Approve beta backport of #{number}?
+approve
+decline
+don't know
+""",
+]
+message_on_remove = "PR #{number}'s beta-nomination has been removed."
+
+[notify-zulip."stable-nominated".bootstrap]
+required_labels = ["T-bootstrap"]
+zulip_stream = 507486 # #t-infra/bootstrap/backports
+topic = "#{number}: stable-nominated"
+message_on_add = [
+    """\
+@*T-bootstrap* PR #{number} "{title}" has been nominated for stable backport.
+""",
+    """\
+/poll Approve stable backport of #{number}?
+approve
+approve (but does not justify new dot release on its own)
+decline
+don't know
+""",
+]
+message_on_remove = "PR #{number}'s stable-nomination has been removed."
+
 [notify-zulip."A-edition-2021"]
 required_labels = ["C-bug"]
 zulip_stream = 268952 # #edition
@@ -1217,6 +1229,7 @@ compiler = [
     "@oli-obk",
     "@petrochenkov",
     "@SparrowLii",
+    "@WaffleLapkin",
     "@wesleywiser",
 ]
 libs = [
@@ -1228,14 +1241,6 @@ libs = [
     "@thomcc",
     "@ibraheemdev",
 ]
-bootstrap = [
-    "@Mark-Simulacrum",
-    "@albertlarsan68",
-    "@onur-ozkan",
-    "@kobzol",
-    "@jieyouxu",
-    "@clubby789",
-]
 infra-ci = [
     "@Mark-Simulacrum",
     "@Kobzol",
@@ -1255,6 +1260,7 @@ codegen = [
     "@dianqk",
     "@saethlin",
     "@workingjubilee",
+    "@WaffleLapkin",
 ]
 query-system = [
     "@oli-obk",
@@ -1424,8 +1430,8 @@ compiletest = [
 "/src/tools/rustdoc-themes" =                            ["rustdoc"]
 "/src/tools/tidy" =                                      ["bootstrap"]
 "/src/tools/x" =                                         ["bootstrap"]
-"/src/tools/rustdoc-gui-test" =                          ["bootstrap", "@onur-ozkan"]
-"/src/tools/libcxx-version" =                            ["@onur-ozkan"]
+"/src/tools/rustdoc-gui-test" =                          ["bootstrap"]
+"/src/tools/libcxx-version" =                            ["bootstrap"]
 
 # Enable review queue tracking
 # Documentation at: https://forge.rust-lang.org/triagebot/review-queue-tracking.html