about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.editorconfig11
-rw-r--r--.github/workflows/ci.yml6
-rw-r--r--.github/workflows/dependencies.yml4
-rw-r--r--.github/workflows/ghcr.yml2
-rw-r--r--.github/workflows/post-merge.yml2
-rw-r--r--Cargo.lock5
-rw-r--r--compiler/rustc_ast/src/ast.rs21
-rw-r--r--compiler/rustc_ast/src/visit.rs9
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs90
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs12
-rw-r--r--compiler/rustc_ast_passes/messages.ftl5
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs51
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs26
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs8
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/item.rs56
-rw-r--r--compiler/rustc_attr_parsing/messages.ftl1
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/cfg.rs5
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/confusables.rs2
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/deprecation.rs2
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/inline.rs8
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/link_attrs.rs15
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs13
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/must_use.rs5
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/path.rs5
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs8
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/repr.rs8
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs4
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/stability.rs58
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/test_attrs.rs11
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/traits.rs2
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/transparency.rs2
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs5
-rw-r--r--compiler/rustc_attr_parsing/src/session_diagnostics.rs4
-rw-r--r--compiler/rustc_borrowck/src/handle_placeholders.rs2
-rw-r--r--compiler/rustc_borrowck/src/polonius/legacy/facts.rs16
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs13
-rw-r--r--compiler/rustc_borrowck/src/renumber.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs16
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_accessible.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/derive.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs32
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs22
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs12
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs1
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl3
-rw-r--r--compiler/rustc_codegen_ssa/src/back/apple.rs24
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs83
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs21
-rw-r--r--compiler/rustc_const_eval/src/interpret/call.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs4
-rw-r--r--compiler/rustc_const_eval/src/interpret/util.rs14
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs2
-rw-r--r--compiler/rustc_const_eval/src/util/type_name.rs24
-rw-r--r--compiler/rustc_expand/src/base.rs53
-rw-r--r--compiler/rustc_expand/src/expand.rs28
-rw-r--r--compiler/rustc_expand/src/mbe/diagnostics.rs12
-rw-r--r--compiler/rustc_expand/src/mbe/macro_check.rs18
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs26
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs457
-rw-r--r--compiler/rustc_hir/Cargo.toml1
-rw-r--r--compiler/rustc_hir/src/attrs/data_structures.rs3
-rw-r--r--compiler/rustc_hir/src/attrs/encode_cross_crate.rs1
-rw-r--r--compiler/rustc_hir/src/def.rs59
-rw-r--r--compiler/rustc_hir/src/hir.rs35
-rw-r--r--compiler/rustc_hir/src/intravisit.rs26
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs93
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs36
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs17
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/hir_wf_check.rs5
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs61
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs50
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs10
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs11
-rw-r--r--compiler/rustc_interface/src/tests.rs1
-rw-r--r--compiler/rustc_lint/messages.ftl2
-rw-r--r--compiler/rustc_lint/src/builtin.rs25
-rw-r--r--compiler/rustc_lint/src/context.rs16
-rw-r--r--compiler/rustc_lint/src/deref_into_dyn_supertrait.rs4
-rw-r--r--compiler/rustc_lint/src/early/diagnostics.rs14
-rw-r--r--compiler/rustc_lint/src/internal.rs12
-rw-r--r--compiler/rustc_lint/src/lints.rs6
-rw-r--r--compiler/rustc_lint/src/non_local_def.rs8
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs2
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs2
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp7
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/table.rs26
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs7
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs69
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs4
-rw-r--r--compiler/rustc_middle/src/ty/print/mod.rs82
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs109
-rw-r--r--compiler/rustc_mir_transform/src/cross_crate_inline.rs2
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/search_graph.rs4
-rw-r--r--compiler/rustc_parse/messages.ftl5
-rw-r--r--compiler/rustc_parse/src/errors.rs14
-rw-r--r--compiler/rustc_parse/src/parser/item.rs54
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs41
-rw-r--r--compiler/rustc_passes/messages.ftl7
-rw-r--r--compiler/rustc_passes/src/check_attr.rs97
-rw-r--r--compiler/rustc_passes/src/dead.rs8
-rw-r--r--compiler/rustc_passes/src/errors.rs6
-rw-r--r--compiler/rustc_passes/src/reachable.rs5
-rw-r--r--compiler/rustc_passes/src/stability.rs24
-rw-r--r--compiler/rustc_privacy/src/lib.rs3
-rw-r--r--compiler/rustc_resolve/messages.ftl3
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs10
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs4
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs50
-rw-r--r--compiler/rustc_resolve/src/errors.rs6
-rw-r--r--compiler/rustc_resolve/src/ident.rs16
-rw-r--r--compiler/rustc_resolve/src/late.rs14
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs9
-rw-r--r--compiler/rustc_resolve/src/lib.rs10
-rw-r--r--compiler/rustc_resolve/src/macros.rs57
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--compiler/rustc_symbol_mangling/src/export.rs9
-rw-r--r--compiler/rustc_symbol_mangling/src/legacy.rs33
-rw-r--r--compiler/rustc_symbol_mangling/src/lib.rs55
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs28
-rw-r--r--compiler/rustc_target/src/spec/base/apple/mod.rs24
-rw-r--r--compiler/rustc_target/src/spec/mod.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/aarch64_be_unknown_none_softfloat.rs43
-rw-r--r--compiler/rustc_target/src/spec/targets/avr_none.rs2
-rw-r--r--compiler/rustc_target/src/target_features.rs4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs43
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs74
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs17
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs4
-rw-r--r--compiler/rustc_ty_utils/src/implied_bounds.rs8
-rw-r--r--compiler/rustc_ty_utils/src/sig_types.rs2
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs6
-rw-r--r--compiler/rustc_type_ir/src/search_graph/mod.rs289
-rw-r--r--compiler/rustc_type_ir/src/search_graph/stack.rs27
-rw-r--r--library/alloc/src/lib.rs1
-rw-r--r--library/alloc/src/vec/mod.rs74
-rw-r--r--library/core/src/alloc/layout.rs8
-rw-r--r--library/core/src/ascii/ascii_char.rs612
-rw-r--r--library/core/src/iter/adapters/map_windows.rs2
-rw-r--r--library/core/src/ops/range.rs2
-rw-r--r--library/core/src/ptr/const_ptr.rs22
-rw-r--r--library/core/src/ptr/mod.rs16
-rw-r--r--library/core/src/ptr/mut_ptr.rs25
-rw-r--r--library/core/src/ptr/non_null.rs30
-rw-r--r--library/core/src/ptr/unique.rs8
-rw-r--r--library/std/src/lib.rs7
-rw-r--r--library/std/src/panic.rs2
-rw-r--r--library/std/src/path.rs3
-rw-r--r--library/std/src/sys/fs/windows.rs2
-rw-r--r--library/std/src/sys/pal/hermit/time.rs32
-rw-r--r--library/std/src/sys/pal/sgx/time.rs15
-rw-r--r--library/std/src/sys/pal/solid/time.rs9
-rw-r--r--library/std/src/sys/pal/uefi/tests.rs57
-rw-r--r--library/std/src/sys/pal/uefi/time.rs178
-rw-r--r--library/std/src/sys/pal/unix/time.rs30
-rw-r--r--library/std/src/sys/pal/unsupported/time.rs15
-rw-r--r--library/std/src/sys/pal/wasi/time.rs25
-rw-r--r--library/std/src/sys/pal/windows/time.rs30
-rw-r--r--library/std/src/sys/pal/xous/time.rs15
-rw-r--r--library/std/src/time.rs30
-rw-r--r--library/std/tests/path.rs8
-rw-r--r--library/test/src/cli.rs17
-rw-r--r--src/bootstrap/Cargo.lock4
-rw-r--r--src/bootstrap/Cargo.toml2
-rw-r--r--src/bootstrap/src/bin/rustc.rs2
-rw-r--r--src/bootstrap/src/bin/rustdoc.rs4
-rw-r--r--src/bootstrap/src/core/build_steps/check.rs38
-rw-r--r--src/bootstrap/src/core/build_steps/clean.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/clippy.rs57
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs229
-rw-r--r--src/bootstrap/src/core/build_steps/dist.rs52
-rw-r--r--src/bootstrap/src/core/build_steps/doc.rs33
-rw-r--r--src/bootstrap/src/core/build_steps/gcc.rs27
-rw-r--r--src/bootstrap/src/core/build_steps/install.rs9
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs91
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs42
-rw-r--r--src/bootstrap/src/core/builder/mod.rs2
-rw-r--r--src/bootstrap/src/core/config/config.rs2
-rw-r--r--src/bootstrap/src/core/sanity.rs1
-rw-r--r--src/bootstrap/src/lib.rs139
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/bootstrap/src/utils/shared_helpers.rs5
-rw-r--r--src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile2
-rwxr-xr-xsrc/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh2
-rw-r--r--src/ci/docker/host-x86_64/pr-check-2/Dockerfile6
-rw-r--r--src/ci/github-actions/jobs.yml2
-rwxr-xr-xsrc/ci/run.sh3
m---------src/doc/reference0
m---------src/doc/rust-by-example0
-rw-r--r--src/doc/rustc-dev-guide/src/building/optimized-build.md2
-rw-r--r--src/doc/rustc-dev-guide/src/stability.md7
-rw-r--r--src/doc/rustc/src/SUMMARY.md1
-rw-r--r--src/doc/rustc/src/platform-support.md1
-rw-r--r--src/doc/rustc/src/platform-support/aarch64_be-unknown-none-softfloat.md74
-rw-r--r--src/doc/rustc/src/tests/index.md8
-rw-r--r--src/doc/unstable-book/src/compiler-environment-variables/SDKROOT.md2
-rw-r--r--src/doc/unstable-book/src/compiler-flags/codegen-source-order.md12
-rw-r--r--src/librustdoc/clean/inline.rs53
-rw-r--r--src/librustdoc/clean/mod.rs23
-rw-r--r--src/librustdoc/formats/item_type.rs9
-rw-r--r--src/librustdoc/html/render/print_item.rs8
-rw-r--r--src/librustdoc/passes/collect_intra_doc_links.rs44
-rw-r--r--src/librustdoc/visit_ast.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/copy_iterator.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/derivable_impls.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_drop.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/error_impl_error.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/format_impl.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/from_over_into.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/infallible_try_from.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/item_name_repetitions.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_inline.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_trait_methods.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/op_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/same_name_method.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/serde_api.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/to_string_trait_impl.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unconditional_recursion.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils/mod.rs26
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs3
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs3
-rw-r--r--src/tools/clippy/tests/missing-test-files.rs2
-rw-r--r--src/tools/clippy/tests/ui/bool_assert_comparison.fixed24
-rw-r--r--src/tools/clippy/tests/ui/bool_assert_comparison.rs18
-rw-r--r--src/tools/clippy/tests/ui/bool_assert_comparison.stderr134
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-96721.stderr2
-rw-r--r--src/tools/compiletest/src/runtest.rs4
-rw-r--r--src/tools/miri/src/bin/miri.rs2
-rw-r--r--src/tools/miri/src/borrow_tracker/mod.rs24
-rw-r--r--src/tools/miri/src/helpers.rs2
-rw-r--r--src/tools/opt-dist/Cargo.toml2
-rw-r--r--src/tools/opt-dist/src/tests.rs10
-rw-r--r--src/tools/run-make-support/src/external_deps/rustc.rs6
-rw-r--r--src/tools/rustfmt/src/items.rs51
-rw-r--r--src/tools/rustfmt/tests/source/negative-impl.rs4
-rw-r--r--src/tools/rustfmt/tests/target/negative-impl.rs8
-rw-r--r--tests/assembly-llvm/asm/aarch64-outline-atomics.rs4
-rw-r--r--tests/assembly-llvm/targets/targets-elf.rs3
-rw-r--r--tests/codegen-llvm/addr-of-mutate.rs6
-rw-r--r--tests/codegen-llvm/dead_on_return.rs31
-rw-r--r--tests/codegen-llvm/function-arguments.rs2
-rw-r--r--tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs2
-rw-r--r--tests/run-make/link-under-xcode/foo.rs1
-rw-r--r--tests/run-make/link-under-xcode/rmake.rs32
-rw-r--r--tests/run-make/pgo-branch-weights/rmake.rs11
-rw-r--r--tests/run-make/pgo-indirect-call-promotion/rmake.rs13
-rw-r--r--tests/run-make/pgo-use/rmake.rs2
-rw-r--r--tests/run-make/wasm-panic-small/rmake.rs2
-rw-r--r--tests/rustdoc-ui/intra-doc/github-flavored-admonitions.rs6
-rw-r--r--tests/rustdoc/enum/enum-variant-value.rs22
-rw-r--r--tests/ui/argument-suggestions/issue-100478.stderr16
-rw-r--r--tests/ui/async-await/drop-live-upvar-2.may_not_dangle.stderr18
-rw-r--r--tests/ui/async-await/drop-live-upvar-2.rs37
-rw-r--r--tests/ui/async-await/drop-live-upvar.rs23
-rw-r--r--tests/ui/async-await/drop-live-upvar.stderr22
-rw-r--r--tests/ui/async-await/recursive-async-auto-trait-overflow.rs14
-rw-r--r--tests/ui/attributes/crate-name-macro-call.stderr2
-rw-r--r--tests/ui/attributes/crate-type-delimited.stderr19
-rw-r--r--tests/ui/attributes/crate-type-empty.stderr15
-rw-r--r--tests/ui/attributes/crate-type-macro-call.stderr19
-rw-r--r--tests/ui/attributes/invalid-macro-use.rs4
-rw-r--r--tests/ui/attributes/invalid-macro-use.stderr26
-rw-r--r--tests/ui/attributes/invalid-reprs.stderr1
-rw-r--r--tests/ui/attributes/lint_on_root.rs2
-rw-r--r--tests/ui/attributes/lint_on_root.stderr4
-rw-r--r--tests/ui/attributes/malformed-attrs.rs2
-rw-r--r--tests/ui/attributes/malformed-attrs.stderr210
-rw-r--r--tests/ui/attributes/malformed-reprs.stderr22
-rw-r--r--tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr15
-rw-r--r--tests/ui/attributes/used_with_multi_args.stderr5
-rw-r--r--tests/ui/cfg/cfg-target-compact-errors.stderr8
-rw-r--r--tests/ui/check-cfg/target_feature.stderr1
-rw-r--r--tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs5
-rw-r--r--tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr28
-rw-r--r--tests/ui/deprecation/deprecation-sanity.stderr48
-rw-r--r--tests/ui/dist/cranelift-x86_64-unknown-linux-gnu-dist.rs11
-rw-r--r--tests/ui/error-codes/E0197.stderr2
-rw-r--r--tests/ui/error-codes/E0540.stderr7
-rw-r--r--tests/ui/error-codes/E0565-1.stderr8
-rw-r--r--tests/ui/extern/issue-47725.rs1
-rw-r--r--tests/ui/extern/issue-47725.stderr2
-rw-r--r--tests/ui/feature-gates/feature-gate-optimize_attribute.stderr17
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr4
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs5
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr324
-rw-r--r--tests/ui/fn/fn-arg-count-mismatch-diagnostics.rs12
-rw-r--r--tests/ui/fn/fn-arg-count-mismatch-diagnostics.stderr28
-rw-r--r--tests/ui/infinite/issue-41731-infinite-macro-print.rs2
-rw-r--r--tests/ui/infinite/issue-41731-infinite-macro-print.stderr6
-rw-r--r--tests/ui/infinite/issue-41731-infinite-macro-println.rs2
-rw-r--r--tests/ui/infinite/issue-41731-infinite-macro-println.stderr6
-rw-r--r--tests/ui/intrinsics/bad-intrinsic-monomorphization.stderr16
-rw-r--r--tests/ui/intrinsics/non-integer-atomic.stderr88
-rw-r--r--tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stderr2
-rw-r--r--tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stderr2
-rw-r--r--tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stderr2
-rw-r--r--tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stderr2
-rw-r--r--tests/ui/invalid/invalid-inline.stderr13
-rw-r--r--tests/ui/issues/issue-43988.stderr50
-rw-r--r--tests/ui/link-native-libs/link-attr-validation-early.rs4
-rw-r--r--tests/ui/link-native-libs/link-attr-validation-early.stderr12
-rw-r--r--tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-invalid-format.stderr4
-rw-r--r--tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.rs2
-rw-r--r--tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.stderr6
-rw-r--r--tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-too-many-arguments.rs2
-rw-r--r--tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-too-many-arguments.stderr6
-rw-r--r--tests/ui/lint/dead-code/self-assign.rs17
-rw-r--r--tests/ui/lint/dead-code/self-assign.stderr44
-rw-r--r--tests/ui/lint/lint-malformed.stderr15
-rw-r--r--tests/ui/lint/unused/unused_attributes-must_use.fixed139
-rw-r--r--tests/ui/lint/unused/unused_attributes-must_use.rs3
-rw-r--r--tests/ui/lint/unused/unused_attributes-must_use.stderr64
-rw-r--r--tests/ui/macros/macro-rules-attr-error.rs39
-rw-r--r--tests/ui/macros/macro-rules-attr-error.stderr55
-rw-r--r--tests/ui/macros/macro-use-bad-args-1.stderr1
-rw-r--r--tests/ui/macros/macro-use-bad-args-2.stderr1
-rw-r--r--tests/ui/malformed/malformed-regressions.rs4
-rw-r--r--tests/ui/malformed/malformed-regressions.stderr22
-rw-r--r--tests/ui/modules/path-invalid-form.stderr2
-rw-r--r--tests/ui/modules/path-macro.stderr2
-rw-r--r--tests/ui/parser/bad-lit-suffixes.stderr1
-rw-r--r--tests/ui/parser/default-on-wrong-item-kind.rs8
-rw-r--r--tests/ui/parser/default-on-wrong-item-kind.stderr42
-rw-r--r--tests/ui/proc-macro/attribute.rs16
-rw-r--r--tests/ui/proc-macro/attribute.stderr268
-rw-r--r--tests/ui/proc-macro/macro-namespace-reserved-2.stderr8
-rw-r--r--tests/ui/recursion_limit/invalid_digit_type.stderr2
-rw-r--r--tests/ui/recursion_limit/invalid_macro.stderr2
-rw-r--r--tests/ui/recursion_limit/no-value.stderr2
-rw-r--r--tests/ui/repr/invalid_repr_list_help.stderr5
-rw-r--r--tests/ui/repr/repr.stderr62
-rw-r--r--tests/ui/resolve/path-attr-in-const-block.stderr2
-rw-r--r--tests/ui/span/E0539.stderr6
-rw-r--r--tests/ui/specialization/defaultimpl/validation.rs2
-rw-r--r--tests/ui/specialization/defaultimpl/validation.stderr4
-rw-r--r--tests/ui/test-attrs/test-should-panic-attr.rs4
-rw-r--r--tests/ui/test-attrs/test-should-panic-attr.stderr10
-rw-r--r--tests/ui/trait-bounds/more_maybe_bounds.rs8
-rw-r--r--tests/ui/trait-bounds/more_maybe_bounds.stderr6
-rw-r--r--tests/ui/traits/const-traits/inherent-impl.rs4
-rw-r--r--tests/ui/traits/const-traits/inherent-impl.stderr8
-rw-r--r--tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr26
-rw-r--r--tests/ui/traits/const-traits/span-bug-issue-121418.rs2
-rw-r--r--tests/ui/traits/const-traits/span-bug-issue-121418.stderr4
-rw-r--r--tests/ui/traits/safety-inherent-impl.stderr2
-rw-r--r--tests/ui/traits/syntax-trait-polarity.stderr20
-rw-r--r--tests/ui/unpretty/exhaustive.hir.stdout2
-rw-r--r--tests/ui/unsized/relaxed-bounds-invalid-places.rs4
-rw-r--r--tests/ui/unsized/relaxed-bounds-invalid-places.stderr18
-rw-r--r--tests/ui/unstable-feature-bound/unstable_feature_bound_on_trait.fail.stderr18
-rw-r--r--tests/ui/unstable-feature-bound/unstable_feature_bound_on_trait.rs33
-rw-r--r--tests/ui/unstable-feature-bound/unstable_inherent_method.rs4
-rw-r--r--tests/ui/unstable-feature-bound/unstable_inherent_method.stderr8
-rw-r--r--triagebot.toml1
389 files changed, 5863 insertions, 2647 deletions
diff --git a/.editorconfig b/.editorconfig
index ef8ed24c52a..1b137cf4ebe 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -7,9 +7,18 @@ root = true
 [*]
 end_of_line = lf
 charset = utf-8
-trim_trailing_whitespace = true
 insert_final_newline = true
 
+# some tests need trailing whitespace in output snapshots
+[!tests/]
+trim_trailing_whitespace = true
+# for actual source code files of test, we still don't want trailing whitespace
+[tests/**.{rs,js}]
+trim_trailing_whitespace = true
+# these specific source files need to have trailing whitespace.
+[tests/ui/{frontmatter/frontmatter-whitespace-3.rs,parser/shebang/shebang-space.rs}]
+trim_trailing_whitespace = false
+
 [!src/llvm-project]
 indent_style = space
 indent_size = 4
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 6ce543071d8..df5dda76eb7 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -52,7 +52,7 @@ jobs:
       run_type: ${{ steps.jobs.outputs.run_type }}
     steps:
       - name: Checkout the source code
-        uses: actions/checkout@v4
+        uses: actions/checkout@v5
       - name: Test citool
         # Only test citool on the auto branch, to reduce latency of the calculate matrix job
         # on PR/try builds.
@@ -113,7 +113,7 @@ jobs:
         run: git config --global core.autocrlf false
 
       - name: checkout the source code
-        uses: actions/checkout@v4
+        uses: actions/checkout@v5
         with:
           fetch-depth: 2
 
@@ -313,7 +313,7 @@ jobs:
     if: ${{ !cancelled() && contains(fromJSON('["auto", "try"]'), needs.calculate_matrix.outputs.run_type) }}
     steps:
       - name: checkout the source code
-        uses: actions/checkout@v4
+        uses: actions/checkout@v5
         with:
           fetch-depth: 2
       # Calculate the exit status of the whole CI workflow.
diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml
index 9d4b6192d6e..80ffd67e04e 100644
--- a/.github/workflows/dependencies.yml
+++ b/.github/workflows/dependencies.yml
@@ -51,7 +51,7 @@ jobs:
     runs-on: ubuntu-24.04
     steps:
       - name: checkout the source code
-        uses: actions/checkout@v4
+        uses: actions/checkout@v5
         with:
           submodules: recursive
       - name: install the bootstrap toolchain
@@ -101,7 +101,7 @@ jobs:
       pull-requests: write
     steps:
       - name: checkout the source code
-        uses: actions/checkout@v4
+        uses: actions/checkout@v5
 
       - name: download Cargo.lock from update job
         uses: actions/download-artifact@v4
diff --git a/.github/workflows/ghcr.yml b/.github/workflows/ghcr.yml
index 6d050d98cb2..a89867efe66 100644
--- a/.github/workflows/ghcr.yml
+++ b/.github/workflows/ghcr.yml
@@ -29,7 +29,7 @@ jobs:
       # Needed to write to the ghcr.io registry
       packages: write
     steps:
-      - uses: actions/checkout@v4
+      - uses: actions/checkout@v5
         with:
           persist-credentials: false
 
diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml
index ca088ba31fd..12ff4be4f1e 100644
--- a/.github/workflows/post-merge.yml
+++ b/.github/workflows/post-merge.yml
@@ -15,7 +15,7 @@ jobs:
     permissions:
       pull-requests: write
     steps:
-      - uses: actions/checkout@v4
+      - uses: actions/checkout@v5
         with:
           # Make sure that we have enough commits to find the parent merge commit.
           # Since all merges should be through merge commits, fetching two commits
diff --git a/Cargo.lock b/Cargo.lock
index dbb76ada837..8a878faecbc 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3889,6 +3889,7 @@ dependencies = [
 name = "rustc_hir"
 version = "0.0.0"
 dependencies = [
+ "bitflags",
  "odht",
  "rustc_abi",
  "rustc_arena",
@@ -5284,9 +5285,9 @@ dependencies = [
 
 [[package]]
 name = "sysinfo"
-version = "0.36.1"
+version = "0.37.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "252800745060e7b9ffb7b2badbd8b31cfa4aa2e61af879d0a3bf2a317c20217d"
+checksum = "07cec4dc2d2e357ca1e610cfb07de2fa7a10fc3e9fe89f72545f3d244ea87753"
 dependencies = [
  "libc",
  "objc2-core-foundation",
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 8160ed3cc46..87c9c797ea5 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -3661,15 +3661,19 @@ pub struct TyAlias {
 
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Impl {
+    pub generics: Generics,
+    pub of_trait: Option<Box<TraitImplHeader>>,
+    pub self_ty: Box<Ty>,
+    pub items: ThinVec<Box<AssocItem>>,
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct TraitImplHeader {
     pub defaultness: Defaultness,
     pub safety: Safety,
-    pub generics: Generics,
     pub constness: Const,
     pub polarity: ImplPolarity,
-    /// The trait being implemented, if any.
-    pub of_trait: Option<TraitRef>,
-    pub self_ty: Box<Ty>,
-    pub items: ThinVec<Box<AssocItem>>,
+    pub trait_ref: TraitRef,
 }
 
 #[derive(Clone, Encodable, Decodable, Debug, Default, Walkable)]
@@ -3793,7 +3797,7 @@ pub enum ItemKind {
     /// An implementation.
     ///
     /// E.g., `impl<A> Foo<A> { .. }` or `impl<A> Trait for Foo<A> { .. }`.
-    Impl(Box<Impl>),
+    Impl(Impl),
     /// A macro invocation.
     ///
     /// E.g., `foo!(..)`.
@@ -3880,7 +3884,7 @@ impl ItemKind {
             | Self::Union(_, generics, _)
             | Self::Trait(box Trait { generics, .. })
             | Self::TraitAlias(_, generics, _)
-            | Self::Impl(box Impl { generics, .. }) => Some(generics),
+            | Self::Impl(Impl { generics, .. }) => Some(generics),
             _ => None,
         }
     }
@@ -4040,7 +4044,7 @@ mod size_asserts {
     static_assert_size!(GenericArg, 24);
     static_assert_size!(GenericBound, 88);
     static_assert_size!(Generics, 40);
-    static_assert_size!(Impl, 136);
+    static_assert_size!(Impl, 64);
     static_assert_size!(Item, 144);
     static_assert_size!(ItemKind, 80);
     static_assert_size!(LitKind, 24);
@@ -4053,6 +4057,7 @@ mod size_asserts {
     static_assert_size!(PathSegment, 24);
     static_assert_size!(Stmt, 32);
     static_assert_size!(StmtKind, 16);
+    static_assert_size!(TraitImplHeader, 80);
     static_assert_size!(Ty, 64);
     static_assert_size!(TyKind, 40);
     // tidy-alphabetical-end
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 5fdce27db53..68b3d2b0368 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -929,8 +929,13 @@ macro_rules! common_visitor_and_walkers {
         }
 
         impl_walkable!(|&$($mut)? $($lt)? self: Impl, vis: &mut V| {
-            let Impl { defaultness, safety, generics, constness, polarity, of_trait, self_ty, items } = self;
-            visit_visitable!($($mut)? vis, defaultness, safety, generics, constness, polarity, of_trait, self_ty);
+            let Impl { generics, of_trait, self_ty, items } = self;
+            try_visit!(vis.visit_generics(generics));
+            if let Some(box of_trait) = of_trait {
+                let TraitImplHeader { defaultness, safety, constness, polarity, trait_ref } = of_trait;
+                visit_visitable!($($mut)? vis, defaultness, safety, constness, polarity, trait_ref);
+            }
+            try_visit!(vis.visit_ty(self_ty));
             visit_visitable_with!($($mut)? vis, items, AssocCtxt::Impl { of_trait: of_trait.is_some() });
             V::Result::output()
         });
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index ac6fac4c08e..2cd2c41928e 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -340,13 +340,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 );
                 hir::ItemKind::Union(ident, generics, vdata)
             }
-            ItemKind::Impl(box Impl {
-                safety,
-                polarity,
-                defaultness,
-                constness,
+            ItemKind::Impl(Impl {
                 generics: ast_generics,
-                of_trait: trait_ref,
+                of_trait,
                 self_ty: ty,
                 items: impl_items,
             }) => {
@@ -364,54 +360,30 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 // lifetime to be added, but rather a reference to a
                 // parent lifetime.
                 let itctx = ImplTraitContext::Universal;
-                let (generics, (trait_ref, lowered_ty)) =
+                let (generics, (of_trait, lowered_ty)) =
                     self.lower_generics(ast_generics, id, itctx, |this| {
-                        let modifiers = TraitBoundModifiers {
-                            constness: BoundConstness::Never,
-                            asyncness: BoundAsyncness::Normal,
-                            // we don't use this in bound lowering
-                            polarity: BoundPolarity::Positive,
-                        };
-
-                        let trait_ref = trait_ref.as_ref().map(|trait_ref| {
-                            this.lower_trait_ref(
-                                modifiers,
-                                trait_ref,
-                                ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
-                            )
-                        });
+                        let of_trait = of_trait
+                            .as_deref()
+                            .map(|of_trait| this.lower_trait_impl_header(of_trait));
 
                         let lowered_ty = this.lower_ty(
                             ty,
                             ImplTraitContext::Disallowed(ImplTraitPosition::ImplSelf),
                         );
 
-                        (trait_ref, lowered_ty)
+                        (of_trait, lowered_ty)
                     });
 
                 let new_impl_items = self
                     .arena
                     .alloc_from_iter(impl_items.iter().map(|item| self.lower_impl_item_ref(item)));
 
-                // `defaultness.has_value()` is never called for an `impl`, always `true` in order
-                // to not cause an assertion failure inside the `lower_defaultness` function.
-                let has_val = true;
-                let (defaultness, defaultness_span) = self.lower_defaultness(*defaultness, has_val);
-                let polarity = match polarity {
-                    ImplPolarity::Positive => ImplPolarity::Positive,
-                    ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(*s)),
-                };
-                hir::ItemKind::Impl(self.arena.alloc(hir::Impl {
-                    constness: self.lower_constness(*constness),
-                    safety: self.lower_safety(*safety, hir::Safety::Safe),
-                    polarity,
-                    defaultness,
-                    defaultness_span,
+                hir::ItemKind::Impl(hir::Impl {
                     generics,
-                    of_trait: trait_ref,
+                    of_trait,
                     self_ty: lowered_ty,
                     items: new_impl_items,
-                }))
+                })
             }
             ItemKind::Trait(box Trait {
                 constness,
@@ -464,14 +436,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 let body = Box::new(self.lower_delim_args(body));
                 let def_id = self.local_def_id(id);
                 let def_kind = self.tcx.def_kind(def_id);
-                let DefKind::Macro(macro_kind) = def_kind else {
+                let DefKind::Macro(macro_kinds) = def_kind else {
                     unreachable!(
                         "expected DefKind::Macro for macro item, found {}",
                         def_kind.descr(def_id.to_def_id())
                     );
                 };
                 let macro_def = self.arena.alloc(ast::MacroDef { body, macro_rules: *macro_rules });
-                hir::ItemKind::Macro(ident, macro_def, macro_kind)
+                hir::ItemKind::Macro(ident, macro_def, macro_kinds)
             }
             ItemKind::Delegation(box delegation) => {
                 let delegation_results = self.lower_delegation(delegation, id, false);
@@ -982,6 +954,44 @@ impl<'hir> LoweringContext<'_, 'hir> {
         self.expr(span, hir::ExprKind::Err(guar))
     }
 
+    fn lower_trait_impl_header(
+        &mut self,
+        trait_impl_header: &TraitImplHeader,
+    ) -> &'hir hir::TraitImplHeader<'hir> {
+        let TraitImplHeader { constness, safety, polarity, defaultness, ref trait_ref } =
+            *trait_impl_header;
+        let constness = self.lower_constness(constness);
+        let safety = self.lower_safety(safety, hir::Safety::Safe);
+        let polarity = match polarity {
+            ImplPolarity::Positive => ImplPolarity::Positive,
+            ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(s)),
+        };
+        // `defaultness.has_value()` is never called for an `impl`, always `true` in order
+        // to not cause an assertion failure inside the `lower_defaultness` function.
+        let has_val = true;
+        let (defaultness, defaultness_span) = self.lower_defaultness(defaultness, has_val);
+        let modifiers = TraitBoundModifiers {
+            constness: BoundConstness::Never,
+            asyncness: BoundAsyncness::Normal,
+            // we don't use this in bound lowering
+            polarity: BoundPolarity::Positive,
+        };
+        let trait_ref = self.lower_trait_ref(
+            modifiers,
+            trait_ref,
+            ImplTraitContext::Disallowed(ImplTraitPosition::Trait),
+        );
+
+        self.arena.alloc(hir::TraitImplHeader {
+            constness,
+            safety,
+            polarity,
+            defaultness,
+            defaultness_span,
+            trait_ref,
+        })
+    }
+
     fn lower_impl_item(
         &mut self,
         i: &AssocItem,
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 64c1b53f633..465d9dc82bc 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -296,6 +296,7 @@ enum RelaxedBoundPolicy<'a> {
 enum RelaxedBoundForbiddenReason {
     TraitObjectTy,
     SuperTrait,
+    AssocTyBounds,
     LateBoundVarsInScope,
 }
 
@@ -1109,9 +1110,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         &*self.arena.alloc(self.ty(constraint.span, hir::TyKind::Err(guar)));
                     hir::AssocItemConstraintKind::Equality { term: err_ty.into() }
                 } else {
-                    // FIXME(#135229): These should be forbidden!
-                    let bounds =
-                        self.lower_param_bounds(bounds, RelaxedBoundPolicy::Allowed, itctx);
+                    let bounds = self.lower_param_bounds(
+                        bounds,
+                        RelaxedBoundPolicy::Forbidden(RelaxedBoundForbiddenReason::AssocTyBounds),
+                        itctx,
+                    );
                     hir::AssocItemConstraintKind::Bound { bounds }
                 }
             }
@@ -2124,7 +2127,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         diag.emit();
                         return;
                     }
-                    RelaxedBoundForbiddenReason::LateBoundVarsInScope => {}
+                    RelaxedBoundForbiddenReason::AssocTyBounds
+                    | RelaxedBoundForbiddenReason::LateBoundVarsInScope => {}
                 };
             }
         }
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 53e64439afc..340a1a239c5 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -175,11 +175,6 @@ ast_passes_generic_default_trailing = generic parameters with a default must be
 ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
     .help = remove one of these features
 
-ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation}
-    .because = {$annotation} because of this
-    .type = inherent impl for this type
-    .only_trait = only trait implementations may be annotated with {$annotation}
-
 ast_passes_item_invalid_safety = items outside of `unsafe extern {"{ }"}` cannot be declared with `safe` safety qualifier
     .suggestion = remove safe from this item
 
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 9d3b0969ef3..dc2eb17589c 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -954,13 +954,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         }
 
         match &item.kind {
-            ItemKind::Impl(box Impl {
-                safety,
-                polarity,
-                defaultness: _,
-                constness,
+            ItemKind::Impl(Impl {
                 generics,
-                of_trait: Some(t),
+                of_trait:
+                    Some(box TraitImplHeader {
+                        safety,
+                        polarity,
+                        defaultness: _,
+                        constness,
+                        trait_ref: t,
+                    }),
                 self_ty,
                 items,
             }) => {
@@ -992,46 +995,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     walk_list!(this, visit_assoc_item, items, AssocCtxt::Impl { of_trait: true });
                 });
             }
-            ItemKind::Impl(box Impl {
-                safety,
-                polarity,
-                defaultness,
-                constness,
-                generics,
-                of_trait: None,
-                self_ty,
-                items,
-            }) => {
-                let error = |annotation_span, annotation, only_trait| errors::InherentImplCannot {
-                    span: self_ty.span,
-                    annotation_span,
-                    annotation,
-                    self_ty: self_ty.span,
-                    only_trait,
-                };
-
+            ItemKind::Impl(Impl { generics, of_trait: None, self_ty, items }) => {
                 self.visit_attrs_vis(&item.attrs, &item.vis);
                 self.visibility_not_permitted(
                     &item.vis,
                     errors::VisibilityNotPermittedNote::IndividualImplItems,
                 );
-                if let &Safety::Unsafe(span) = safety {
-                    self.dcx().emit_err(errors::InherentImplCannotUnsafe {
-                        span: self_ty.span,
-                        annotation_span: span,
-                        annotation: "unsafe",
-                        self_ty: self_ty.span,
-                    });
-                }
-                if let &ImplPolarity::Negative(span) = polarity {
-                    self.dcx().emit_err(error(span, "negative", false));
-                }
-                if let &Defaultness::Default(def_span) = defaultness {
-                    self.dcx().emit_err(error(def_span, "`default`", true));
-                }
-                if let &Const::Yes(span) = constness {
-                    self.dcx().emit_err(error(span, "`const`", true));
-                }
 
                 self.with_tilde_const(Some(TildeConstReason::Impl { span: item.span }), |this| {
                     this.visit_generics(generics)
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 60f47490f12..1cb2493afe8 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -465,32 +465,6 @@ pub(crate) struct UnsafeNegativeImpl {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes_inherent_cannot_be)]
-pub(crate) struct InherentImplCannot<'a> {
-    #[primary_span]
-    pub span: Span,
-    #[label(ast_passes_because)]
-    pub annotation_span: Span,
-    pub annotation: &'a str,
-    #[label(ast_passes_type)]
-    pub self_ty: Span,
-    #[note(ast_passes_only_trait)]
-    pub only_trait: bool,
-}
-
-#[derive(Diagnostic)]
-#[diag(ast_passes_inherent_cannot_be, code = E0197)]
-pub(crate) struct InherentImplCannotUnsafe<'a> {
-    #[primary_span]
-    pub span: Span,
-    #[label(ast_passes_because)]
-    pub annotation_span: Span,
-    pub annotation: &'a str,
-    #[label(ast_passes_type)]
-    pub self_ty: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(ast_passes_unsafe_item)]
 pub(crate) struct UnsafeItem {
     #[primary_span]
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 662357ce884..c9344a76a7b 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -217,18 +217,18 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 }
             }
 
-            ast::ItemKind::Impl(box ast::Impl { polarity, defaultness, of_trait, .. }) => {
-                if let &ast::ImplPolarity::Negative(span) = polarity {
+            ast::ItemKind::Impl(ast::Impl { of_trait: Some(of_trait), .. }) => {
+                if let ast::ImplPolarity::Negative(span) = of_trait.polarity {
                     gate!(
                         &self,
                         negative_impls,
-                        span.to(of_trait.as_ref().map_or(span, |t| t.path.span)),
+                        span.to(of_trait.trait_ref.path.span),
                         "negative trait bounds are not fully implemented; \
                          use marker types for now"
                     );
                 }
 
-                if let ast::Defaultness::Default(_) = defaultness {
+                if let ast::Defaultness::Default(_) = of_trait.defaultness {
                     gate!(&self, specialization, i.span, "specialization is unstable");
                 }
             }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 6e34d1b61db..ab402cbb8dc 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -308,39 +308,41 @@ impl<'a> State<'a> {
                 let (cb, ib) = self.head(visibility_qualified(&item.vis, "union"));
                 self.print_struct(struct_def, generics, *ident, item.span, true, cb, ib);
             }
-            ast::ItemKind::Impl(box ast::Impl {
-                safety,
-                polarity,
-                defaultness,
-                constness,
-                generics,
-                of_trait,
-                self_ty,
-                items,
-            }) => {
+            ast::ItemKind::Impl(ast::Impl { generics, of_trait, self_ty, items }) => {
                 let (cb, ib) = self.head("");
                 self.print_visibility(&item.vis);
-                self.print_defaultness(*defaultness);
-                self.print_safety(*safety);
-                self.word("impl");
-
-                if generics.params.is_empty() {
-                    self.nbsp();
-                } else {
-                    self.print_generic_params(&generics.params);
-                    self.space();
-                }
 
-                self.print_constness(*constness);
+                let impl_generics = |this: &mut Self| {
+                    this.word("impl");
 
-                if let ast::ImplPolarity::Negative(_) = polarity {
-                    self.word("!");
-                }
-
-                if let Some(t) = of_trait {
-                    self.print_trait_ref(t);
+                    if generics.params.is_empty() {
+                        this.nbsp();
+                    } else {
+                        this.print_generic_params(&generics.params);
+                        this.space();
+                    }
+                };
+
+                if let Some(box of_trait) = of_trait {
+                    let ast::TraitImplHeader {
+                        defaultness,
+                        safety,
+                        constness,
+                        polarity,
+                        ref trait_ref,
+                    } = *of_trait;
+                    self.print_defaultness(defaultness);
+                    self.print_safety(safety);
+                    impl_generics(self);
+                    self.print_constness(constness);
+                    if let ast::ImplPolarity::Negative(_) = polarity {
+                        self.word("!");
+                    }
+                    self.print_trait_ref(trait_ref);
                     self.space();
                     self.word_space("for");
+                } else {
+                    impl_generics(self);
                 }
 
                 self.print_type(self_ty);
diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl
index 35ff48cb5f2..de22ea322c7 100644
--- a/compiler/rustc_attr_parsing/messages.ftl
+++ b/compiler/rustc_attr_parsing/messages.ftl
@@ -132,6 +132,7 @@ attr_parsing_unknown_version_literal =
 attr_parsing_unrecognized_repr_hint =
     unrecognized representation hint
     .help = valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+    .note = for more information, visit <https://doc.rust-lang.org/reference/type-layout.html?highlight=repr#representations>
 
 attr_parsing_unstable_cfg_target_compact =
     compact `cfg(target(..))` is experimental and subject to change
diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
index 95104b896ac..b3393e93de8 100644
--- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
@@ -15,7 +15,7 @@ impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
     type Item = (Symbol, Span);
     const CONVERT: ConvertFn<Self::Item> =
         |items, span| AttributeKind::AllowInternalUnstable(items, span);
-    const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
+    const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]);
 
     fn extend<'c>(
         cx: &'c mut AcceptContext<'_, '_, S>,
@@ -32,7 +32,7 @@ impl<S: Stage> CombineAttributeParser<S> for UnstableFeatureBoundParser {
     const PATH: &'static [rustc_span::Symbol] = &[sym::unstable_feature_bound];
     type Item = (Symbol, Span);
     const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::UnstableFeatureBound(items);
-    const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
+    const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]);
 
     fn extend<'c>(
         cx: &'c mut AcceptContext<'_, '_, S>,
@@ -53,7 +53,7 @@ impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
     type Item = Symbol;
     const CONVERT: ConvertFn<Self::Item> =
         |items, first_span| AttributeKind::AllowConstFnUnstable(items, first_span);
-    const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
+    const TEMPLATE: AttributeTemplate = template!(Word, List: &["feat1, feat2, ..."]);
 
     fn extend<'c>(
         cx: &'c mut AcceptContext<'_, '_, S>,
diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
index 947be28bc95..695ee666476 100644
--- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
@@ -16,7 +16,10 @@ use crate::{
     CfgMatchesLintEmitter, fluent_generated, parse_version, session_diagnostics, try_gate_cfg,
 };
 
-pub const CFG_TEMPLATE: AttributeTemplate = template!(List: "predicate");
+pub const CFG_TEMPLATE: AttributeTemplate = template!(
+    List: &["predicate"],
+    "https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute"
+);
 
 pub fn parse_cfg_attr<'c, S: Stage>(
     cx: &'c mut AcceptContext<'_, '_, S>,
diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
index c5fb11dbf6a..a9f77195d1b 100644
--- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
@@ -17,7 +17,7 @@ impl<S: Stage> SingleAttributeParser<S> for OptimizeParser {
     const PATH: &[Symbol] = &[sym::optimize];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
-    const TEMPLATE: AttributeTemplate = template!(List: "size|speed|none");
+    const TEMPLATE: AttributeTemplate = template!(List: &["size", "speed", "none"]);
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let Some(list) = args.list() else {
@@ -253,7 +253,7 @@ pub(crate) struct UsedParser {
 impl<S: Stage> AttributeParser<S> for UsedParser {
     const ATTRIBUTES: AcceptMapping<Self, S> = &[(
         &[sym::used],
-        template!(Word, List: "compiler|linker"),
+        template!(Word, List: &["compiler", "linker"]),
         |group: &mut Self, cx, args| {
             let used_by = match args {
                 ArgParser::NoArgs => UsedBy::Linker,
@@ -327,7 +327,7 @@ impl<S: Stage> CombineAttributeParser<S> for TargetFeatureParser {
     type Item = (Symbol, Span);
     const PATH: &[Symbol] = &[sym::target_feature];
     const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature(items, span);
-    const TEMPLATE: AttributeTemplate = template!(List: "enable = \"feat1, feat2\"");
+    const TEMPLATE: AttributeTemplate = template!(List: &["enable = \"feat1, feat2\""]);
 
     fn extend<'c>(
         cx: &'c mut AcceptContext<'_, '_, S>,
diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs
index 7d24c89a6e8..edd22172ca2 100644
--- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs
@@ -16,7 +16,7 @@ pub(crate) struct ConfusablesParser {
 impl<S: Stage> AttributeParser<S> for ConfusablesParser {
     const ATTRIBUTES: AcceptMapping<Self, S> = &[(
         &[sym::rustc_confusables],
-        template!(List: r#""name1", "name2", ..."#),
+        template!(List: &[r#""name1", "name2", ..."#]),
         |this, cx, args| {
             let Some(list) = args.list() else {
                 cx.expected_list(cx.attr_span);
diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
index 38ec4bd5645..e57ea8bbb5c 100644
--- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
@@ -40,7 +40,7 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
     const TEMPLATE: AttributeTemplate = template!(
         Word,
-        List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#,
+        List: &[r#"since = "version""#, r#"note = "reason""#, r#"since = "version", note = "reason""#],
         NameValueStr: "reason"
     );
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs
index 8437713206e..e9a45f20bff 100644
--- a/compiler/rustc_attr_parsing/src/attributes/inline.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs
@@ -18,7 +18,11 @@ impl<S: Stage> SingleAttributeParser<S> for InlineParser {
     const PATH: &'static [Symbol] = &[sym::inline];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
-    const TEMPLATE: AttributeTemplate = template!(Word, List: "always|never");
+    const TEMPLATE: AttributeTemplate = template!(
+        Word,
+        List: &["always", "never"],
+        "https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute"
+    );
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         match args {
@@ -59,7 +63,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
     const PATH: &'static [Symbol] = &[sym::rustc_force_inline];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
-    const TEMPLATE: AttributeTemplate = template!(Word, List: "reason", NameValueStr: "reason");
+    const TEMPLATE: AttributeTemplate = template!(Word, List: &["reason"], NameValueStr: "reason");
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let reason = match args {
diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
index 7eab3090870..d406c30b83e 100644
--- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
@@ -16,7 +16,10 @@ impl<S: Stage> SingleAttributeParser<S> for LinkNameParser {
     const PATH: &[Symbol] = &[sym::link_name];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
-    const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
+    const TEMPLATE: AttributeTemplate = template!(
+        NameValueStr: "name",
+        "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute"
+    );
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let Some(nv) = args.name_value() else {
@@ -38,7 +41,10 @@ impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
     const PATH: &[Symbol] = &[sym::link_section];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
-    const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
+    const TEMPLATE: AttributeTemplate = template!(
+        NameValueStr: "name",
+        "https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute"
+    );
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let Some(nv) = args.name_value() else {
@@ -94,7 +100,10 @@ impl<S: Stage> SingleAttributeParser<S> for LinkOrdinalParser {
     const PATH: &[Symbol] = &[sym::link_ordinal];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
-    const TEMPLATE: AttributeTemplate = template!(List: "ordinal");
+    const TEMPLATE: AttributeTemplate = template!(
+        List: &["ordinal"],
+        "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute"
+    );
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let ordinal = parse_single_integer(cx, args)?;
diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
index 886f7a889d3..a1166bf9ac5 100644
--- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
@@ -31,7 +31,10 @@ pub(crate) struct MacroUseParser {
     first_span: Option<Span>,
 }
 
-const MACRO_USE_TEMPLATE: AttributeTemplate = template!(Word, List: "name1, name2, ...");
+const MACRO_USE_TEMPLATE: AttributeTemplate = template!(
+    Word, List: &["name1, name2, ..."],
+    "https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute"
+);
 
 impl<S: Stage> AttributeParser<S> for MacroUseParser {
     const ATTRIBUTES: AcceptMapping<Self, S> = &[(
@@ -113,3 +116,11 @@ impl<S: Stage> AttributeParser<S> for MacroUseParser {
         Some(AttributeKind::MacroUse { span: self.first_span?, arguments: self.state })
     }
 }
+
+pub(crate) struct AllowInternalUnsafeParser;
+
+impl<S: Stage> NoArgsAttributeParser<S> for AllowInternalUnsafeParser {
+    const PATH: &[Symbol] = &[sym::allow_internal_unsafe];
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore;
+    const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::AllowInternalUnsafe(span);
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/must_use.rs b/compiler/rustc_attr_parsing/src/attributes/must_use.rs
index d767abbc250..c88bb5a69e5 100644
--- a/compiler/rustc_attr_parsing/src/attributes/must_use.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/must_use.rs
@@ -14,7 +14,10 @@ impl<S: Stage> SingleAttributeParser<S> for MustUseParser {
     const PATH: &[Symbol] = &[sym::must_use];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
-    const TEMPLATE: AttributeTemplate = template!(Word, NameValueStr: "reason");
+    const TEMPLATE: AttributeTemplate = template!(
+        Word, NameValueStr: "reason",
+        "https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute"
+    );
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         Some(AttributeKind::MustUse {
diff --git a/compiler/rustc_attr_parsing/src/attributes/path.rs b/compiler/rustc_attr_parsing/src/attributes/path.rs
index 5700d780d71..c1c3de8cbfc 100644
--- a/compiler/rustc_attr_parsing/src/attributes/path.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/path.rs
@@ -12,7 +12,10 @@ impl<S: Stage> SingleAttributeParser<S> for PathParser {
     const PATH: &[Symbol] = &[sym::path];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
-    const TEMPLATE: AttributeTemplate = template!(NameValueStr: "file");
+    const TEMPLATE: AttributeTemplate = template!(
+        NameValueStr: "file",
+        "https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute"
+    );
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let Some(nv) = args.name_value() else {
diff --git a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs
index b156a7c5845..b267980914c 100644
--- a/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/proc_macro_attrs.rs
@@ -28,8 +28,10 @@ impl<S: Stage> SingleAttributeParser<S> for ProcMacroDeriveParser {
     const PATH: &[Symbol] = &[sym::proc_macro_derive];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
-    const TEMPLATE: AttributeTemplate =
-        template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)");
+    const TEMPLATE: AttributeTemplate = template!(
+        List: &["TraitName", "TraitName, attributes(name1, name2, ...)"],
+        "https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros"
+    );
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let (trait_name, helper_attrs) = parse_derive_like(cx, args, true)?;
@@ -47,7 +49,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcBuiltinMacroParser {
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
     const TEMPLATE: AttributeTemplate =
-        template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)");
+        template!(List: &["TraitName", "TraitName, attributes(name1, name2, ...)"]);
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let (builtin_name, helper_attrs) = parse_derive_like(cx, args, false)?;
diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs
index 6087afe6ded..996d2af5f37 100644
--- a/compiler/rustc_attr_parsing/src/attributes/repr.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs
@@ -26,8 +26,10 @@ impl<S: Stage> CombineAttributeParser<S> for ReprParser {
     const CONVERT: ConvertFn<Self::Item> =
         |items, first_span| AttributeKind::Repr { reprs: items, first_span };
     // FIXME(jdonszelmann): never used
-    const TEMPLATE: AttributeTemplate =
-        template!(List: "C | Rust | align(...) | packed(...) | <integer type> | transparent");
+    const TEMPLATE: AttributeTemplate = template!(
+        List: &["C", "Rust", "transparent", "align(...)", "packed(...)", "<integer type>"],
+        "https://doc.rust-lang.org/reference/type-layout.html#representations"
+    );
 
     fn extend<'c>(
         cx: &'c mut AcceptContext<'_, '_, S>,
@@ -275,7 +277,7 @@ pub(crate) struct AlignParser(Option<(Align, Span)>);
 
 impl AlignParser {
     const PATH: &'static [Symbol] = &[sym::rustc_align];
-    const TEMPLATE: AttributeTemplate = template!(List: "<alignment in bytes>");
+    const TEMPLATE: AttributeTemplate = template!(List: &["<alignment in bytes>"]);
 
     fn parse<'c, S: Stage>(
         &mut self,
diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
index b465d2e62ff..1a668b4416f 100644
--- a/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs
@@ -12,7 +12,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeStart {
     const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_start];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
-    const TEMPLATE: AttributeTemplate = template!(List: "start");
+    const TEMPLATE: AttributeTemplate = template!(List: &["start"]);
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         parse_single_integer(cx, args)
@@ -26,7 +26,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeEnd {
     const PATH: &'static [Symbol] = &[sym::rustc_layout_scalar_valid_range_end];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
-    const TEMPLATE: AttributeTemplate = template!(List: "end");
+    const TEMPLATE: AttributeTemplate = template!(List: &["end"]);
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         parse_single_integer(cx, args)
diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs
index 3c4ec133d51..c6707f5048b 100644
--- a/compiler/rustc_attr_parsing/src/attributes/stability.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs
@@ -48,7 +48,7 @@ impl<S: Stage> AttributeParser<S> for StabilityParser {
     const ATTRIBUTES: AcceptMapping<Self, S> = &[
         (
             &[sym::stable],
-            template!(List: r#"feature = "name", since = "version""#),
+            template!(List: &[r#"feature = "name", since = "version""#]),
             |this, cx, args| {
                 reject_outside_std!(cx);
                 if !this.check_duplicate(cx)
@@ -60,7 +60,7 @@ impl<S: Stage> AttributeParser<S> for StabilityParser {
         ),
         (
             &[sym::unstable],
-            template!(List: r#"feature = "name", reason = "...", issue = "N""#),
+            template!(List: &[r#"feature = "name", reason = "...", issue = "N""#]),
             |this, cx, args| {
                 reject_outside_std!(cx);
                 if !this.check_duplicate(cx)
@@ -131,7 +131,7 @@ pub(crate) struct BodyStabilityParser {
 impl<S: Stage> AttributeParser<S> for BodyStabilityParser {
     const ATTRIBUTES: AcceptMapping<Self, S> = &[(
         &[sym::rustc_default_body_unstable],
-        template!(List: r#"feature = "name", reason = "...", issue = "N""#),
+        template!(List: &[r#"feature = "name", reason = "...", issue = "N""#]),
         |this, cx, args| {
             reject_outside_std!(cx);
             if this.stability.is_some() {
@@ -177,29 +177,37 @@ impl ConstStabilityParser {
 
 impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
     const ATTRIBUTES: AcceptMapping<Self, S> = &[
-        (&[sym::rustc_const_stable], template!(List: r#"feature = "name""#), |this, cx, args| {
-            reject_outside_std!(cx);
+        (
+            &[sym::rustc_const_stable],
+            template!(List: &[r#"feature = "name""#]),
+            |this, cx, args| {
+                reject_outside_std!(cx);
 
-            if !this.check_duplicate(cx)
-                && let Some((feature, level)) = parse_stability(cx, args)
-            {
-                this.stability = Some((
-                    PartialConstStability { level, feature, promotable: false },
-                    cx.attr_span,
-                ));
-            }
-        }),
-        (&[sym::rustc_const_unstable], template!(List: r#"feature = "name""#), |this, cx, args| {
-            reject_outside_std!(cx);
-            if !this.check_duplicate(cx)
-                && let Some((feature, level)) = parse_unstability(cx, args)
-            {
-                this.stability = Some((
-                    PartialConstStability { level, feature, promotable: false },
-                    cx.attr_span,
-                ));
-            }
-        }),
+                if !this.check_duplicate(cx)
+                    && let Some((feature, level)) = parse_stability(cx, args)
+                {
+                    this.stability = Some((
+                        PartialConstStability { level, feature, promotable: false },
+                        cx.attr_span,
+                    ));
+                }
+            },
+        ),
+        (
+            &[sym::rustc_const_unstable],
+            template!(List: &[r#"feature = "name""#]),
+            |this, cx, args| {
+                reject_outside_std!(cx);
+                if !this.check_duplicate(cx)
+                    && let Some((feature, level)) = parse_unstability(cx, args)
+                {
+                    this.stability = Some((
+                        PartialConstStability { level, feature, promotable: false },
+                        cx.attr_span,
+                    ));
+                }
+            },
+        ),
         (&[sym::rustc_promotable], template!(Word), |this, cx, _| {
             reject_outside_std!(cx);
             this.promotable = true;
diff --git a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
index 77b494328c7..3267855fb0d 100644
--- a/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/test_attrs.rs
@@ -13,7 +13,10 @@ impl<S: Stage> SingleAttributeParser<S> for IgnoreParser {
     const PATH: &[Symbol] = &[sym::ignore];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
-    const TEMPLATE: AttributeTemplate = template!(Word, NameValueStr: "reason");
+    const TEMPLATE: AttributeTemplate = template!(
+        Word, NameValueStr: "reason",
+        "https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute"
+    );
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         Some(AttributeKind::Ignore {
@@ -51,8 +54,10 @@ impl<S: Stage> SingleAttributeParser<S> for ShouldPanicParser {
     const PATH: &[Symbol] = &[sym::should_panic];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
-    const TEMPLATE: AttributeTemplate =
-        template!(Word, List: r#"expected = "reason""#, NameValueStr: "reason");
+    const TEMPLATE: AttributeTemplate = template!(
+        Word, List: &[r#"expected = "reason""#], NameValueStr: "reason",
+        "https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute"
+    );
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         Some(AttributeKind::ShouldPanic {
diff --git a/compiler/rustc_attr_parsing/src/attributes/traits.rs b/compiler/rustc_attr_parsing/src/attributes/traits.rs
index a954617ca57..8514d799aa4 100644
--- a/compiler/rustc_attr_parsing/src/attributes/traits.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/traits.rs
@@ -16,7 +16,7 @@ impl<S: Stage> SingleAttributeParser<S> for SkipDuringMethodDispatchParser {
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
 
-    const TEMPLATE: AttributeTemplate = template!(List: "array, boxed_slice");
+    const TEMPLATE: AttributeTemplate = template!(List: &["array, boxed_slice"]);
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let mut array = false;
diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs
index 1c57dc1ebe2..d4d68eb8b27 100644
--- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs
@@ -19,7 +19,7 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
         cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes");
     });
     const TEMPLATE: AttributeTemplate =
-        template!(NameValueStr: "transparent|semitransparent|opaque");
+        template!(NameValueStr: ["transparent", "semitransparent", "opaque"]);
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let Some(nv) = args.name_value() else {
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 80dfdffdb55..1420753a44e 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -33,7 +33,9 @@ use crate::attributes::lint_helpers::{
     AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser,
 };
 use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
-use crate::attributes::macro_attrs::{MacroEscapeParser, MacroUseParser};
+use crate::attributes::macro_attrs::{
+    AllowInternalUnsafeParser, MacroEscapeParser, MacroUseParser,
+};
 use crate::attributes::must_use::MustUseParser;
 use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
 use crate::attributes::non_exhaustive::NonExhaustiveParser;
@@ -178,6 +180,7 @@ attribute_parsers!(
         Single<SkipDuringMethodDispatchParser>,
         Single<TransparencyParser>,
         Single<WithoutArgs<AllowIncoherentImplParser>>,
+        Single<WithoutArgs<AllowInternalUnsafeParser>>,
         Single<WithoutArgs<AsPtrParser>>,
         Single<WithoutArgs<AutomaticallyDerivedParser>>,
         Single<WithoutArgs<CoherenceIsCoreParser>>,
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
index 1de25ca252b..41179844152 100644
--- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs
+++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -498,6 +498,7 @@ pub(crate) struct ReprIdent {
 #[derive(Diagnostic)]
 #[diag(attr_parsing_unrecognized_repr_hint, code = E0552)]
 #[help]
+#[note]
 pub(crate) struct UnrecognizedReprHint {
     #[primary_span]
     pub span: Span,
@@ -690,6 +691,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
             }
         }
 
+        if let Some(link) = self.template.docs {
+            diag.note(format!("for more information, visit <{link}>"));
+        }
         let suggestions = self.template.suggestions(false, &name);
         diag.span_suggestions(
             self.attr_span,
diff --git a/compiler/rustc_borrowck/src/handle_placeholders.rs b/compiler/rustc_borrowck/src/handle_placeholders.rs
index e168b819a8d..34599ac55b8 100644
--- a/compiler/rustc_borrowck/src/handle_placeholders.rs
+++ b/compiler/rustc_borrowck/src/handle_placeholders.rs
@@ -157,7 +157,7 @@ fn region_definitions<'tcx>(
     for info in var_infos.iter() {
         let origin = match info.origin {
             RegionVariableOrigin::Nll(origin) => origin,
-            _ => NllRegionVariableOrigin::Existential { from_forall: false, name: None },
+            _ => NllRegionVariableOrigin::Existential { name: None },
         };
 
         let definition = RegionDefinition { origin, universe: info.universe, external_name: None };
diff --git a/compiler/rustc_borrowck/src/polonius/legacy/facts.rs b/compiler/rustc_borrowck/src/polonius/legacy/facts.rs
index 64389b11a65..1f8177477e6 100644
--- a/compiler/rustc_borrowck/src/polonius/legacy/facts.rs
+++ b/compiler/rustc_borrowck/src/polonius/legacy/facts.rs
@@ -184,22 +184,6 @@ where
     }
 }
 
-impl<A, B, C, D> FactRow for (A, B, C, D)
-where
-    A: FactCell,
-    B: FactCell,
-    C: FactCell,
-    D: FactCell,
-{
-    fn write(
-        &self,
-        out: &mut dyn Write,
-        location_table: &PoloniusLocationTable,
-    ) -> Result<(), Box<dyn Error>> {
-        write_row(out, location_table, &[&self.0, &self.1, &self.2, &self.3])
-    }
-}
-
 fn write_row(
     out: &mut dyn Write,
     location_table: &PoloniusLocationTable,
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index dbd245214a2..b0c31ac9601 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -1939,10 +1939,15 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         //
         // and here we prefer to blame the source (the y = x statement).
         let blame_source = match from_region_origin {
-            NllRegionVariableOrigin::FreeRegion
-            | NllRegionVariableOrigin::Existential { from_forall: false, name: _ } => true,
-            NllRegionVariableOrigin::Placeholder(_)
-            | NllRegionVariableOrigin::Existential { from_forall: true, name: _ } => false,
+            NllRegionVariableOrigin::FreeRegion => true,
+            NllRegionVariableOrigin::Placeholder(_) => false,
+            // `'existential: 'whatever` never results in a region error by itself.
+            // We may always infer it to `'static` afterall. This means while an error
+            // path may go through an existential, these existentials are never the
+            // `from_region`.
+            NllRegionVariableOrigin::Existential { name: _ } => {
+                unreachable!("existentials can outlive everything")
+            }
         };
 
         // To pick a constraint to blame, we organize constraints by how interesting we expect them
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
index 100d30704b9..fa3064afee8 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -66,7 +66,7 @@ impl<'a, 'tcx> RegionRenumberer<'a, 'tcx> {
         T: TypeFoldable<TyCtxt<'tcx>>,
         F: Fn() -> RegionCtxt,
     {
-        let origin = NllRegionVariableOrigin::Existential { from_forall: false, name: None };
+        let origin = NllRegionVariableOrigin::Existential { name: None };
         fold_regions(self.infcx.tcx, value, |_region, _depth| {
             self.infcx.next_nll_region_var(origin, || region_ctxt_fn())
         })
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index 393adafea0b..84ca9bad2c1 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -216,7 +216,7 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
                     *ex_reg_var
                 } else {
                     let ex_reg_var =
-                        self.next_existential_region_var(true, br.kind.get_name(infcx.infcx.tcx));
+                        self.next_existential_region_var(br.kind.get_name(infcx.infcx.tcx));
                     debug!(?ex_reg_var);
                     reg_map.insert(br, ex_reg_var);
 
@@ -244,17 +244,9 @@ impl<'a, 'b, 'tcx> NllTypeRelating<'a, 'b, 'tcx> {
     }
 
     #[instrument(skip(self), level = "debug")]
-    fn next_existential_region_var(
-        &mut self,
-        from_forall: bool,
-        name: Option<Symbol>,
-    ) -> ty::Region<'tcx> {
-        let origin = NllRegionVariableOrigin::Existential { name, from_forall };
-
-        let reg_var =
-            self.type_checker.infcx.next_nll_region_var(origin, || RegionCtxt::Existential(name));
-
-        reg_var
+    fn next_existential_region_var(&mut self, name: Option<Symbol>) -> ty::Region<'tcx> {
+        let origin = NllRegionVariableOrigin::Existential { name };
+        self.type_checker.infcx.next_nll_region_var(origin, || RegionCtxt::Existential(name))
     }
 
     #[instrument(skip(self), level = "debug")]
diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs
index 5f203dd5d11..f7d8f4aa783 100644
--- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs
@@ -44,7 +44,7 @@ impl MultiItemModifier for Expander {
         item: Annotatable,
         _is_derive_const: bool,
     ) -> ExpandResult<Vec<Annotatable>, Annotatable> {
-        let template = AttributeTemplate { list: Some("path"), ..Default::default() };
+        let template = AttributeTemplate { list: Some(&["path"]), ..Default::default() };
         validate_attr::check_builtin_meta_item(
             &ecx.sess.psess,
             meta_item,
diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs
index e259f5b3955..a33eca43de5 100644
--- a/compiler/rustc_builtin_macros/src/derive.rs
+++ b/compiler/rustc_builtin_macros/src/derive.rs
@@ -34,8 +34,10 @@ impl MultiItemModifier for Expander {
         let (sess, features) = (ecx.sess, ecx.ecfg.features);
         let result =
             ecx.resolver.resolve_derives(ecx.current_expansion.id, ecx.force_mode, &|| {
-                let template =
-                    AttributeTemplate { list: Some("Trait1, Trait2, ..."), ..Default::default() };
+                let template = AttributeTemplate {
+                    list: Some(&["Trait1, Trait2, ..."]),
+                    ..Default::default()
+                };
                 validate_attr::check_builtin_meta_item(
                     &sess.psess,
                     meta_item,
diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
index 6082e376435..75db5d77783 100644
--- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
@@ -108,11 +108,7 @@ pub(crate) fn expand_deriving_coerce_pointee(
             cx.item(
                 span,
                 attrs.clone(),
-                ast::ItemKind::Impl(Box::new(ast::Impl {
-                    safety: ast::Safety::Default,
-                    polarity: ast::ImplPolarity::Positive,
-                    defaultness: ast::Defaultness::Final,
-                    constness: ast::Const::No,
+                ast::ItemKind::Impl(ast::Impl {
                     generics: Generics {
                         params: generics
                             .params
@@ -137,10 +133,16 @@ pub(crate) fn expand_deriving_coerce_pointee(
                         where_clause: generics.where_clause.clone(),
                         span: generics.span,
                     },
-                    of_trait: Some(trait_ref),
+                    of_trait: Some(Box::new(ast::TraitImplHeader {
+                        safety: ast::Safety::Default,
+                        polarity: ast::ImplPolarity::Positive,
+                        defaultness: ast::Defaultness::Final,
+                        constness: ast::Const::No,
+                        trait_ref,
+                    })),
                     self_ty: self_type.clone(),
                     items: ThinVec::new(),
-                })),
+                }),
             ),
         ));
     }
@@ -152,16 +154,18 @@ pub(crate) fn expand_deriving_coerce_pointee(
         let item = cx.item(
             span,
             attrs.clone(),
-            ast::ItemKind::Impl(Box::new(ast::Impl {
-                safety: ast::Safety::Default,
-                polarity: ast::ImplPolarity::Positive,
-                defaultness: ast::Defaultness::Final,
-                constness: ast::Const::No,
+            ast::ItemKind::Impl(ast::Impl {
                 generics,
-                of_trait: Some(trait_ref),
+                of_trait: Some(Box::new(ast::TraitImplHeader {
+                    safety: ast::Safety::Default,
+                    polarity: ast::ImplPolarity::Positive,
+                    defaultness: ast::Defaultness::Final,
+                    constness: ast::Const::No,
+                    trait_ref,
+                })),
                 self_ty: self_type.clone(),
                 items: ThinVec::new(),
-            })),
+            }),
         );
         push(Annotatable::Item(item));
     };
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 3f4b47152c4..3fcf9da9450 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -826,21 +826,25 @@ impl<'a> TraitDef<'a> {
             )
         }
 
-        let opt_trait_ref = Some(trait_ref);
-
         cx.item(
             self.span,
             attrs,
-            ast::ItemKind::Impl(Box::new(ast::Impl {
-                safety: ast::Safety::Default,
-                polarity: ast::ImplPolarity::Positive,
-                defaultness: ast::Defaultness::Final,
-                constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No },
+            ast::ItemKind::Impl(ast::Impl {
                 generics: trait_generics,
-                of_trait: opt_trait_ref,
+                of_trait: Some(Box::new(ast::TraitImplHeader {
+                    safety: ast::Safety::Default,
+                    polarity: ast::ImplPolarity::Positive,
+                    defaultness: ast::Defaultness::Final,
+                    constness: if self.is_const {
+                        ast::Const::Yes(DUMMY_SP)
+                    } else {
+                        ast::Const::No
+                    },
+                    trait_ref,
+                })),
                 self_ty: self_type,
                 items: methods.into_iter().chain(associated_types).collect(),
-            })),
+            }),
         )
     }
 
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 009e7e2487b..043123fcab2 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -24,6 +24,7 @@ use crate::attributes::{self, llfn_attrs_from_instance};
 use crate::builder::Builder;
 use crate::context::CodegenCx;
 use crate::llvm::{self, Attribute, AttributePlace};
+use crate::llvm_util;
 use crate::type_::Type;
 use crate::type_of::LayoutLlvmExt;
 use crate::value::Value;
@@ -500,7 +501,16 @@ impl<'ll, 'tcx> FnAbiLlvmExt<'ll, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
                     }
                 }
                 PassMode::Indirect { attrs, meta_attrs: None, on_stack: false } => {
-                    apply(attrs);
+                    let i = apply(attrs);
+                    if cx.sess().opts.optimize != config::OptLevel::No
+                        && llvm_util::get_version() >= (21, 0, 0)
+                    {
+                        attributes::apply_to_llfn(
+                            llfn,
+                            llvm::AttributePlace::Argument(i),
+                            &[llvm::AttributeKind::DeadOnReturn.create_attr(cx.llcx)],
+                        );
+                    }
                 }
                 PassMode::Indirect { attrs, meta_attrs: Some(meta_attrs), on_stack } => {
                     assert!(!on_stack);
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index ee77774c688..27ae729a531 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -213,6 +213,12 @@ pub(crate) unsafe fn create_module<'ll>(
             target_data_layout = target_data_layout.replace("p8:128:128:128:48", "p8:128:128")
         }
     }
+    if llvm_version < (22, 0, 0) {
+        if sess.target.arch == "avr" {
+            // LLVM 22.0 updated the default layout on avr: https://github.com/llvm/llvm-project/pull/153010
+            target_data_layout = target_data_layout.replace("n8:16", "n8")
+        }
+    }
 
     // Ensure the data-layout values hardcoded remain the defaults.
     {
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 75d3d27f74e..ad3c3d5932e 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -249,6 +249,7 @@ pub(crate) enum AttributeKind {
     FnRetThunkExtern = 41,
     Writable = 42,
     DeadOnUnwind = 43,
+    DeadOnReturn = 44,
 }
 
 /// LLVMIntPredicate
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index 3ca070acc9d..b6cfea88363 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -401,6 +401,9 @@ codegen_ssa_version_script_write_failure = failed to write version script: {$err
 
 codegen_ssa_visual_studio_not_installed = you may need to install Visual Studio build tools with the "C++ build tools" workload
 
+codegen_ssa_xcrun_about =
+    the SDK is needed by the linker to know where to find symbols in system libraries and for embedding the SDK version in the final object file
+
 codegen_ssa_xcrun_command_line_tools_insufficient =
     when compiling for iOS, tvOS, visionOS or watchOS, you need a full installation of Xcode
 
diff --git a/compiler/rustc_codegen_ssa/src/back/apple.rs b/compiler/rustc_codegen_ssa/src/back/apple.rs
index 2f68bad1695..2274450e20e 100644
--- a/compiler/rustc_codegen_ssa/src/back/apple.rs
+++ b/compiler/rustc_codegen_ssa/src/back/apple.rs
@@ -160,6 +160,10 @@ pub(super) fn add_version_to_llvm_target(
 pub(super) fn get_sdk_root(sess: &Session) -> Option<PathBuf> {
     let sdk_name = sdk_name(&sess.target);
 
+    // Attempt to invoke `xcrun` to find the SDK.
+    //
+    // Note that when cross-compiling from e.g. Linux, the `xcrun` binary may sometimes be provided
+    // as a shim by a cross-compilation helper tool. It usually isn't, but we still try nonetheless.
     match xcrun_show_sdk_path(sdk_name, sess.verbose_internals()) {
         Ok((path, stderr)) => {
             // Emit extra stderr, such as if `-verbose` was passed, or if `xcrun` emitted a warning.
@@ -169,7 +173,19 @@ pub(super) fn get_sdk_root(sess: &Session) -> Option<PathBuf> {
             Some(path)
         }
         Err(err) => {
-            let mut diag = sess.dcx().create_err(err);
+            // Failure to find the SDK is not a hard error, since the user might have specified it
+            // in a manner unknown to us (moreso if cross-compiling):
+            // - A compiler driver like `zig cc` which links using an internally bundled SDK.
+            // - Extra linker arguments (`-Clink-arg=-syslibroot`).
+            // - A custom linker or custom compiler driver.
+            //
+            // Though we still warn, since such cases are uncommon, and it is very hard to debug if
+            // you do not know the details.
+            //
+            // FIXME(madsmtm): Make this a lint, to allow deny warnings to work.
+            // (Or fix <https://github.com/rust-lang/rust/issues/21204>).
+            let mut diag = sess.dcx().create_warn(err);
+            diag.note(fluent::codegen_ssa_xcrun_about);
 
             // Recognize common error cases, and give more Rust-specific error messages for those.
             if let Some(developer_dir) = xcode_select_developer_dir() {
@@ -209,6 +225,8 @@ fn xcrun_show_sdk_path(
     sdk_name: &'static str,
     verbose: bool,
 ) -> Result<(PathBuf, String), XcrunError> {
+    // Intentionally invoke the `xcrun` in PATH, since e.g. nixpkgs provide an `xcrun` shim, so we
+    // don't want to require `/usr/bin/xcrun`.
     let mut cmd = Command::new("xcrun");
     if verbose {
         cmd.arg("--verbose");
@@ -280,7 +298,7 @@ fn stdout_to_path(mut stdout: Vec<u8>) -> PathBuf {
     }
     #[cfg(unix)]
     let path = <OsString as std::os::unix::ffi::OsStringExt>::from_vec(stdout);
-    #[cfg(not(unix))] // Unimportant, this is only used on macOS
-    let path = OsString::from(String::from_utf8(stdout).unwrap());
+    #[cfg(not(unix))] // Not so important, this is mostly used on macOS
+    let path = OsString::from(String::from_utf8(stdout).expect("stdout must be UTF-8"));
     PathBuf::from(path)
 }
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 3ec0d900994..4ebe59dc2a7 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -3194,39 +3194,60 @@ fn add_apple_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavo
 }
 
 fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) -> Option<PathBuf> {
-    let os = &sess.target.os;
-    if sess.target.vendor != "apple"
-        || !matches!(os.as_ref(), "ios" | "tvos" | "watchos" | "visionos" | "macos")
-        || !matches!(flavor, LinkerFlavor::Darwin(..))
-    {
+    if !sess.target.is_like_darwin {
         return None;
     }
-
-    if os == "macos" && !matches!(flavor, LinkerFlavor::Darwin(Cc::No, _)) {
+    let LinkerFlavor::Darwin(cc, _) = flavor else {
         return None;
-    }
-
-    let sdk_root = sess.time("get_apple_sdk_root", || get_apple_sdk_root(sess))?;
+    };
 
-    match flavor {
-        LinkerFlavor::Darwin(Cc::Yes, _) => {
-            // Use `-isysroot` instead of `--sysroot`, as only the former
-            // makes Clang treat it as a platform SDK.
-            //
-            // This is admittedly a bit strange, as on most targets
-            // `-isysroot` only applies to include header files, but on Apple
-            // targets this also applies to libraries and frameworks.
-            cmd.cc_arg("-isysroot");
-            cmd.cc_arg(&sdk_root);
-        }
-        LinkerFlavor::Darwin(Cc::No, _) => {
-            cmd.link_arg("-syslibroot");
-            cmd.link_arg(&sdk_root);
-        }
-        _ => unreachable!(),
+    // The default compiler driver on macOS is at `/usr/bin/cc`. This is a trampoline binary that
+    // effectively invokes `xcrun cc` internally to look up both the compiler binary and the SDK
+    // root from the current Xcode installation. When cross-compiling, when `rustc` is invoked
+    // inside Xcode, or when invoking the linker directly, this default logic is unsuitable, so
+    // instead we invoke `xcrun` manually.
+    //
+    // (Note that this doesn't mean we get a duplicate lookup here - passing `SDKROOT` below will
+    // cause the trampoline binary to skip looking up the SDK itself).
+    let sdkroot = sess.time("get_apple_sdk_root", || get_apple_sdk_root(sess))?;
+
+    if cc == Cc::Yes {
+        // There are a few options to pass the SDK root when linking with a C/C++ compiler:
+        // - The `--sysroot` flag.
+        // - The `-isysroot` flag.
+        // - The `SDKROOT` environment variable.
+        //
+        // `--sysroot` isn't actually enough to get Clang to treat it as a platform SDK, you need
+        // to specify `-isysroot`. This is admittedly a bit strange, as on most targets `-isysroot`
+        // only applies to include header files, but on Apple targets it also applies to libraries
+        // and frameworks.
+        //
+        // This leaves the choice between `-isysroot` and `SDKROOT`. Both are supported by Clang and
+        // GCC, though they may not be supported by all compiler drivers. We choose `SDKROOT`,
+        // primarily because that is the same interface that is used when invoking the tool under
+        // `xcrun -sdk macosx $tool`.
+        //
+        // In that sense, if a given compiler driver does not support `SDKROOT`, the blame is fairly
+        // clearly in the tool in question, since they also don't support being run under `xcrun`.
+        //
+        // Additionally, `SDKROOT` is an environment variable and thus optional. It also has lower
+        // precedence than `-isysroot`, so a custom compiler driver that does not support it and
+        // instead figures out the SDK on their own can easily do so by using `-isysroot`.
+        //
+        // (This in particular affects Clang built with the `DEFAULT_SYSROOT` CMake flag, such as
+        // the one provided by some versions of Homebrew's `llvm` package. Those will end up
+        // ignoring the value we set here, and instead use their built-in sysroot).
+        cmd.cmd().env("SDKROOT", &sdkroot);
+    } else {
+        // When invoking the linker directly, we use the `-syslibroot` parameter. `SDKROOT` is not
+        // read by the linker, so it's really the only option.
+        //
+        // This is also what Clang does.
+        cmd.link_arg("-syslibroot");
+        cmd.link_arg(&sdkroot);
     }
 
-    Some(sdk_root)
+    Some(sdkroot)
 }
 
 fn get_apple_sdk_root(sess: &Session) -> Option<PathBuf> {
@@ -3255,7 +3276,13 @@ fn get_apple_sdk_root(sess: &Session) -> Option<PathBuf> {
             }
             "macosx"
                 if sdkroot.contains("iPhoneOS.platform")
-                    || sdkroot.contains("iPhoneSimulator.platform") => {}
+                    || sdkroot.contains("iPhoneSimulator.platform")
+                    || sdkroot.contains("AppleTVOS.platform")
+                    || sdkroot.contains("AppleTVSimulator.platform")
+                    || sdkroot.contains("WatchOS.platform")
+                    || sdkroot.contains("WatchSimulator.platform")
+                    || sdkroot.contains("XROS.platform")
+                    || sdkroot.contains("XRSimulator.platform") => {}
             "watchos"
                 if sdkroot.contains("WatchSimulator.platform")
                     || sdkroot.contains("MacOSX.platform") => {}
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index 7e124f65324..0494666bda9 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -569,7 +569,7 @@ fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel
     // core/std/allocators/etc. For example symbols used to hook up allocation
     // are not considered for export
     let codegen_fn_attrs = tcx.codegen_fn_attrs(sym_def_id);
-    let is_extern = codegen_fn_attrs.contains_extern_indicator();
+    let is_extern = codegen_fn_attrs.contains_extern_indicator(tcx, sym_def_id);
     let std_internal =
         codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL);
 
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 7f54a47327a..287787eb3d1 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -443,6 +443,27 @@ fn apply_overrides(tcx: TyCtxt<'_>, did: LocalDefId, codegen_fn_attrs: &mut Code
     if tcx.should_inherit_track_caller(did) {
         codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
     }
+
+    // Foreign items by default use no mangling for their symbol name.
+    if tcx.is_foreign_item(did) {
+        // There's a few exceptions to this rule though:
+        if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL) {
+            // * `#[rustc_std_internal_symbol]` mangles the symbol name in a special way
+            //   both for exports and imports through foreign items. This is handled further,
+            //   during symbol mangling logic.
+        } else if codegen_fn_attrs.link_name.is_some() {
+            // * This can be overridden with the `#[link_name]` attribute
+        } else {
+            // NOTE: there's one more exception that we cannot apply here. On wasm,
+            // some items cannot be `no_mangle`.
+            // However, we don't have enough information here to determine that.
+            // As such, no_mangle foreign items on wasm that have the same defid as some
+            // import will *still* be mangled despite this.
+            //
+            // if none of the exceptions apply; apply no_mangle
+            codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
+        }
+    }
 }
 
 fn check_result(
diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index a0160d1188d..b1cc0cc2878 100644
--- a/compiler/rustc_const_eval/src/interpret/call.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -346,7 +346,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         destination: &PlaceTy<'tcx, M::Provenance>,
         mut cont: ReturnContinuation,
     ) -> InterpResult<'tcx> {
-        let _span = enter_trace_span!(M, step::init_stack_frame, %instance, tracing_separate_thread = Empty);
+        let _trace = enter_trace_span!(M, step::init_stack_frame, %instance, tracing_separate_thread = Empty);
 
         // Compute callee information.
         // FIXME: for variadic support, do we have to somehow determine callee's extra_args?
@@ -527,7 +527,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         target: Option<mir::BasicBlock>,
         unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx> {
-        let _span =
+        let _trace =
             enter_trace_span!(M, step::init_fn_call, tracing_separate_thread = Empty, ?fn_val)
                 .or_if_tracing_disabled(|| trace!("init_fn_call: {:#?}", fn_val));
 
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index c4b705d7124..d4f2bb8257d 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -113,7 +113,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// See [LayoutOf::layout_of] for the original documentation.
     #[inline(always)]
     pub fn layout_of(&self, ty: Ty<'tcx>) -> <Self as LayoutOfHelpers<'tcx>>::LayoutOfResult {
-        let _span = enter_trace_span!(M, layouting::layout_of, ty = ?ty.kind());
+        let _trace = enter_trace_span!(M, layouting::layout_of, ty = ?ty.kind());
         LayoutOf::layout_of(self, ty)
     }
 
@@ -126,7 +126,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         sig: ty::PolyFnSig<'tcx>,
         extra_args: &'tcx ty::List<Ty<'tcx>>,
     ) -> <Self as FnAbiOfHelpers<'tcx>>::FnAbiOfResult {
-        let _span = enter_trace_span!(M, layouting::fn_abi_of_fn_ptr, ?sig, ?extra_args);
+        let _trace = enter_trace_span!(M, layouting::fn_abi_of_fn_ptr, ?sig, ?extra_args);
         FnAbiOf::fn_abi_of_fn_ptr(self, sig, extra_args)
     }
 
@@ -139,7 +139,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         instance: ty::Instance<'tcx>,
         extra_args: &'tcx ty::List<Ty<'tcx>>,
     ) -> <Self as FnAbiOfHelpers<'tcx>>::FnAbiOfResult {
-        let _span = enter_trace_span!(M, layouting::fn_abi_of_instance, ?instance, ?extra_args);
+        let _trace = enter_trace_span!(M, layouting::fn_abi_of_instance, ?instance, ?extra_args);
         FnAbiOf::fn_abi_of_instance(self, instance, extra_args)
     }
 }
@@ -322,7 +322,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         frame: &Frame<'tcx, M::Provenance, M::FrameExtra>,
         value: T,
     ) -> Result<T, ErrorHandled> {
-        let _span = enter_trace_span!(
+        let _trace = enter_trace_span!(
             M,
             "instantiate_from_frame_and_normalize_erasing_regions",
             "{}",
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 14541809070..53a440b646b 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -773,7 +773,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         mir_place: mir::Place<'tcx>,
         layout: Option<TyAndLayout<'tcx>>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
-        let _span = enter_trace_span!(
+        let _trace = enter_trace_span!(
             M,
             step::eval_place_to_op,
             ?mir_place,
@@ -823,7 +823,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         mir_op: &mir::Operand<'tcx>,
         layout: Option<TyAndLayout<'tcx>>,
     ) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
-        let _span =
+        let _trace =
             enter_trace_span!(M, step::eval_operand, ?mir_op, tracing_separate_thread = Empty);
 
         use rustc_middle::mir::Operand::*;
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 45c4edb8503..6ff50dc700f 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -526,7 +526,7 @@ where
         &self,
         mir_place: mir::Place<'tcx>,
     ) -> InterpResult<'tcx, PlaceTy<'tcx, M::Provenance>> {
-        let _span =
+        let _trace =
             enter_trace_span!(M, step::eval_place, ?mir_place, tracing_separate_thread = Empty);
 
         let mut place = self.local_to_place(mir_place.local)?;
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 9df49c0f4cc..76e470b69dc 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -76,7 +76,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     ///
     /// This does NOT move the statement counter forward, the caller has to do that!
     pub fn eval_statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
-        let _span = enter_trace_span!(
+        let _trace = enter_trace_span!(
             M,
             step::eval_statement,
             stmt = ?stmt.kind,
@@ -465,7 +465,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     }
 
     fn eval_terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> InterpResult<'tcx> {
-        let _span = enter_trace_span!(
+        let _trace = enter_trace_span!(
             M,
             step::eval_terminator,
             terminator = ?terminator.kind,
diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs
index 71800950faa..72bee345406 100644
--- a/compiler/rustc_const_eval/src/interpret/util.rs
+++ b/compiler/rustc_const_eval/src/interpret/util.rs
@@ -85,11 +85,11 @@ impl EnteredTraceSpan for tracing::span::EnteredSpan {
 /// # let my_debug_var = String::new();
 /// // logs a span named "hello" with a field named "arg" of value 42 (works only because
 /// // 42 implements the tracing::Value trait, otherwise use one of the options below)
-/// let _span = enter_trace_span!(M, "hello", arg = 42);
+/// let _trace = enter_trace_span!(M, "hello", arg = 42);
 /// // logs a field called "my_display_var" using the Display implementation
-/// let _span = enter_trace_span!(M, "hello", %my_display_var);
+/// let _trace = enter_trace_span!(M, "hello", %my_display_var);
 /// // logs a field called "my_debug_var" using the Debug implementation
-/// let _span = enter_trace_span!(M, "hello", ?my_debug_var);
+/// let _trace = enter_trace_span!(M, "hello", ?my_debug_var);
 ///  ```
 ///
 /// ### `NAME::SUBNAME` syntax
@@ -107,8 +107,8 @@ impl EnteredTraceSpan for tracing::span::EnteredSpan {
 /// # use rustc_const_eval::enter_trace_span;
 /// # type M = rustc_const_eval::const_eval::CompileTimeMachine<'static>;
 /// // for example, the first will expand to the second
-/// let _span = enter_trace_span!(M, borrow_tracker::on_stack_pop, /* ... */);
-/// let _span = enter_trace_span!(M, "borrow_tracker", borrow_tracker = "on_stack_pop", /* ... */);
+/// let _trace = enter_trace_span!(M, borrow_tracker::on_stack_pop, /* ... */);
+/// let _trace = enter_trace_span!(M, "borrow_tracker", borrow_tracker = "on_stack_pop", /* ... */);
 /// ```
 ///
 /// ### `tracing_separate_thread` parameter
@@ -124,7 +124,7 @@ impl EnteredTraceSpan for tracing::span::EnteredSpan {
 /// ```rust
 /// # use rustc_const_eval::enter_trace_span;
 /// # type M = rustc_const_eval::const_eval::CompileTimeMachine<'static>;
-/// let _span = enter_trace_span!(M, step::eval_statement, tracing_separate_thread = tracing::field::Empty);
+/// let _trace = enter_trace_span!(M, step::eval_statement, tracing_separate_thread = tracing::field::Empty);
 /// ```
 ///
 /// ### Executing something else when tracing is disabled
@@ -136,7 +136,7 @@ impl EnteredTraceSpan for tracing::span::EnteredSpan {
 /// # use rustc_const_eval::enter_trace_span;
 /// # use rustc_const_eval::interpret::EnteredTraceSpan;
 /// # type M = rustc_const_eval::const_eval::CompileTimeMachine<'static>;
-/// let _span = enter_trace_span!(M, step::eval_statement)
+/// let _trace = enter_trace_span!(M, step::eval_statement)
 ///     .or_if_tracing_disabled(|| tracing::info!("eval_statement"));
 /// ```
 #[macro_export]
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index ed48f53c310..ab0c0665d51 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -1415,7 +1415,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         recursive: bool,
         reset_provenance_and_padding: bool,
     ) -> InterpResult<'tcx> {
-        let _span = enter_trace_span!(
+        let _trace = enter_trace_span!(
             M,
             "validate_operand",
             "recursive={recursive}, reset_provenance_and_padding={reset_provenance_and_padding}, val={val:?}"
diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs
index 2dc746754f8..9d6674873b1 100644
--- a/compiler/rustc_const_eval/src/util/type_name.rs
+++ b/compiler/rustc_const_eval/src/util/type_name.rs
@@ -7,12 +7,12 @@ use rustc_middle::bug;
 use rustc_middle::ty::print::{PrettyPrinter, PrintError, Printer};
 use rustc_middle::ty::{self, GenericArg, GenericArgKind, Ty, TyCtxt};
 
-struct AbsolutePathPrinter<'tcx> {
+struct TypeNamePrinter<'tcx> {
     tcx: TyCtxt<'tcx>,
     path: String,
 }
 
-impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
+impl<'tcx> Printer<'tcx> for TypeNamePrinter<'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
@@ -75,26 +75,26 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
         self.pretty_print_dyn_existential(predicates)
     }
 
-    fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
+    fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
         self.path.push_str(self.tcx.crate_name(cnum).as_str());
         Ok(())
     }
 
-    fn path_qualified(
+    fn print_path_with_qualified(
         &mut self,
         self_ty: Ty<'tcx>,
         trait_ref: Option<ty::TraitRef<'tcx>>,
     ) -> Result<(), PrintError> {
-        self.pretty_path_qualified(self_ty, trait_ref)
+        self.pretty_print_path_with_qualified(self_ty, trait_ref)
     }
 
-    fn path_append_impl(
+    fn print_path_with_impl(
         &mut self,
         print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
         self_ty: Ty<'tcx>,
         trait_ref: Option<ty::TraitRef<'tcx>>,
     ) -> Result<(), PrintError> {
-        self.pretty_path_append_impl(
+        self.pretty_print_path_with_impl(
             |cx| {
                 print_prefix(cx)?;
 
@@ -107,7 +107,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
         )
     }
 
-    fn path_append(
+    fn print_path_with_simple(
         &mut self,
         print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
         disambiguated_data: &DisambiguatedDefPathData,
@@ -119,7 +119,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
         Ok(())
     }
 
-    fn path_generic_args(
+    fn print_path_with_generic_args(
         &mut self,
         print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
         args: &[GenericArg<'tcx>],
@@ -135,7 +135,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
     }
 }
 
-impl<'tcx> PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> {
+impl<'tcx> PrettyPrinter<'tcx> for TypeNamePrinter<'tcx> {
     fn should_print_region(&self, _region: ty::Region<'_>) -> bool {
         false
     }
@@ -159,7 +159,7 @@ impl<'tcx> PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> {
     }
 }
 
-impl Write for AbsolutePathPrinter<'_> {
+impl Write for TypeNamePrinter<'_> {
     fn write_str(&mut self, s: &str) -> std::fmt::Result {
         self.path.push_str(s);
         Ok(())
@@ -167,7 +167,7 @@ impl Write for AbsolutePathPrinter<'_> {
 }
 
 pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> String {
-    let mut p = AbsolutePathPrinter { tcx, path: String::new() };
+    let mut p = TypeNamePrinter { tcx, path: String::new() };
     p.print_type(ty).unwrap();
     p.path
 }
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index c234aa43c09..f2c15071532 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -17,6 +17,7 @@ use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult};
 use rustc_feature::Features;
 use rustc_hir as hir;
 use rustc_hir::attrs::{AttributeKind, CfgEntry, Deprecation};
+use rustc_hir::def::MacroKinds;
 use rustc_hir::{Stability, find_attr};
 use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools};
 use rustc_parse::MACRO_ARGUMENTS;
@@ -718,6 +719,9 @@ impl MacResult for DummyResult {
 /// A syntax extension kind.
 #[derive(Clone)]
 pub enum SyntaxExtensionKind {
+    /// A `macro_rules!` macro that can work as any `MacroKind`
+    MacroRules(Arc<crate::MacroRulesMacroExpander>),
+
     /// A token-based function-like macro.
     Bang(
         /// An expander with signature TokenStream -> TokenStream.
@@ -772,9 +776,39 @@ pub enum SyntaxExtensionKind {
     ),
 
     /// A glob delegation.
+    ///
+    /// This is for delegated function implementations, and has nothing to do with glob imports.
     GlobDelegation(Arc<dyn GlobDelegationExpander + sync::DynSync + sync::DynSend>),
 }
 
+impl SyntaxExtensionKind {
+    /// Returns `Some(expander)` for a macro usable as a `LegacyBang`; otherwise returns `None`
+    ///
+    /// This includes a `MacroRules` with function-like rules.
+    pub fn as_legacy_bang(&self) -> Option<&(dyn TTMacroExpander + sync::DynSync + sync::DynSend)> {
+        match self {
+            SyntaxExtensionKind::LegacyBang(exp) => Some(exp.as_ref()),
+            SyntaxExtensionKind::MacroRules(exp) if exp.kinds().contains(MacroKinds::BANG) => {
+                Some(exp.as_ref())
+            }
+            _ => None,
+        }
+    }
+
+    /// Returns `Some(expander)` for a macro usable as an `Attr`; otherwise returns `None`
+    ///
+    /// This includes a `MacroRules` with `attr` rules.
+    pub fn as_attr(&self) -> Option<&(dyn AttrProcMacro + sync::DynSync + sync::DynSend)> {
+        match self {
+            SyntaxExtensionKind::Attr(exp) => Some(exp.as_ref()),
+            SyntaxExtensionKind::MacroRules(exp) if exp.kinds().contains(MacroKinds::ATTR) => {
+                Some(exp.as_ref())
+            }
+            _ => None,
+        }
+    }
+}
+
 /// A struct representing a macro definition in "lowered" form ready for expansion.
 pub struct SyntaxExtension {
     /// A syntax extension kind.
@@ -804,18 +838,19 @@ pub struct SyntaxExtension {
 }
 
 impl SyntaxExtension {
-    /// Returns which kind of macro calls this syntax extension.
-    pub fn macro_kind(&self) -> MacroKind {
+    /// Returns which kinds of macro call this syntax extension.
+    pub fn macro_kinds(&self) -> MacroKinds {
         match self.kind {
             SyntaxExtensionKind::Bang(..)
             | SyntaxExtensionKind::LegacyBang(..)
-            | SyntaxExtensionKind::GlobDelegation(..) => MacroKind::Bang,
+            | SyntaxExtensionKind::GlobDelegation(..) => MacroKinds::BANG,
             SyntaxExtensionKind::Attr(..)
             | SyntaxExtensionKind::LegacyAttr(..)
-            | SyntaxExtensionKind::NonMacroAttr => MacroKind::Attr,
+            | SyntaxExtensionKind::NonMacroAttr => MacroKinds::ATTR,
             SyntaxExtensionKind::Derive(..) | SyntaxExtensionKind::LegacyDerive(..) => {
-                MacroKind::Derive
+                MacroKinds::DERIVE
             }
+            SyntaxExtensionKind::MacroRules(ref m) => m.kinds(),
         }
     }
 
@@ -904,10 +939,7 @@ impl SyntaxExtension {
             find_attr!(attrs, AttributeKind::AllowInternalUnstable(i, _) => i)
                 .map(|i| i.as_slice())
                 .unwrap_or_default();
-        // FIXME(jdonszelman): allow_internal_unsafe isn't yet new-style
-        // let allow_internal_unsafe = find_attr!(attrs, AttributeKind::AllowInternalUnsafe);
-        let allow_internal_unsafe =
-            ast::attr::find_by_name(attrs, sym::allow_internal_unsafe).is_some();
+        let allow_internal_unsafe = find_attr!(attrs, AttributeKind::AllowInternalUnsafe(_));
 
         let local_inner_macros = ast::attr::find_by_name(attrs, sym::macro_export)
             .and_then(|macro_export| macro_export.meta_item_list())
@@ -1027,11 +1059,12 @@ impl SyntaxExtension {
         parent: LocalExpnId,
         call_site: Span,
         descr: Symbol,
+        kind: MacroKind,
         macro_def_id: Option<DefId>,
         parent_module: Option<DefId>,
     ) -> ExpnData {
         ExpnData::new(
-            ExpnKind::Macro(self.macro_kind(), descr),
+            ExpnKind::Macro(kind, descr),
             parent.to_expn_id(),
             call_site,
             self.span,
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index e7ae4416968..670f5c91bb9 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -736,8 +736,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
 
         let (fragment_kind, span) = (invoc.fragment_kind, invoc.span());
         ExpandResult::Ready(match invoc.kind {
-            InvocationKind::Bang { mac, span } => match ext {
-                SyntaxExtensionKind::Bang(expander) => {
+            InvocationKind::Bang { mac, span } => {
+                if let SyntaxExtensionKind::Bang(expander) = ext {
                     match expander.expand(self.cx, span, mac.args.tokens.clone()) {
                         Ok(tok_result) => {
                             let fragment =
@@ -755,8 +755,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         }
                         Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)),
                     }
-                }
-                SyntaxExtensionKind::LegacyBang(expander) => {
+                } else if let Some(expander) = ext.as_legacy_bang() {
                     let tok_result = match expander.expand(self.cx, span, mac.args.tokens.clone()) {
                         ExpandResult::Ready(tok_result) => tok_result,
                         ExpandResult::Retry(_) => {
@@ -776,11 +775,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         let guar = self.error_wrong_fragment_kind(fragment_kind, &mac, span);
                         fragment_kind.dummy(span, guar)
                     }
+                } else {
+                    unreachable!();
                 }
-                _ => unreachable!(),
-            },
-            InvocationKind::Attr { attr, pos, mut item, derives } => match ext {
-                SyntaxExtensionKind::Attr(expander) => {
+            }
+            InvocationKind::Attr { attr, pos, mut item, derives } => {
+                if let Some(expander) = ext.as_attr() {
                     self.gate_proc_macro_input(&item);
                     self.gate_proc_macro_attr_item(span, &item);
                     let tokens = match &item {
@@ -835,8 +835,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                         }
                         Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)),
                     }
-                }
-                SyntaxExtensionKind::LegacyAttr(expander) => {
+                } else if let SyntaxExtensionKind::LegacyAttr(expander) = ext {
                     match validate_attr::parse_meta(&self.cx.sess.psess, &attr) {
                         Ok(meta) => {
                             let item_clone = macro_stats.then(|| item.clone());
@@ -878,15 +877,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                             fragment_kind.expect_from_annotatables(iter::once(item))
                         }
                     }
-                }
-                SyntaxExtensionKind::NonMacroAttr => {
+                } else if let SyntaxExtensionKind::NonMacroAttr = ext {
                     // `-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))
+                } else {
+                    unreachable!();
                 }
-                _ => unreachable!(),
-            },
+            }
             InvocationKind::Derive { path, item, is_const } => match ext {
                 SyntaxExtensionKind::Derive(expander)
                 | SyntaxExtensionKind::LegacyDerive(expander) => {
@@ -2155,6 +2154,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                             attr_name,
                             macro_name: pprust::path_to_string(&call.path),
                             invoc_span: call.path.span,
+                            attr_span: attr.span,
                         },
                     );
                 }
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index 5b9d56ee2bc..80433b7be91 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -58,18 +58,6 @@ pub(super) fn failed_to_match_macro(
 
     let Some(BestFailure { token, msg: label, remaining_matcher, .. }) = tracker.best_failure
     else {
-        // FIXME: we should report this at macro resolution time, as we do for
-        // `resolve_macro_cannot_use_as_attr`. We can do that once we track multiple macro kinds for a
-        // Def.
-        if attr_args.is_none() && !rules.iter().any(|rule| matches!(rule, MacroRule::Func { .. })) {
-            let msg = format!("macro has no rules for function-like invocation `{name}!`");
-            let mut err = psess.dcx().struct_span_err(sp, msg);
-            if !def_head_span.is_dummy() {
-                let msg = "this macro has no rules for function-like invocation";
-                err.span_label(def_head_span, msg);
-            }
-            return (sp, err.emit());
-        }
         return (sp, psess.dcx().span_delayed_bug(sp, "failed to match a macro"));
     };
 
diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs
index 25987a50366..faeae1f494e 100644
--- a/compiler/rustc_expand/src/mbe/macro_check.rs
+++ b/compiler/rustc_expand/src/mbe/macro_check.rs
@@ -357,10 +357,10 @@ enum NestedMacroState {
     /// The token `macro_rules` was processed.
     MacroRules,
     /// The tokens `macro_rules!` were processed.
-    MacroRulesNot,
+    MacroRulesBang,
     /// The tokens `macro_rules!` followed by a name were processed. The name may be either directly
     /// an identifier or a meta-variable (that hopefully would be instantiated by an identifier).
-    MacroRulesNotName,
+    MacroRulesBangName,
     /// The keyword `macro` was processed.
     Macro,
     /// The keyword `macro` followed by a name was processed.
@@ -408,24 +408,24 @@ fn check_nested_occurrences(
                 NestedMacroState::MacroRules,
                 &TokenTree::Token(Token { kind: TokenKind::Bang, .. }),
             ) => {
-                state = NestedMacroState::MacroRulesNot;
+                state = NestedMacroState::MacroRulesBang;
             }
             (
-                NestedMacroState::MacroRulesNot,
+                NestedMacroState::MacroRulesBang,
                 &TokenTree::Token(Token { kind: TokenKind::Ident(..), .. }),
             ) => {
-                state = NestedMacroState::MacroRulesNotName;
+                state = NestedMacroState::MacroRulesBangName;
             }
-            (NestedMacroState::MacroRulesNot, &TokenTree::MetaVar(..)) => {
-                state = NestedMacroState::MacroRulesNotName;
+            (NestedMacroState::MacroRulesBang, &TokenTree::MetaVar(..)) => {
+                state = NestedMacroState::MacroRulesBangName;
                 // We check that the meta-variable is correctly used.
                 check_occurrences(psess, node_id, tt, macros, binders, ops, guar);
             }
-            (NestedMacroState::MacroRulesNotName, TokenTree::Delimited(.., del))
+            (NestedMacroState::MacroRulesBangName, TokenTree::Delimited(.., del))
             | (NestedMacroState::MacroName, TokenTree::Delimited(.., del))
                 if del.delim == Delimiter::Brace =>
             {
-                let macro_rules = state == NestedMacroState::MacroRulesNotName;
+                let macro_rules = state == NestedMacroState::MacroRulesBangName;
                 state = NestedMacroState::Empty;
                 let rest =
                     check_nested_macro(psess, node_id, macro_rules, &del.tts, &nested_macros, guar);
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 08b0efb74a0..334f57f9d62 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -15,6 +15,7 @@ use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan};
 use rustc_feature::Features;
 use rustc_hir as hir;
 use rustc_hir::attrs::AttributeKind;
+use rustc_hir::def::MacroKinds;
 use rustc_hir::find_attr;
 use rustc_lint_defs::BuiltinLintDiag;
 use rustc_lint_defs::builtin::{
@@ -144,6 +145,7 @@ pub struct MacroRulesMacroExpander {
     name: Ident,
     span: Span,
     transparency: Transparency,
+    kinds: MacroKinds,
     rules: Vec<MacroRule>,
 }
 
@@ -158,6 +160,10 @@ impl MacroRulesMacroExpander {
         };
         if has_compile_error_macro(rhs) { None } else { Some((&self.name, span)) }
     }
+
+    pub fn kinds(&self) -> MacroKinds {
+        self.kinds
+    }
 }
 
 impl TTMacroExpander for MacroRulesMacroExpander {
@@ -540,13 +546,13 @@ pub fn compile_declarative_macro(
     span: Span,
     node_id: NodeId,
     edition: Edition,
-) -> (SyntaxExtension, Option<Arc<SyntaxExtension>>, usize) {
+) -> (SyntaxExtension, usize) {
     let mk_syn_ext = |kind| {
         let is_local = is_defined_in_current_crate(node_id);
         SyntaxExtension::new(sess, kind, span, Vec::new(), edition, ident.name, attrs, is_local)
     };
-    let mk_bang_ext = |expander| mk_syn_ext(SyntaxExtensionKind::LegacyBang(expander));
-    let dummy_syn_ext = |guar| (mk_bang_ext(Arc::new(DummyExpander(guar))), None, 0);
+    let dummy_syn_ext =
+        |guar| (mk_syn_ext(SyntaxExtensionKind::LegacyBang(Arc::new(DummyExpander(guar)))), 0);
 
     let macro_rules = macro_def.macro_rules;
     let exp_sep = if macro_rules { exp!(Semi) } else { exp!(Comma) };
@@ -559,12 +565,12 @@ pub fn compile_declarative_macro(
     let mut guar = None;
     let mut check_emission = |ret: Result<(), ErrorGuaranteed>| guar = guar.or(ret.err());
 
-    let mut has_attr_rules = false;
+    let mut kinds = MacroKinds::empty();
     let mut rules = Vec::new();
 
     while p.token != token::Eof {
         let args = if p.eat_keyword_noexpect(sym::attr) {
-            has_attr_rules = true;
+            kinds |= MacroKinds::ATTR;
             if !features.macro_attr() {
                 feature_err(sess, sym::macro_attr, span, "`macro_rules!` attributes are unstable")
                     .emit();
@@ -581,6 +587,7 @@ pub fn compile_declarative_macro(
             }
             Some(args)
         } else {
+            kinds |= MacroKinds::BANG;
             None
         };
         let lhs_tt = p.parse_token_tree();
@@ -627,6 +634,7 @@ pub fn compile_declarative_macro(
         let guar = sess.dcx().span_err(span, "macros must contain at least one rule");
         return dummy_syn_ext(guar);
     }
+    assert!(!kinds.is_empty());
 
     let transparency = find_attr!(attrs, AttributeKind::MacroTransparency(x) => *x)
         .unwrap_or(Transparency::fallback(macro_rules));
@@ -640,12 +648,8 @@ pub fn compile_declarative_macro(
     // Return the number of rules for unused rule linting, if this is a local macro.
     let nrules = if is_defined_in_current_crate(node_id) { rules.len() } else { 0 };
 
-    let exp = Arc::new(MacroRulesMacroExpander { name: ident, span, node_id, transparency, rules });
-    let opt_attr_ext = has_attr_rules.then(|| {
-        let exp = Arc::clone(&exp);
-        Arc::new(mk_syn_ext(SyntaxExtensionKind::Attr(exp)))
-    });
-    (mk_bang_ext(exp), opt_attr_ext, nrules)
+    let exp = MacroRulesMacroExpander { name: ident, kinds, span, node_id, transparency, rules };
+    (mk_syn_ext(SyntaxExtensionKind::MacroRules(Arc::new(exp))), nrules)
 }
 
 fn check_no_eof(sess: &Session, p: &Parser<'_>, msg: &'static str) -> Option<ErrorGuaranteed> {
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 5c63d4808db..ab6b8f92802 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -120,13 +120,15 @@ pub struct AttributeTemplate {
     /// If `true`, the attribute is allowed to be a bare word like `#[test]`.
     pub word: bool,
     /// If `Some`, the attribute is allowed to take a list of items like `#[allow(..)]`.
-    pub list: Option<&'static str>,
+    pub list: Option<&'static [&'static str]>,
     /// If non-empty, the attribute is allowed to take a list containing exactly
     /// one of the listed words, like `#[coverage(off)]`.
     pub one_of: &'static [Symbol],
     /// If `Some`, the attribute is allowed to be a name/value pair where the
     /// value is a string, like `#[must_use = "reason"]`.
-    pub name_value_str: Option<&'static str>,
+    pub name_value_str: Option<&'static [&'static str]>,
+    /// A link to the document for this attribute.
+    pub docs: Option<&'static str>,
 }
 
 impl AttributeTemplate {
@@ -137,11 +139,15 @@ impl AttributeTemplate {
             suggestions.push(format!("#{inner}[{name}]"));
         }
         if let Some(descr) = self.list {
-            suggestions.push(format!("#{inner}[{name}({descr})]"));
+            for descr in descr {
+                suggestions.push(format!("#{inner}[{name}({descr})]"));
+            }
         }
         suggestions.extend(self.one_of.iter().map(|&word| format!("#{inner}[{name}({word})]")));
         if let Some(descr) = self.name_value_str {
-            suggestions.push(format!("#{inner}[{name} = \"{descr}\"]"));
+            for descr in descr {
+                suggestions.push(format!("#{inner}[{name} = \"{descr}\"]"));
+            }
         }
         suggestions.sort();
 
@@ -205,20 +211,33 @@ pub enum AttributeDuplicates {
 /// supports forms `#[attr]` and `#[attr(description)]`.
 #[macro_export]
 macro_rules! template {
-    (Word) => { $crate::template!(@ true, None, &[], None) };
-    (List: $descr: expr) => { $crate::template!(@ false, Some($descr), &[], None) };
-    (OneOf: $one_of: expr) => { $crate::template!(@ false, None, $one_of, None) };
-    (NameValueStr: $descr: expr) => { $crate::template!(@ false, None, &[], Some($descr)) };
-    (Word, List: $descr: expr) => { $crate::template!(@ true, Some($descr), &[], None) };
-    (Word, NameValueStr: $descr: expr) => { $crate::template!(@ true, None, &[], Some($descr)) };
+    (Word) => { $crate::template!(@ true, None, &[], None, None) };
+    (Word, $link: literal) => { $crate::template!(@ true, None, &[], None, Some($link)) };
+    (List: $descr: expr) => { $crate::template!(@ false, Some($descr), &[], None, None) };
+    (List: $descr: expr, $link: literal) => { $crate::template!(@ false, Some($descr), &[], None, Some($link)) };
+    (OneOf: $one_of: expr) => { $crate::template!(@ false, None, $one_of, None, None) };
+    (NameValueStr: [$($descr: literal),* $(,)?]) => { $crate::template!(@ false, None, &[], Some(&[$($descr,)*]), None) };
+    (NameValueStr: [$($descr: literal),* $(,)?], $link: literal) => { $crate::template!(@ false, None, &[], Some(&[$($descr,)*]), Some($link)) };
+    (NameValueStr: $descr: literal) => { $crate::template!(@ false, None, &[], Some(&[$descr]), None) };
+    (NameValueStr: $descr: literal, $link: literal) => { $crate::template!(@ false, None, &[], Some(&[$descr]), Some($link)) };
+    (Word, List: $descr: expr) => { $crate::template!(@ true, Some($descr), &[], None, None) };
+    (Word, List: $descr: expr, $link: literal) => { $crate::template!(@ true, Some($descr), &[], None, Some($link)) };
+    (Word, NameValueStr: $descr: expr) => { $crate::template!(@ true, None, &[], Some(&[$descr]), None) };
+    (Word, NameValueStr: $descr: expr, $link: literal) => { $crate::template!(@ true, None, &[], Some(&[$descr]), Some($link)) };
     (List: $descr1: expr, NameValueStr: $descr2: expr) => {
-        $crate::template!(@ false, Some($descr1), &[], Some($descr2))
+        $crate::template!(@ false, Some($descr1), &[], Some(&[$descr2]), None)
+    };
+    (List: $descr1: expr, NameValueStr: $descr2: expr, $link: literal) => {
+        $crate::template!(@ false, Some($descr1), &[], Some(&[$descr2]), Some($link))
     };
     (Word, List: $descr1: expr, NameValueStr: $descr2: expr) => {
-        $crate::template!(@ true, Some($descr1), &[], Some($descr2))
+        $crate::template!(@ true, Some($descr1), &[], Some(&[$descr2]), None)
     };
-    (@ $word: expr, $list: expr, $one_of: expr, $name_value_str: expr) => { $crate::AttributeTemplate {
-        word: $word, list: $list, one_of: $one_of, name_value_str: $name_value_str
+    (Word, List: $descr1: expr, NameValueStr: $descr2: expr, $link: literal) => {
+        $crate::template!(@ true, Some($descr1), &[], Some(&[$descr2]), Some($link))
+    };
+    (@ $word: expr, $list: expr, $one_of: expr, $name_value_str: expr, $link: expr) => { $crate::AttributeTemplate {
+        word: $word, list: $list, one_of: $one_of, name_value_str: $name_value_str, docs: $link,
     } };
 }
 
@@ -391,18 +410,42 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // ==========================================================================
 
     // Conditional compilation:
-    ungated!(cfg, Normal, template!(List: "predicate"), DuplicatesOk, EncodeCrossCrate::Yes),
-    ungated!(cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ..."), DuplicatesOk, EncodeCrossCrate::Yes),
+    ungated!(
+        cfg, Normal,
+        template!(
+            List: &["predicate"],
+            "https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute"
+        ),
+        DuplicatesOk, EncodeCrossCrate::Yes
+    ),
+    ungated!(
+        cfg_attr, Normal,
+        template!(
+            List: &["predicate, attr1, attr2, ..."],
+            "https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute"
+        ),
+        DuplicatesOk, EncodeCrossCrate::Yes
+    ),
 
     // Testing:
     ungated!(
-        ignore, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing,
-        EncodeCrossCrate::No,
+        ignore, Normal,
+        template!(
+            Word,
+            NameValueStr: "reason",
+            "https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute"
+        ),
+        WarnFollowing, EncodeCrossCrate::No,
     ),
     ungated!(
         should_panic, Normal,
-        template!(Word, List: r#"expected = "reason""#, NameValueStr: "reason"), FutureWarnFollowing,
-        EncodeCrossCrate::No,
+        template!(
+            Word,
+            List: &[r#"expected = "reason""#],
+            NameValueStr: "reason",
+            "https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute"
+        ),
+        FutureWarnFollowing, EncodeCrossCrate::No,
     ),
     // FIXME(Centril): This can be used on stable but shouldn't.
     ungated!(
@@ -411,46 +454,102 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
 
     // Macros:
-    ungated!(automatically_derived, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes),
     ungated!(
-        macro_use, Normal, template!(Word, List: "name1, name2, ..."), WarnFollowingWordOnly,
-        EncodeCrossCrate::No,
+        automatically_derived, Normal,
+        template!(
+            Word,
+            "https://doc.rust-lang.org/reference/attributes/derive.html#the-automatically_derived-attribute"
+        ),
+        WarnFollowing, EncodeCrossCrate::Yes
+    ),
+    ungated!(
+        macro_use, Normal,
+        template!(
+            Word,
+            List: &["name1, name2, ..."],
+            "https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute"
+        ),
+        WarnFollowingWordOnly, EncodeCrossCrate::No,
     ),
     ungated!(macro_escape, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), // Deprecated synonym for `macro_use`.
     ungated!(
-        macro_export, Normal, template!(Word, List: "local_inner_macros"),
+        macro_export, Normal,
+        template!(
+            Word,
+            List: &["local_inner_macros"],
+            "https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope"
+        ),
         WarnFollowing, EncodeCrossCrate::Yes
     ),
-    ungated!(proc_macro, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No),
     ungated!(
-        proc_macro_derive, Normal, template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)"),
+        proc_macro, Normal,
+        template!(
+            Word,
+            "https://doc.rust-lang.org/reference/procedural-macros.html#function-like-procedural-macros"),
+        ErrorFollowing, EncodeCrossCrate::No
+    ),
+    ungated!(
+        proc_macro_derive, Normal,
+        template!(
+            List: &["TraitName", "TraitName, attributes(name1, name2, ...)"],
+            "https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros"
+        ),
         ErrorFollowing, EncodeCrossCrate::No,
     ),
-    ungated!(proc_macro_attribute, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No),
+    ungated!(
+        proc_macro_attribute, Normal,
+        template!(Word, "https://doc.rust-lang.org/reference/procedural-macros.html#attribute-macros"),
+        ErrorFollowing, EncodeCrossCrate::No
+    ),
 
     // Lints:
     ungated!(
-        warn, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
+        warn, Normal,
+        template!(
+            List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
+            "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
+        ),
         DuplicatesOk, EncodeCrossCrate::No,
     ),
     ungated!(
-        allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
+        allow, Normal,
+        template!(
+            List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
+            "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
+        ),
         DuplicatesOk, EncodeCrossCrate::No,
     ),
     ungated!(
-        expect, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
+        expect, Normal,
+        template!(
+            List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
+            "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
+        ),
         DuplicatesOk, EncodeCrossCrate::No,
     ),
     ungated!(
-        forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
+        forbid, Normal,
+        template!(
+            List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
+            "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
+        ),
         DuplicatesOk, EncodeCrossCrate::No
     ),
     ungated!(
-        deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
+        deny, Normal,
+        template!(
+            List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
+            "https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
+        ),
         DuplicatesOk, EncodeCrossCrate::No
     ),
     ungated!(
-        must_use, Normal, template!(Word, NameValueStr: "reason"),
+        must_use, Normal,
+        template!(
+            Word,
+            NameValueStr: "reason",
+            "https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute"
+        ),
         FutureWarnFollowing, EncodeCrossCrate::Yes
     ),
     gated!(
@@ -461,52 +560,104 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         deprecated, Normal,
         template!(
             Word,
-            List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#,
-            NameValueStr: "reason"
+            List: &[r#"/*opt*/ since = "version", /*opt*/ note = "reason""#],
+            NameValueStr: "reason",
+            "https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-deprecated-attribute"
         ),
         ErrorFollowing, EncodeCrossCrate::Yes
     ),
 
     // Crate properties:
     ungated!(
-        crate_name, CrateLevel, template!(NameValueStr: "name"), FutureWarnFollowing,
-        EncodeCrossCrate::No,
+        crate_name, CrateLevel,
+        template!(
+            NameValueStr: "name",
+            "https://doc.rust-lang.org/reference/crates-and-source-files.html#the-crate_name-attribute"
+        ),
+        FutureWarnFollowing, EncodeCrossCrate::No,
     ),
     ungated!(
-        crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), DuplicatesOk,
-        EncodeCrossCrate::No,
+        crate_type, CrateLevel,
+        template!(
+            NameValueStr: ["bin", "lib", "dylib", "cdylib", "rlib", "staticlib", "sdylib", "proc-macro"],
+            "https://doc.rust-lang.org/reference/linkage.html"
+        ),
+        DuplicatesOk, EncodeCrossCrate::No,
     ),
 
     // ABI, linking, symbols, and FFI
     ungated!(
         link, Normal,
-        template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated""#),
-        DuplicatesOk,
-        EncodeCrossCrate::No,
+        template!(List: &[
+            r#"name = "...""#,
+            r#"name = "...", kind = "dylib|static|...""#,
+            r#"name = "...", wasm_import_module = "...""#,
+            r#"name = "...", import_name_type = "decorated|noprefix|undecorated""#,
+            r#"name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated""#,
+        ], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute"),
+        DuplicatesOk, EncodeCrossCrate::No,
     ),
     ungated!(
-        link_name, Normal, template!(NameValueStr: "name"),
+        link_name, Normal,
+        template!(NameValueStr: "name", "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute"),
         FutureWarnPreceding, EncodeCrossCrate::Yes
     ),
-    ungated!(no_link, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
-    ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, EncodeCrossCrate::No),
+    ungated!(
+        no_link, Normal,
+        template!(Word, "https://doc.rust-lang.org/reference/items/extern-crates.html#the-no_link-attribute"),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    ungated!(
+        repr, Normal,
+        template!(
+            List: &["C", "Rust", "transparent", "align(...)", "packed(...)", "<integer type>"],
+            "https://doc.rust-lang.org/reference/type-layout.html#representations"
+        ),
+        DuplicatesOk, EncodeCrossCrate::No
+    ),
     // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
-    gated!(rustc_align, Normal, template!(List: "alignment"), DuplicatesOk, EncodeCrossCrate::No, fn_align, experimental!(rustc_align)),
-    ungated!(unsafe(Edition2024) export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
-    ungated!(unsafe(Edition2024) link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
-    ungated!(unsafe(Edition2024) no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
-    ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, EncodeCrossCrate::No),
-    ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, EncodeCrossCrate::Yes),
-    ungated!(unsafe naked, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
+    gated!(rustc_align, Normal, template!(List: &["alignment"]), DuplicatesOk, EncodeCrossCrate::No, fn_align, experimental!(rustc_align)),
+    ungated!(
+        unsafe(Edition2024) export_name, Normal,
+        template!(NameValueStr: "name", "https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute"),
+        FutureWarnPreceding, EncodeCrossCrate::No
+    ),
+    ungated!(
+        unsafe(Edition2024) link_section, Normal,
+        template!(NameValueStr: "name", "https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute"),
+        FutureWarnPreceding, EncodeCrossCrate::No
+    ),
+    ungated!(
+        unsafe(Edition2024) no_mangle, Normal,
+        template!(Word, "https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute"),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    ungated!(
+        used, Normal,
+        template!(Word, List: &["compiler", "linker"], "https://doc.rust-lang.org/reference/abi.html#the-used-attribute"),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    ungated!(
+        link_ordinal, Normal,
+        template!(List: &["ordinal"], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute"),
+        ErrorPreceding, EncodeCrossCrate::Yes
+    ),
+    ungated!(
+        unsafe naked, Normal,
+        template!(Word, "https://doc.rust-lang.org/reference/attributes/codegen.html#the-naked-attribute"),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
 
     // Limits:
     ungated!(
-        recursion_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing,
-        EncodeCrossCrate::No
+        recursion_limit, CrateLevel,
+        template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute"),
+        FutureWarnFollowing, EncodeCrossCrate::No
     ),
     ungated!(
-        type_length_limit, CrateLevel, template!(NameValueStr: "N"), FutureWarnFollowing,
-        EncodeCrossCrate::No
+        type_length_limit, CrateLevel,
+        template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-type_length_limit-attribute"),
+        FutureWarnFollowing, EncodeCrossCrate::No
     ),
     gated!(
         move_size_limit, CrateLevel, template!(NameValueStr: "N"), ErrorFollowing,
@@ -514,35 +665,84 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
 
     // Entry point:
-    ungated!(no_main, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
+    ungated!(
+        no_main, CrateLevel,
+        template!(Word, "https://doc.rust-lang.org/reference/crates-and-source-files.html#the-no_main-attribute"),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
 
     // Modules, prelude, and resolution:
-    ungated!(path, Normal, template!(NameValueStr: "file"), FutureWarnFollowing, EncodeCrossCrate::No),
-    ungated!(no_std, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No),
-    ungated!(no_implicit_prelude, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
-    ungated!(non_exhaustive, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes),
+    ungated!(
+        path, Normal,
+        template!(NameValueStr: "file", "https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute"),
+        FutureWarnFollowing, EncodeCrossCrate::No
+    ),
+    ungated!(
+        no_std, CrateLevel,
+        template!(Word, "https://doc.rust-lang.org/reference/names/preludes.html#the-no_std-attribute"),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    ungated!(
+        no_implicit_prelude, Normal,
+        template!(Word, "https://doc.rust-lang.org/reference/names/preludes.html#the-no_implicit_prelude-attribute"),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    ungated!(
+        non_exhaustive, Normal,
+        template!(Word, "https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute"),
+        WarnFollowing, EncodeCrossCrate::Yes
+    ),
 
     // Runtime
     ungated!(
         windows_subsystem, CrateLevel,
-        template!(NameValueStr: "windows|console"), FutureWarnFollowing,
-        EncodeCrossCrate::No
+        template!(NameValueStr: ["windows", "console"], "https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute"),
+        FutureWarnFollowing, EncodeCrossCrate::No
+    ),
+    ungated!( // RFC 2070
+        panic_handler, Normal,
+        template!(Word, "https://doc.rust-lang.org/reference/panic.html#the-panic_handler-attribute"),
+        WarnFollowing, EncodeCrossCrate::Yes
     ),
-    ungated!(panic_handler, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes), // RFC 2070
 
     // Code generation:
-    ungated!(inline, Normal, template!(Word, List: "always|never"), FutureWarnFollowing, EncodeCrossCrate::No),
-    ungated!(cold, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
-    ungated!(no_builtins, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::Yes),
     ungated!(
-        target_feature, Normal, template!(List: r#"enable = "name""#),
+        inline, Normal,
+        template!(
+            Word,
+            List: &["always", "never"],
+            "https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute"
+        ),
+        FutureWarnFollowing, EncodeCrossCrate::No
+    ),
+    ungated!(
+        cold, Normal,
+        template!(Word, "https://doc.rust-lang.org/reference/attributes/codegen.html#the-cold-attribute"),
+        WarnFollowing, EncodeCrossCrate::No
+    ),
+    ungated!(
+        no_builtins, CrateLevel,
+        template!(Word, "https://doc.rust-lang.org/reference/attributes/codegen.html#the-no_builtins-attribute"),
+        WarnFollowing, EncodeCrossCrate::Yes
+    ),
+    ungated!(
+        target_feature, Normal,
+        template!(List: &[r#"enable = "name""#], "https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute"),
         DuplicatesOk, EncodeCrossCrate::No,
     ),
-    ungated!(track_caller, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes),
-    ungated!(instruction_set, Normal, template!(List: "set"), ErrorPreceding, EncodeCrossCrate::No),
+    ungated!(
+        track_caller, Normal,
+        template!(Word, "https://doc.rust-lang.org/reference/attributes/codegen.html#the-track_caller-attribute"),
+        WarnFollowing, EncodeCrossCrate::Yes
+    ),
+    ungated!(
+        instruction_set, Normal,
+        template!(List: &["set"], "https://doc.rust-lang.org/reference/attributes/codegen.html#the-instruction_set-attribute"),
+        ErrorPreceding, EncodeCrossCrate::No
+    ),
     gated!(
         no_sanitize, Normal,
-        template!(List: "address, kcfi, memory, thread"), DuplicatesOk,
+        template!(List: &["address, kcfi, memory, thread"]), DuplicatesOk,
         EncodeCrossCrate::No, experimental!(no_sanitize)
     ),
     gated!(
@@ -552,18 +752,31 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
 
     ungated!(
-        doc, Normal, template!(List: "hidden|inline|...", NameValueStr: "string"), DuplicatesOk,
-        EncodeCrossCrate::Yes
+        doc, Normal,
+        template!(
+            List: &["hidden", "inline"],
+            NameValueStr: "string",
+            "https://doc.rust-lang.org/rustdoc/write-documentation/the-doc-attribute.html"
+        ),
+        DuplicatesOk, EncodeCrossCrate::Yes
     ),
 
     // Debugging
     ungated!(
         debugger_visualizer, Normal,
-        template!(List: r#"natvis_file = "...", gdb_script_file = "...""#),
+        template!(
+            List: &[r#"natvis_file = "...", gdb_script_file = "...""#],
+            "https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute"
+        ),
         DuplicatesOk, EncodeCrossCrate::No
     ),
-    ungated!(collapse_debuginfo, Normal, template!(List: "no|external|yes"), ErrorFollowing,
-        EncodeCrossCrate::Yes
+    ungated!(
+        collapse_debuginfo, Normal,
+        template!(
+            List: &["no", "external", "yes"],
+            "https://doc.rust-lang.org/reference/attributes/debugger.html#the-collapse_debuginfo-attribute"
+        ),
+        ErrorFollowing, EncodeCrossCrate::Yes
     ),
 
     // ==========================================================================
@@ -578,7 +791,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
 
     // Testing:
     gated!(
-        test_runner, CrateLevel, template!(List: "path"), ErrorFollowing,
+        test_runner, CrateLevel, template!(List: &["path"]), ErrorFollowing,
         EncodeCrossCrate::Yes, custom_test_frameworks,
         "custom test frameworks are an unstable feature",
     ),
@@ -597,7 +810,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
     // RFC 2412
     gated!(
-        optimize, Normal, template!(List: "none|size|speed"), ErrorPreceding,
+        optimize, Normal, template!(List: &["none", "size", "speed"]), ErrorPreceding,
         EncodeCrossCrate::No, optimize_attribute, experimental!(optimize)
     ),
 
@@ -610,7 +823,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         EncodeCrossCrate::No, experimental!(ffi_const)
     ),
     gated!(
-        register_tool, CrateLevel, template!(List: "tool1, tool2, ..."), DuplicatesOk,
+        register_tool, CrateLevel, template!(List: &["tool1, tool2, ..."]), DuplicatesOk,
         EncodeCrossCrate::No, experimental!(register_tool),
     ),
 
@@ -624,7 +837,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
     // lang-team MCP 147
     gated!(
-        deprecated_safe, Normal, template!(List: r#"since = "version", note = "...""#), ErrorFollowing,
+        deprecated_safe, Normal, template!(List: &[r#"since = "version", note = "...""#]), ErrorFollowing,
         EncodeCrossCrate::Yes, experimental!(deprecated_safe),
     ),
 
@@ -643,7 +856,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // RFC 3543
     // `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]`
     gated!(
-        patchable_function_entry, Normal, template!(List: "prefix_nops = m, entry_nops = n"), ErrorPreceding,
+        patchable_function_entry, Normal, template!(List: &["prefix_nops = m, entry_nops = n"]), ErrorPreceding,
         EncodeCrossCrate::Yes, experimental!(patchable_function_entry)
     ),
 
@@ -673,37 +886,37 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
 
     ungated!(
         feature, CrateLevel,
-        template!(List: "name1, name2, ..."), DuplicatesOk, EncodeCrossCrate::No,
+        template!(List: &["name1, name2, ..."]), DuplicatesOk, EncodeCrossCrate::No,
     ),
     // DuplicatesOk since it has its own validation
     ungated!(
         stable, Normal,
-        template!(List: r#"feature = "name", since = "version""#), DuplicatesOk, EncodeCrossCrate::No,
+        template!(List: &[r#"feature = "name", since = "version""#]), DuplicatesOk, EncodeCrossCrate::No,
     ),
     ungated!(
         unstable, Normal,
-        template!(List: r#"feature = "name", reason = "...", issue = "N""#), DuplicatesOk,
+        template!(List: &[r#"feature = "name", reason = "...", issue = "N""#]), DuplicatesOk,
         EncodeCrossCrate::Yes
     ),
     ungated!(
-        unstable_feature_bound, Normal, template!(Word, List: "feat1, feat2, ..."),
+        unstable_feature_bound, Normal, template!(Word, List: &["feat1, feat2, ..."]),
         DuplicatesOk, EncodeCrossCrate::No,
     ),
     ungated!(
-        rustc_const_unstable, Normal, template!(List: r#"feature = "name""#),
+        rustc_const_unstable, Normal, template!(List: &[r#"feature = "name""#]),
         DuplicatesOk, EncodeCrossCrate::Yes
     ),
     ungated!(
         rustc_const_stable, Normal,
-        template!(List: r#"feature = "name""#), DuplicatesOk, EncodeCrossCrate::No,
+        template!(List: &[r#"feature = "name""#]), DuplicatesOk, EncodeCrossCrate::No,
     ),
     ungated!(
         rustc_default_body_unstable, Normal,
-        template!(List: r#"feature = "name", reason = "...", issue = "N""#),
+        template!(List: &[r#"feature = "name", reason = "...", issue = "N""#]),
         DuplicatesOk, EncodeCrossCrate::No
     ),
     gated!(
-        allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."),
+        allow_internal_unstable, Normal, template!(Word, List: &["feat1, feat2, ..."]),
         DuplicatesOk, EncodeCrossCrate::Yes,
         "allow_internal_unstable side-steps feature gating and stability checks",
     ),
@@ -718,7 +931,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         through unstable paths"
     ),
     rustc_attr!(
-        rustc_deprecated_safe_2024, Normal, template!(List: r#"audit_that = "...""#),
+        rustc_deprecated_safe_2024, Normal, template!(List: &[r#"audit_that = "...""#]),
         ErrorFollowing, EncodeCrossCrate::Yes,
         "`#[rustc_deprecated_safe_2024]` is used to declare functions unsafe across the edition 2024 boundary",
     ),
@@ -743,7 +956,13 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     rustc_attr!(
         rustc_never_type_options,
         Normal,
-        template!(List: r#"/*opt*/ fallback = "unit|niko|never|no""#),
+        template!(List: &[
+            "",
+            r#"fallback = "unit""#,
+            r#"fallback = "niko""#,
+            r#"fallback = "never""#,
+            r#"fallback = "no""#,
+        ]),
         ErrorFollowing,
         EncodeCrossCrate::No,
         "`rustc_never_type_options` is used to experiment with never type fallback and work on \
@@ -808,7 +1027,17 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // ==========================================================================
 
     gated!(
-        linkage, Normal, template!(NameValueStr: "external|internal|..."),
+        linkage, Normal, template!(NameValueStr: [
+            "available_externally",
+            "common",
+            "extern_weak",
+            "external",
+            "internal",
+            "linkonce",
+            "linkonce_odr",
+            "weak",
+            "weak_odr",
+        ], "https://doc.rust-lang.org/reference/linkage.html"),
         ErrorPreceding, EncodeCrossCrate::No,
         "the `linkage` attribute is experimental and not portable across platforms",
     ),
@@ -823,7 +1052,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
 
     rustc_attr!(
         rustc_builtin_macro, Normal,
-        template!(Word, List: "name, /*opt*/ attributes(name1, name2, ...)"), ErrorFollowing,
+        template!(Word, List: &["name", "name, /*opt*/ attributes(name1, name2, ...)"]), ErrorFollowing,
         EncodeCrossCrate::Yes,
     ),
     rustc_attr!(
@@ -832,12 +1061,12 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
     rustc_attr!(
         rustc_macro_transparency, Normal,
-        template!(NameValueStr: "transparent|semiopaque|opaque"), ErrorFollowing,
+        template!(NameValueStr: ["transparent", "semiopaque", "opaque"]), ErrorFollowing,
         EncodeCrossCrate::Yes, "used internally for testing macro hygiene",
     ),
     rustc_attr!(
         rustc_autodiff, Normal,
-        template!(Word, List: r#""...""#), DuplicatesOk,
+        template!(Word, List: &[r#""...""#]), DuplicatesOk,
         EncodeCrossCrate::Yes,
     ),
     // Traces that are left when `cfg` and `cfg_attr` attributes are expanded.
@@ -860,7 +1089,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     rustc_attr!(
         rustc_on_unimplemented, Normal,
         template!(
-            List: r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#,
+            List: &[r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#],
             NameValueStr: "message"
         ),
         ErrorFollowing, EncodeCrossCrate::Yes,
@@ -868,7 +1097,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
     rustc_attr!(
         rustc_confusables, Normal,
-        template!(List: r#""name1", "name2", ..."#),
+        template!(List: &[r#""name1", "name2", ..."#]),
         ErrorFollowing, EncodeCrossCrate::Yes,
     ),
     // Enumerates "identity-like" conversion methods to suggest on type mismatch.
@@ -909,7 +1138,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // 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"),
+        rustc_lint_opt_deny_field_access, Normal, template!(List: &["message"]),
         WarnFollowing, EncodeCrossCrate::Yes,
     ),
 
@@ -921,7 +1150,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         rustc_promotable, Normal, template!(Word), WarnFollowing,
         EncodeCrossCrate::No, ),
     rustc_attr!(
-        rustc_legacy_const_generics, Normal, template!(List: "N"), ErrorFollowing,
+        rustc_legacy_const_generics, Normal, template!(List: &["N"]), ErrorFollowing,
         EncodeCrossCrate::Yes,
     ),
     // Do not const-check this function's body. It will always get replaced during CTFE via `hook_special_const_fn`.
@@ -946,7 +1175,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     ),
     gated!(
         rustc_allow_const_fn_unstable, Normal,
-        template!(Word, List: "feat1, feat2, ..."), DuplicatesOk, EncodeCrossCrate::No,
+        template!(Word, List: &["feat1, feat2, ..."]), DuplicatesOk, EncodeCrossCrate::No,
         "rustc_allow_const_fn_unstable side-steps feature gating and stability checks"
     ),
 
@@ -955,13 +1184,13 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     // ==========================================================================
 
     rustc_attr!(
-        rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"), ErrorFollowing,
+        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 the standard library",
     ),
     rustc_attr!(
-        rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"), ErrorFollowing,
+        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 the standard library",
@@ -1097,14 +1326,14 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         "the `#[rustc_main]` attribute is used internally to specify test entry point function",
     ),
     rustc_attr!(
-        rustc_skip_during_method_dispatch, Normal, template!(List: "array, boxed_slice"), ErrorFollowing,
+        rustc_skip_during_method_dispatch, Normal, template!(List: &["array, boxed_slice"]), ErrorFollowing,
         EncodeCrossCrate::No,
         "the `#[rustc_skip_during_method_dispatch]` attribute is used to exclude a trait \
         from method dispatch when the receiver is of the following type, for compatibility in \
         editions < 2021 (array) or editions < 2024 (boxed_slice)."
     ),
     rustc_attr!(
-        rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."),
+        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. Its syntax and semantics are highly experimental and will be \
@@ -1166,11 +1395,11 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         WarnFollowing, EncodeCrossCrate::No
     ),
     rustc_attr!(
-        TEST, rustc_layout, Normal, template!(List: "field1, field2, ..."),
+        TEST, rustc_layout, Normal, template!(List: &["field1, field2, ..."]),
         WarnFollowing, EncodeCrossCrate::Yes
     ),
     rustc_attr!(
-        TEST, rustc_abi, Normal, template!(List: "field1, field2, ..."),
+        TEST, rustc_abi, Normal, template!(List: &["field1, field2, ..."]),
         WarnFollowing, EncodeCrossCrate::No
     ),
     rustc_attr!(
@@ -1191,29 +1420,29 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         EncodeCrossCrate::Yes
     ),
     rustc_attr!(
-        TEST, rustc_if_this_changed, Normal, template!(Word, List: "DepNode"), DuplicatesOk,
+        TEST, rustc_if_this_changed, Normal, template!(Word, List: &["DepNode"]), DuplicatesOk,
         EncodeCrossCrate::No
     ),
     rustc_attr!(
-        TEST, rustc_then_this_would_need, Normal, template!(List: "DepNode"), DuplicatesOk,
+        TEST, rustc_then_this_would_need, Normal, template!(List: &["DepNode"]), DuplicatesOk,
         EncodeCrossCrate::No
     ),
     rustc_attr!(
         TEST, rustc_clean, Normal,
-        template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
+        template!(List: &[r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#]),
         DuplicatesOk, EncodeCrossCrate::No
     ),
     rustc_attr!(
         TEST, rustc_partition_reused, Normal,
-        template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk, EncodeCrossCrate::No
+        template!(List: &[r#"cfg = "...", module = "...""#]), DuplicatesOk, EncodeCrossCrate::No
     ),
     rustc_attr!(
         TEST, rustc_partition_codegened, Normal,
-        template!(List: r#"cfg = "...", module = "...""#), DuplicatesOk, EncodeCrossCrate::No
+        template!(List: &[r#"cfg = "...", module = "...""#]), DuplicatesOk, EncodeCrossCrate::No
     ),
     rustc_attr!(
         TEST, rustc_expected_cgu_reuse, Normal,
-        template!(List: r#"cfg = "...", module = "...", kind = "...""#), DuplicatesOk,
+        template!(List: &[r#"cfg = "...", module = "...", kind = "...""#]), DuplicatesOk,
         EncodeCrossCrate::No
     ),
     rustc_attr!(
@@ -1225,11 +1454,11 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         WarnFollowing, EncodeCrossCrate::No
     ),
     rustc_attr!(
-        TEST, rustc_mir, Normal, template!(List: "arg1, arg2, ..."),
+        TEST, rustc_mir, Normal, template!(List: &["arg1, arg2, ..."]),
         DuplicatesOk, EncodeCrossCrate::Yes
     ),
     gated!(
-        custom_mir, Normal, template!(List: r#"dialect = "...", phase = "...""#),
+        custom_mir, Normal, template!(List: &[r#"dialect = "...", phase = "...""#]),
         ErrorFollowing, EncodeCrossCrate::No,
         "the `#[custom_mir]` attribute is just used for the Rust test suite",
     ),
diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml
index 539d2e6f0b1..71496b7ec32 100644
--- a/compiler/rustc_hir/Cargo.toml
+++ b/compiler/rustc_hir/Cargo.toml
@@ -5,6 +5,7 @@ edition = "2024"
 
 [dependencies]
 # tidy-alphabetical-start
+bitflags = "2.9.1"
 odht = { version = "0.3.1", features = ["nightly"] }
 rustc_abi = { path = "../rustc_abi" }
 rustc_arena = { path = "../rustc_arena" }
diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs
index 5f419315467..e02edf5fe24 100644
--- a/compiler/rustc_hir/src/attrs/data_structures.rs
+++ b/compiler/rustc_hir/src/attrs/data_structures.rs
@@ -249,6 +249,9 @@ pub enum AttributeKind {
     /// Represents `#[rustc_allow_incoherent_impl]`.
     AllowIncoherentImpl(Span),
 
+    /// Represents `#[allow_internal_unsafe]`.
+    AllowInternalUnsafe(Span),
+
     /// Represents `#[allow_internal_unstable]`.
     AllowInternalUnstable(ThinVec<(Symbol, Span)>, Span),
 
diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
index e3a7f0b97a8..7ce624dcc55 100644
--- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
+++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs
@@ -16,6 +16,7 @@ impl AttributeKind {
             Align { .. } => No,
             AllowConstFnUnstable(..) => No,
             AllowIncoherentImpl(..) => No,
+            AllowInternalUnsafe(..) => Yes,
             AllowInternalUnstable(..) => Yes,
             AsPtr(..) => Yes,
             AutomaticallyDerived(..) => Yes,
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 339d4e2eab7..79319e24266 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -31,6 +31,53 @@ pub enum CtorKind {
     Const,
 }
 
+/// A set of macro kinds, for macros that can have more than one kind
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable, Hash, Debug)]
+#[derive(HashStable_Generic)]
+pub struct MacroKinds(u8);
+bitflags::bitflags! {
+    impl MacroKinds: u8 {
+        const BANG = 1 << 0;
+        const ATTR = 1 << 1;
+        const DERIVE = 1 << 2;
+    }
+}
+
+impl From<MacroKind> for MacroKinds {
+    fn from(kind: MacroKind) -> Self {
+        match kind {
+            MacroKind::Bang => Self::BANG,
+            MacroKind::Attr => Self::ATTR,
+            MacroKind::Derive => Self::DERIVE,
+        }
+    }
+}
+
+impl MacroKinds {
+    /// Convert the MacroKinds to a static string.
+    ///
+    /// This hardcodes all the possibilities, in order to return a static string.
+    pub fn descr(self) -> &'static str {
+        match self {
+            // FIXME: change this to "function-like macro" and fix all tests
+            Self::BANG => "macro",
+            Self::ATTR => "attribute macro",
+            Self::DERIVE => "derive macro",
+            _ if self == (Self::ATTR | Self::BANG) => "attribute/function macro",
+            _ if self == (Self::DERIVE | Self::BANG) => "derive/function macro",
+            _ if self == (Self::ATTR | Self::DERIVE) => "attribute/derive macro",
+            _ if self.is_all() => "attribute/derive/function macro",
+            _ if self.is_empty() => "useless macro",
+            _ => unreachable!(),
+        }
+    }
+
+    /// Return an indefinite article (a/an) for use with `descr()`
+    pub fn article(self) -> &'static str {
+        if self.contains(Self::ATTR) { "an" } else { "a" }
+    }
+}
+
 /// An attribute that is not a macro; e.g., `#[inline]` or `#[rustfmt::skip]`.
 #[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Hash, Debug, HashStable_Generic)]
 pub enum NonMacroAttrKind {
@@ -101,7 +148,7 @@ pub enum DefKind {
     AssocConst,
 
     // Macro namespace
-    Macro(MacroKind),
+    Macro(MacroKinds),
 
     // Not namespaced (or they are, but we don't treat them so)
     ExternCrate,
@@ -177,7 +224,7 @@ impl DefKind {
             DefKind::AssocConst => "associated constant",
             DefKind::TyParam => "type parameter",
             DefKind::ConstParam => "const parameter",
-            DefKind::Macro(macro_kind) => macro_kind.descr(),
+            DefKind::Macro(kinds) => kinds.descr(),
             DefKind::LifetimeParam => "lifetime parameter",
             DefKind::Use => "import",
             DefKind::ForeignMod => "foreign module",
@@ -208,7 +255,7 @@ impl DefKind {
             | DefKind::Use
             | DefKind::InlineConst
             | DefKind::ExternCrate => "an",
-            DefKind::Macro(macro_kind) => macro_kind.article(),
+            DefKind::Macro(kinds) => kinds.article(),
             _ => "a",
         }
     }
@@ -845,10 +892,10 @@ impl<Id> Res<Id> {
         )
     }
 
-    pub fn macro_kind(self) -> Option<MacroKind> {
+    pub fn macro_kinds(self) -> Option<MacroKinds> {
         match self {
-            Res::Def(DefKind::Macro(kind), _) => Some(kind),
-            Res::NonMacroAttr(..) => Some(MacroKind::Attr),
+            Res::Def(DefKind::Macro(kinds), _) => Some(kinds),
+            Res::NonMacroAttr(..) => Some(MacroKinds::ATTR),
             _ => None,
         }
     }
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 34db6f92d92..e8feb721984 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -20,7 +20,6 @@ use rustc_data_structures::tagged_ptr::TaggedRef;
 use rustc_index::IndexVec;
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_span::def_id::LocalDefId;
-use rustc_span::hygiene::MacroKind;
 use rustc_span::source_map::Spanned;
 use rustc_span::{BytePos, DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
 use rustc_target::asm::InlineAsmRegOrRegClass;
@@ -30,7 +29,7 @@ use tracing::debug;
 
 use crate::LangItem;
 use crate::attrs::AttributeKind;
-use crate::def::{CtorKind, DefKind, PerNS, Res};
+use crate::def::{CtorKind, DefKind, MacroKinds, PerNS, Res};
 use crate::def_id::{DefId, LocalDefIdMap};
 pub(crate) use crate::hir_id::{HirId, ItemLocalId, ItemLocalMap, OwnerId};
 use crate::intravisit::{FnKind, VisitorExt};
@@ -1310,6 +1309,7 @@ impl AttributeExt for Attribute {
             Attribute::Parsed(AttributeKind::Ignore { span, .. }) => *span,
             Attribute::Parsed(AttributeKind::ShouldPanic { span, .. }) => *span,
             Attribute::Parsed(AttributeKind::AutomaticallyDerived(span)) => *span,
+            Attribute::Parsed(AttributeKind::AllowInternalUnsafe(span)) => *span,
             a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"),
         }
     }
@@ -4156,7 +4156,7 @@ impl<'hir> Item<'hir> {
         expect_fn, (Ident, &FnSig<'hir>, &'hir Generics<'hir>, BodyId),
             ItemKind::Fn { ident, sig, generics, body, .. }, (*ident, sig, generics, *body);
 
-        expect_macro, (Ident, &ast::MacroDef, MacroKind),
+        expect_macro, (Ident, &ast::MacroDef, MacroKinds),
             ItemKind::Macro(ident, def, mk), (*ident, def, *mk);
 
         expect_mod, (Ident, &'hir Mod<'hir>), ItemKind::Mod(ident, m), (*ident, m);
@@ -4194,7 +4194,7 @@ impl<'hir> Item<'hir> {
         expect_trait_alias, (Ident, &'hir Generics<'hir>, GenericBounds<'hir>),
             ItemKind::TraitAlias(ident, generics, bounds), (*ident, generics, bounds);
 
-        expect_impl, &'hir Impl<'hir>, ItemKind::Impl(imp), imp;
+        expect_impl, &Impl<'hir>, ItemKind::Impl(imp), imp;
     }
 }
 
@@ -4335,7 +4335,7 @@ pub enum ItemKind<'hir> {
         has_body: bool,
     },
     /// A MBE macro definition (`macro_rules!` or `macro`).
-    Macro(Ident, &'hir ast::MacroDef, MacroKind),
+    Macro(Ident, &'hir ast::MacroDef, MacroKinds),
     /// A module.
     Mod(Ident, &'hir Mod<'hir>),
     /// An external module, e.g. `extern { .. }`.
@@ -4372,7 +4372,7 @@ pub enum ItemKind<'hir> {
     TraitAlias(Ident, &'hir Generics<'hir>, GenericBounds<'hir>),
 
     /// An implementation, e.g., `impl<A> Trait for Foo { .. }`.
-    Impl(&'hir Impl<'hir>),
+    Impl(Impl<'hir>),
 }
 
 /// Represents an impl block declaration.
@@ -4381,6 +4381,14 @@ pub enum ItemKind<'hir> {
 /// Refer to [`ImplItem`] for an associated item within an impl block.
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
 pub struct Impl<'hir> {
+    pub generics: &'hir Generics<'hir>,
+    pub of_trait: Option<&'hir TraitImplHeader<'hir>>,
+    pub self_ty: &'hir Ty<'hir>,
+    pub items: &'hir [ImplItemId],
+}
+
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
+pub struct TraitImplHeader<'hir> {
     pub constness: Constness,
     pub safety: Safety,
     pub polarity: ImplPolarity,
@@ -4388,13 +4396,7 @@ pub struct Impl<'hir> {
     // We do not put a `Span` in `Defaultness` because it breaks foreign crate metadata
     // decoding as `Span`s cannot be decoded when a `Session` is not available.
     pub defaultness_span: Option<Span>,
-    pub generics: &'hir Generics<'hir>,
-
-    /// The trait being implemented, if any.
-    pub of_trait: Option<TraitRef<'hir>>,
-
-    pub self_ty: &'hir Ty<'hir>,
-    pub items: &'hir [ImplItemId],
+    pub trait_ref: TraitRef<'hir>,
 }
 
 impl ItemKind<'_> {
@@ -4756,8 +4758,8 @@ impl<'hir> Node<'hir> {
     /// Get a `hir::Impl` if the node is an impl block for the given `trait_def_id`.
     pub fn impl_block_of_trait(self, trait_def_id: DefId) -> Option<&'hir Impl<'hir>> {
         if let Node::Item(Item { kind: ItemKind::Impl(impl_block), .. }) = self
-            && let Some(trait_ref) = impl_block.of_trait
-            && let Some(trait_id) = trait_ref.trait_def_id()
+            && let Some(of_trait) = impl_block.of_trait
+            && let Some(trait_id) = of_trait.trait_ref.trait_def_id()
             && trait_id == trait_def_id
         {
             Some(impl_block)
@@ -4952,7 +4954,7 @@ mod size_asserts {
     static_assert_size!(GenericArg<'_>, 16);
     static_assert_size!(GenericBound<'_>, 64);
     static_assert_size!(Generics<'_>, 56);
-    static_assert_size!(Impl<'_>, 80);
+    static_assert_size!(Impl<'_>, 40);
     static_assert_size!(ImplItem<'_>, 96);
     static_assert_size!(ImplItemKind<'_>, 40);
     static_assert_size!(Item<'_>, 88);
@@ -4967,6 +4969,7 @@ mod size_asserts {
     static_assert_size!(Res, 12);
     static_assert_size!(Stmt<'_>, 32);
     static_assert_size!(StmtKind<'_>, 16);
+    static_assert_size!(TraitImplHeader<'_>, 48);
     static_assert_size!(TraitItem<'_>, 88);
     static_assert_size!(TraitItemKind<'_>, 48);
     static_assert_size!(Ty<'_>, 48);
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 23fa466859a..9b2f8ae75fa 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -590,21 +590,21 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) -> V::
             try_visit!(visitor.visit_generics(generics));
             try_visit!(visitor.visit_enum_def(enum_definition));
         }
-        ItemKind::Impl(Impl {
-            constness: _,
-            safety: _,
-            defaultness: _,
-            polarity: _,
-            defaultness_span: _,
-            generics,
-            of_trait,
-            self_ty,
-            items,
-        }) => {
+        ItemKind::Impl(Impl { generics, of_trait, self_ty, items }) => {
             try_visit!(visitor.visit_generics(generics));
-            visit_opt!(visitor, visit_trait_ref, of_trait);
+            if let Some(TraitImplHeader {
+                constness: _,
+                safety: _,
+                polarity: _,
+                defaultness: _,
+                defaultness_span: _,
+                trait_ref,
+            }) = of_trait
+            {
+                try_visit!(visitor.visit_trait_ref(trait_ref));
+            }
             try_visit!(visitor.visit_ty_unambig(self_ty));
-            walk_list!(visitor, visit_impl_item_ref, *items);
+            walk_list!(visitor, visit_impl_item_ref, items);
         }
         ItemKind::Struct(ident, ref generics, ref struct_definition)
         | ItemKind::Union(ident, ref generics, ref struct_definition) => {
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index a62efed13bc..c642435b989 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -244,48 +244,48 @@ pub(super) fn check_item<'tcx>(
         //
         // won't be allowed unless there's an *explicit* implementation of `Send`
         // for `T`
-        hir::ItemKind::Impl(impl_) => {
-            let header = tcx.impl_trait_header(def_id);
-            let is_auto = header
-                .is_some_and(|header| tcx.trait_is_auto(header.trait_ref.skip_binder().def_id));
-
+        hir::ItemKind::Impl(ref impl_) => {
             crate::impl_wf_check::check_impl_wf(tcx, def_id)?;
             let mut res = Ok(());
-            if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) {
-                let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span);
-                res = Err(tcx
-                    .dcx()
-                    .struct_span_err(sp, "impls of auto traits cannot be default")
-                    .with_span_labels(impl_.defaultness_span, "default because of this")
-                    .with_span_label(sp, "auto trait")
-                    .emit());
-            }
-            // We match on both `ty::ImplPolarity` and `ast::ImplPolarity` just to get the `!` span.
-            match header.map(|h| h.polarity) {
-                // `None` means this is an inherent impl
-                Some(ty::ImplPolarity::Positive) | None => {
-                    res = res.and(check_impl(tcx, item, impl_.self_ty, &impl_.of_trait));
-                }
-                Some(ty::ImplPolarity::Negative) => {
-                    let ast::ImplPolarity::Negative(span) = impl_.polarity else {
-                        bug!("impl_polarity query disagrees with impl's polarity in HIR");
-                    };
-                    // FIXME(#27579): what amount of WF checking do we need for neg impls?
-                    if let hir::Defaultness::Default { .. } = impl_.defaultness {
-                        let mut spans = vec![span];
-                        spans.extend(impl_.defaultness_span);
-                        res = Err(struct_span_code_err!(
-                            tcx.dcx(),
-                            spans,
-                            E0750,
-                            "negative impls cannot be default impls"
-                        )
+            if let Some(of_trait) = impl_.of_trait {
+                let header = tcx.impl_trait_header(def_id).unwrap();
+                let is_auto = tcx.trait_is_auto(header.trait_ref.skip_binder().def_id);
+                if let (hir::Defaultness::Default { .. }, true) = (of_trait.defaultness, is_auto) {
+                    let sp = of_trait.trait_ref.path.span;
+                    res = Err(tcx
+                        .dcx()
+                        .struct_span_err(sp, "impls of auto traits cannot be default")
+                        .with_span_labels(of_trait.defaultness_span, "default because of this")
+                        .with_span_label(sp, "auto trait")
                         .emit());
-                    }
                 }
-                Some(ty::ImplPolarity::Reservation) => {
-                    // FIXME: what amount of WF checking do we need for reservation impls?
+                match header.polarity {
+                    ty::ImplPolarity::Positive => {
+                        res = res.and(check_impl(tcx, item, impl_));
+                    }
+                    ty::ImplPolarity::Negative => {
+                        let ast::ImplPolarity::Negative(span) = of_trait.polarity else {
+                            bug!("impl_polarity query disagrees with impl's polarity in HIR");
+                        };
+                        // FIXME(#27579): what amount of WF checking do we need for neg impls?
+                        if let hir::Defaultness::Default { .. } = of_trait.defaultness {
+                            let mut spans = vec![span];
+                            spans.extend(of_trait.defaultness_span);
+                            res = Err(struct_span_code_err!(
+                                tcx.dcx(),
+                                spans,
+                                E0750,
+                                "negative impls cannot be default impls"
+                            )
+                            .emit());
+                        }
+                    }
+                    ty::ImplPolarity::Reservation => {
+                        // FIXME: what amount of WF checking do we need for reservation impls?
+                    }
                 }
+            } else {
+                res = res.and(check_impl(tcx, item, impl_));
             }
             res
         }
@@ -1258,16 +1258,15 @@ pub(crate) fn check_const_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<()
     })
 }
 
-#[instrument(level = "debug", skip(tcx, hir_self_ty, hir_trait_ref))]
+#[instrument(level = "debug", skip(tcx, impl_))]
 fn check_impl<'tcx>(
     tcx: TyCtxt<'tcx>,
     item: &'tcx hir::Item<'tcx>,
-    hir_self_ty: &hir::Ty<'_>,
-    hir_trait_ref: &Option<hir::TraitRef<'_>>,
+    impl_: &hir::Impl<'_>,
 ) -> Result<(), ErrorGuaranteed> {
     enter_wf_checking_ctxt(tcx, item.owner_id.def_id, |wfcx| {
-        match hir_trait_ref {
-            Some(hir_trait_ref) => {
+        match impl_.of_trait {
+            Some(of_trait) => {
                 // `#[rustc_reservation_impl]` impls are not real impls and
                 // therefore don't need to be WF (the trait's `Self: Trait` predicate
                 // won't hold).
@@ -1275,7 +1274,7 @@ fn check_impl<'tcx>(
                 // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
                 // other `Foo` impls are incoherent.
                 tcx.ensure_ok().coherent_trait(trait_ref.def_id)?;
-                let trait_span = hir_trait_ref.path.span;
+                let trait_span = of_trait.trait_ref.path.span;
                 let trait_ref = wfcx.deeply_normalize(
                     trait_span,
                     Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
@@ -1299,12 +1298,12 @@ fn check_impl<'tcx>(
                     if let Some(pred) = obligation.predicate.as_trait_clause()
                         && pred.skip_binder().self_ty() == trait_ref.self_ty()
                     {
-                        obligation.cause.span = hir_self_ty.span;
+                        obligation.cause.span = impl_.self_ty.span;
                     }
                     if let Some(pred) = obligation.predicate.as_projection_clause()
                         && pred.skip_binder().self_ty() == trait_ref.self_ty()
                     {
-                        obligation.cause.span = hir_self_ty.span;
+                        obligation.cause.span = impl_.self_ty.span;
                     }
                 }
 
@@ -1321,7 +1320,7 @@ fn check_impl<'tcx>(
                         wfcx.register_obligation(Obligation::new(
                             tcx,
                             ObligationCause::new(
-                                hir_self_ty.span,
+                                impl_.self_ty.span,
                                 wfcx.body_def_id,
                                 ObligationCauseCode::WellFormed(None),
                             ),
@@ -1342,7 +1341,7 @@ fn check_impl<'tcx>(
                     self_ty,
                 );
                 wfcx.register_wf_obligation(
-                    hir_self_ty.span,
+                    impl_.self_ty.span,
                     Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
                     self_ty.into(),
                 );
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 27948f50a4a..32b175611ce 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -531,8 +531,10 @@ pub(crate) fn coerce_unsized_info<'tcx>(
                 }));
             } else if diff_fields.len() > 1 {
                 let item = tcx.hir_expect_item(impl_did);
-                let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(t), .. }) = &item.kind {
-                    t.path.span
+                let span = if let ItemKind::Impl(hir::Impl { of_trait: Some(of_trait), .. }) =
+                    &item.kind
+                {
+                    of_trait.trait_ref.path.span
                 } else {
                     tcx.def_span(impl_did)
                 };
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index c75fef9f716..f707196c816 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -384,7 +384,7 @@ fn emit_orphan_check_error<'tcx>(
         traits::OrphanCheckErr::NonLocalInputType(tys) => {
             let item = tcx.hir_expect_item(impl_def_id);
             let impl_ = item.expect_impl();
-            let hir_trait_ref = impl_.of_trait.as_ref().unwrap();
+            let of_trait = impl_.of_trait.unwrap();
 
             let span = tcx.def_span(impl_def_id);
             let mut diag = tcx.dcx().create_err(match trait_ref.self_ty().kind() {
@@ -401,7 +401,7 @@ fn emit_orphan_check_error<'tcx>(
                     impl_.self_ty.span
                 } else {
                     // Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
-                    hir_trait_ref.path.span
+                    of_trait.trait_ref.path.span
                 };
 
                 ty = tcx.erase_regions(ty);
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 8ccbfbbb3b4..b72e743f95b 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -1295,18 +1295,22 @@ fn impl_trait_header(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::ImplTrai
     let icx = ItemCtxt::new(tcx, def_id);
     let item = tcx.hir_expect_item(def_id);
     let impl_ = item.expect_impl();
-    impl_.of_trait.as_ref().map(|ast_trait_ref| {
+    let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl);
+    if is_rustc_reservation && impl_.of_trait.is_none() {
+        tcx.dcx().span_err(item.span, "reservation impls can't be inherent");
+    }
+    impl_.of_trait.map(|of_trait| {
         let selfty = tcx.type_of(def_id).instantiate_identity();
 
-        check_impl_constness(tcx, impl_.constness, ast_trait_ref);
+        check_impl_constness(tcx, of_trait.constness, &of_trait.trait_ref);
 
-        let trait_ref = icx.lowerer().lower_impl_trait_ref(ast_trait_ref, selfty);
+        let trait_ref = icx.lowerer().lower_impl_trait_ref(&of_trait.trait_ref, selfty);
 
         ty::ImplTraitHeader {
             trait_ref: ty::EarlyBinder::bind(trait_ref),
-            safety: impl_.safety,
-            polarity: polarity_of_impl(tcx, def_id, impl_, item.span),
-            constness: impl_.constness,
+            safety: of_trait.safety,
+            polarity: polarity_of_impl(tcx, of_trait, is_rustc_reservation),
+            constness: of_trait.constness,
         }
     })
 }
@@ -1350,26 +1354,18 @@ fn check_impl_constness(
 
 fn polarity_of_impl(
     tcx: TyCtxt<'_>,
-    def_id: LocalDefId,
-    impl_: &hir::Impl<'_>,
-    span: Span,
+    of_trait: &hir::TraitImplHeader<'_>,
+    is_rustc_reservation: bool,
 ) -> ty::ImplPolarity {
-    let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl);
-    match &impl_ {
-        hir::Impl { polarity: hir::ImplPolarity::Negative(span), of_trait, .. } => {
+    match of_trait.polarity {
+        hir::ImplPolarity::Negative(span) => {
             if is_rustc_reservation {
-                let span = span.to(of_trait.as_ref().map_or(*span, |t| t.path.span));
+                let span = span.to(of_trait.trait_ref.path.span);
                 tcx.dcx().span_err(span, "reservation impls can't be negative");
             }
             ty::ImplPolarity::Negative
         }
-        hir::Impl { polarity: hir::ImplPolarity::Positive, of_trait: None, .. } => {
-            if is_rustc_reservation {
-                tcx.dcx().span_err(span, "reservation impls can't be inherent");
-            }
-            ty::ImplPolarity::Positive
-        }
-        hir::Impl { polarity: hir::ImplPolarity::Positive, of_trait: Some(_), .. } => {
+        hir::ImplPolarity::Positive => {
             if is_rustc_reservation {
                 ty::ImplPolarity::Reservation
             } else {
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 8dd13da4fa7..b59dc4bd132 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -158,7 +158,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
     if let Node::Item(item) = node {
         match item.kind {
             ItemKind::Impl(impl_) => {
-                if impl_.defaultness.is_default() {
+                if let Some(of_trait) = impl_.of_trait
+                    && of_trait.defaultness.is_default()
+                {
                     is_default_impl_trait = tcx
                         .impl_trait_ref(def_id)
                         .map(|t| ty::Binder::dummy(t.instantiate_identity()));
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index eb3492f5de6..8133f9f6823 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -604,13 +604,10 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
 
     #[instrument(level = "debug", skip(self))]
     fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
-        match &item.kind {
-            hir::ItemKind::Impl(hir::Impl { of_trait, .. }) => {
-                if let Some(of_trait) = of_trait {
-                    self.record_late_bound_vars(of_trait.hir_ref_id, Vec::default());
-                }
-            }
-            _ => {}
+        if let hir::ItemKind::Impl(impl_) = item.kind
+            && let Some(of_trait) = impl_.of_trait
+        {
+            self.record_late_bound_vars(of_trait.trait_ref.hir_ref_id, Vec::default());
         }
         match item.kind {
             hir::ItemKind::Fn { generics, .. } => {
@@ -636,7 +633,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
             | hir::ItemKind::Union(_, generics, _)
             | hir::ItemKind::Trait(_, _, _, _, generics, ..)
             | hir::ItemKind::TraitAlias(_, generics, ..)
-            | hir::ItemKind::Impl(&hir::Impl { generics, .. }) => {
+            | hir::ItemKind::Impl(hir::Impl { generics, .. }) => {
                 // These kinds of items have only early-bound lifetime parameters.
                 self.visit_early(item.hir_id(), generics, |this| intravisit::walk_item(this, item));
             }
@@ -2106,7 +2103,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                     // If we have a self type alias (in an impl), try to resolve an
                     // associated item from one of the supertraits of the impl's trait.
                     Res::SelfTyAlias { alias_to: impl_def_id, is_trait_impl: true, .. } => {
-                        let hir::ItemKind::Impl(hir::Impl { of_trait: Some(trait_ref), .. }) = self
+                        let hir::ItemKind::Impl(hir::Impl { of_trait: Some(of_trait), .. }) = self
                             .tcx
                             .hir_node_by_def_id(impl_def_id.expect_local())
                             .expect_item()
@@ -2114,7 +2111,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                         else {
                             return;
                         };
-                        let Some(trait_def_id) = trait_ref.trait_def_id() else {
+                        let Some(trait_def_id) = of_trait.trait_ref.trait_def_id() else {
                             return;
                         };
                         let Some((bound_vars, assoc_item)) = BoundVarContext::supertrait_hrtb_vars(
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 22fb02714dd..62125c99d80 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -251,7 +251,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_
                         .emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: () });
                     Ty::new_error(tcx, guar)
                 }
-                _ => icx.lower_ty(*self_ty),
+                _ => icx.lower_ty(self_ty),
             },
             ItemKind::Fn { .. } => {
                 let args = ty::GenericArgs::identity_for_item(tcx, def_id);
diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
index 835f8e8cdae..8a9f9130fea 100644
--- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
@@ -147,7 +147,11 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
             let hir::Node::Item(hir::Item {
                 kind:
                     hir::ItemKind::Impl(hir::Impl {
-                        of_trait: Some(hir::TraitRef { hir_ref_id: id_in_of_trait, .. }),
+                        of_trait:
+                            Some(hir::TraitImplHeader {
+                                trait_ref: hir::TraitRef { hir_ref_id: id_in_of_trait, .. },
+                                ..
+                            }),
                         ..
                     }),
                 ..
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index 386e1091ac4..d14aef8ace4 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -199,12 +199,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
             //        However, this can easily get out of sync! Ideally, we would perform this step
             //        where we are guaranteed to catch *all* bounds like in
             //        `Self::lower_poly_trait_ref`. List of concrete issues:
-            //        FIXME(more_maybe_bounds): We don't call this for e.g., trait object tys or
-            //                                  supertrait bounds!
+            //        FIXME(more_maybe_bounds): We don't call this for trait object tys, supertrait
+            //                                  bounds or associated type bounds (ATB)!
             //        FIXME(trait_alias, #143122): We don't call it for the RHS. Arguably however,
-            //                                       AST lowering should reject them outright.
-            //        FIXME(associated_type_bounds): We don't call this for them. However, AST
-            //                                       lowering should reject them outright (#135229).
+            //                                     AST lowering should reject them outright.
             let bounds = collect_relaxed_bounds(hir_bounds, self_ty_where_predicates);
             self.check_and_report_invalid_relaxed_bounds(bounds);
         }
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
index 646ff3ca08d..56998b5b53c 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
@@ -200,7 +200,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         }) = tcx.hir_node_by_def_id(parent_id)
             && self_ty.hir_id == impl_self_ty.hir_id
         {
-            let Some(of_trait_ref) = of_trait else {
+            let Some(of_trait) = of_trait else {
                 diag.span_suggestion_verbose(
                     impl_self_ty.span.shrink_to_hi(),
                     "you might have intended to implement this trait for a given type",
@@ -209,10 +209,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 );
                 return;
             };
-            if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
+            if !of_trait.trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
                 return;
             }
-            let of_trait_span = of_trait_ref.path.span;
+            let of_trait_span = of_trait.trait_ref.path.span;
             // make sure that we are not calling unwrap to abort during the compilation
             let Ok(of_trait_name) = tcx.sess.source_map().span_to_snippet(of_trait_span) else {
                 return;
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 1675aecd2b8..c7b984d9b25 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -2732,7 +2732,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         };
         let i = tcx.parent_hir_node(fn_hir_id).expect_item().expect_impl();
 
-        let trait_ref = self.lower_impl_trait_ref(i.of_trait.as_ref()?, self.lower_ty(i.self_ty));
+        let trait_ref = self.lower_impl_trait_ref(&i.of_trait?.trait_ref, self.lower_ty(i.self_ty));
 
         let assoc = tcx.associated_items(trait_ref.def_id).find_by_ident_and_kind(
             tcx,
diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index 3fddaee8cef..d8578970adc 100644
--- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -154,8 +154,9 @@ pub(super) fn diagnostic_hir_wf_check<'tcx>(
                 hir::ItemKind::TyAlias(_, _, ty)
                 | hir::ItemKind::Static(_, _, ty, _)
                 | hir::ItemKind::Const(_, _, ty, _) => vec![ty],
-                hir::ItemKind::Impl(impl_) => match &impl_.of_trait {
-                    Some(t) => t
+                hir::ItemKind::Impl(impl_) => match impl_.of_trait {
+                    Some(of_trait) => of_trait
+                        .trait_ref
                         .path
                         .segments
                         .last()
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 235eec96d74..be5859b57c5 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -690,39 +690,44 @@ impl<'a> State<'a> {
                 let (cb, ib) = self.head("union");
                 self.print_struct(ident.name, generics, struct_def, item.span, true, cb, ib);
             }
-            hir::ItemKind::Impl(&hir::Impl {
-                constness,
-                safety,
-                polarity,
-                defaultness,
-                defaultness_span: _,
-                generics,
-                ref of_trait,
-                self_ty,
-                items,
-            }) => {
+            hir::ItemKind::Impl(hir::Impl { generics, of_trait, self_ty, items }) => {
                 let (cb, ib) = self.head("");
-                self.print_defaultness(defaultness);
-                self.print_safety(safety);
-                self.word_nbsp("impl");
 
-                if let hir::Constness::Const = constness {
-                    self.word_nbsp("const");
-                }
+                let impl_generics = |this: &mut Self| {
+                    this.word_nbsp("impl");
+                    if !generics.params.is_empty() {
+                        this.print_generic_params(generics.params);
+                        this.space();
+                    }
+                };
 
-                if !generics.params.is_empty() {
-                    self.print_generic_params(generics.params);
-                    self.space();
-                }
+                match of_trait {
+                    None => impl_generics(self),
+                    Some(&hir::TraitImplHeader {
+                        constness,
+                        safety,
+                        polarity,
+                        defaultness,
+                        defaultness_span: _,
+                        ref trait_ref,
+                    }) => {
+                        self.print_defaultness(defaultness);
+                        self.print_safety(safety);
+
+                        impl_generics(self);
+
+                        if let hir::Constness::Const = constness {
+                            self.word_nbsp("const");
+                        }
 
-                if let hir::ImplPolarity::Negative(_) = polarity {
-                    self.word("!");
-                }
+                        if let hir::ImplPolarity::Negative(_) = polarity {
+                            self.word("!");
+                        }
 
-                if let Some(t) = of_trait {
-                    self.print_trait_ref(t);
-                    self.space();
-                    self.word_space("for");
+                        self.print_trait_ref(trait_ref);
+                        self.space();
+                        self.word_space("for");
+                    }
                 }
 
                 self.print_type(self_ty);
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 36abd7c8555..b80a2af3100 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1589,26 +1589,64 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // e.g. `reuse HasSelf::method;` should suggest `reuse HasSelf::method($args);`.
                 full_call_span.shrink_to_hi()
             };
+
+            // Controls how the arguments should be listed in the suggestion.
+            enum ArgumentsFormatting {
+                SingleLine,
+                Multiline { fallback_indent: String, brace_indent: String },
+            }
+            let arguments_formatting = {
+                let mut provided_inputs = matched_inputs.iter().filter_map(|a| *a);
+                if let Some(brace_indent) = source_map.indentation_before(suggestion_span)
+                    && let Some(first_idx) = provided_inputs.by_ref().next()
+                    && let Some(last_idx) = provided_inputs.by_ref().next()
+                    && let (_, first_span) = provided_arg_tys[first_idx]
+                    && let (_, last_span) = provided_arg_tys[last_idx]
+                    && source_map.is_multiline(first_span.to(last_span))
+                    && let Some(fallback_indent) = source_map.indentation_before(first_span)
+                {
+                    ArgumentsFormatting::Multiline { fallback_indent, brace_indent }
+                } else {
+                    ArgumentsFormatting::SingleLine
+                }
+            };
+
             let mut suggestion = "(".to_owned();
             let mut needs_comma = false;
             for (expected_idx, provided_idx) in matched_inputs.iter_enumerated() {
                 if needs_comma {
-                    suggestion += ", ";
-                } else {
-                    needs_comma = true;
+                    suggestion += ",";
+                }
+                match &arguments_formatting {
+                    ArgumentsFormatting::SingleLine if needs_comma => suggestion += " ",
+                    ArgumentsFormatting::SingleLine => {}
+                    ArgumentsFormatting::Multiline { .. } => suggestion += "\n",
                 }
-                let suggestion_text = if let Some(provided_idx) = provided_idx
+                needs_comma = true;
+                let (suggestion_span, suggestion_text) = if let Some(provided_idx) = provided_idx
                     && let (_, provided_span) = provided_arg_tys[*provided_idx]
                     && let Ok(arg_text) = source_map.span_to_snippet(provided_span)
                 {
-                    arg_text
+                    (Some(provided_span), arg_text)
                 } else {
                     // Propose a placeholder of the correct type
                     let (_, expected_ty) = formal_and_expected_inputs[expected_idx];
-                    ty_to_snippet(expected_ty, expected_idx)
+                    (None, ty_to_snippet(expected_ty, expected_idx))
                 };
+                if let ArgumentsFormatting::Multiline { fallback_indent, .. } =
+                    &arguments_formatting
+                {
+                    let indent = suggestion_span
+                        .and_then(|span| source_map.indentation_before(span))
+                        .unwrap_or_else(|| fallback_indent.clone());
+                    suggestion += &indent;
+                }
                 suggestion += &suggestion_text;
             }
+            if let ArgumentsFormatting::Multiline { brace_indent, .. } = arguments_formatting {
+                suggestion += ",\n";
+                suggestion += &brace_indent;
+            }
             suggestion += ")";
             err.span_suggestion_verbose(
                 suggestion_span,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 2345cdab208..6013430e1ff 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -936,7 +936,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             Node::ImplItem(item) => {
                 // If it doesn't impl a trait, we can add a return type
                 let Node::Item(&hir::Item {
-                    kind: hir::ItemKind::Impl(&hir::Impl { of_trait, .. }),
+                    kind: hir::ItemKind::Impl(hir::Impl { of_trait, .. }),
                     ..
                 }) = self.tcx.parent_hir_node(item.hir_id())
                 else {
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index f7430f7af4e..824d592fa6c 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1103,7 +1103,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         self_ty.span.ctxt().outer_expn_data().kind,
                         ExpnKind::Macro(MacroKind::Derive, _)
                     ) || matches!(
-                        of_trait.as_ref().map(|t| t.path.span.ctxt().outer_expn_data().kind),
+                        of_trait.map(|t| t.trait_ref.path.span.ctxt().outer_expn_data().kind),
                         Some(ExpnKind::Macro(MacroKind::Derive, _))
                     ) =>
                     {
@@ -1165,13 +1165,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             entry.0.insert(cause_span);
                             entry.1.insert((cause_span, "unsatisfied trait bound introduced here"));
                         } else {
-                            if let Some(trait_ref) = of_trait {
-                                entry.0.insert(trait_ref.path.span);
+                            if let Some(of_trait) = of_trait {
+                                entry.0.insert(of_trait.trait_ref.path.span);
                             }
                             entry.0.insert(self_ty.span);
                         };
-                        if let Some(trait_ref) = of_trait {
-                            entry.1.insert((trait_ref.path.span, ""));
+                        if let Some(of_trait) = of_trait {
+                            entry.1.insert((of_trait.trait_ref.path.span, ""));
                         }
                         entry.1.insert((self_ty.span, ""));
                     }
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index a2afdc45fa8..82d4856df39 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -485,17 +485,6 @@ pub enum NllRegionVariableOrigin {
 
     Existential {
         name: Option<Symbol>,
-        /// If this is true, then this variable was created to represent a lifetime
-        /// bound in a `for` binder. For example, it might have been created to
-        /// represent the lifetime `'a` in a type like `for<'a> fn(&'a u32)`.
-        /// Such variables are created when we are trying to figure out if there
-        /// is any valid instantiation of `'a` that could fit into some scenario.
-        ///
-        /// This is used to inform error reporting: in the case that we are trying to
-        /// determine whether there is any valid instantiation of a `'a` variable that meets
-        /// some constraint C, we want to blame the "source" of that `for` type,
-        /// rather than blaming the source of the constraint C.
-        from_forall: bool,
     },
 }
 
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 16474b231e0..0a764808f95 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -689,6 +689,7 @@ fn test_unstable_options_tracking_hash() {
     // Make sure that changing an [UNTRACKED] option leaves the hash unchanged.
     // tidy-alphabetical-start
     untracked!(assert_incr_state, Some(String::from("loaded")));
+    untracked!(codegen_source_order, true);
     untracked!(deduplicate_diagnostics, false);
     untracked!(dump_dep_graph, true);
     untracked!(dump_mir, Some(String::from("abc")));
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 4d0c0c94a81..c485e6fc849 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -349,6 +349,7 @@ lint_ill_formed_attribute_input = {$num_suggestions ->
         [1] attribute must be of the form {$suggestions}
         *[other] valid forms for the attribute are {$suggestions}
     }
+    .note = for more information, visit <{$docs}>
 
 lint_impl_trait_overcaptures = `{$self_ty}` will capture more lifetimes than possibly intended in edition 2024
     .note = specifically, {$num_captured ->
@@ -982,6 +983,7 @@ lint_unused_allocation_mut = unnecessary allocation, use `&mut` instead
 
 lint_unused_builtin_attribute = unused attribute `{$attr_name}`
     .note = the built-in attribute `{$attr_name}` will be ignored, since it's applied to the macro invocation `{$macro_name}`
+    .suggestion = remove the attribute
 
 lint_unused_closure =
     unused {$pre}{$count ->
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index c893b723375..8006cfcf30f 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -21,6 +21,7 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_ast::visit::{FnCtxt, FnKind};
 use rustc_ast::{self as ast, *};
 use rustc_ast_pretty::pprust::expr_to_string;
+use rustc_attr_parsing::AttributeParser;
 use rustc_errors::{Applicability, LintDiagnostic};
 use rustc_feature::GateIssue;
 use rustc_hir as hir;
@@ -248,12 +249,6 @@ impl UnsafeCode {
 }
 
 impl EarlyLintPass for UnsafeCode {
-    fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
-        if attr.has_name(sym::allow_internal_unsafe) {
-            self.report_unsafe(cx, attr.span, BuiltinUnsafe::AllowInternalUnsafe);
-        }
-    }
-
     #[inline]
     fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
         if let ast::ExprKind::Block(ref blk, _) = e.kind {
@@ -270,7 +265,10 @@ impl EarlyLintPass for UnsafeCode {
                 self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeTrait);
             }
 
-            ast::ItemKind::Impl(box ast::Impl { safety: ast::Safety::Unsafe(_), .. }) => {
+            ast::ItemKind::Impl(ast::Impl {
+                of_trait: Some(box ast::TraitImplHeader { safety: ast::Safety::Unsafe(_), .. }),
+                ..
+            }) => {
                 self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeImpl);
             }
 
@@ -312,6 +310,19 @@ impl EarlyLintPass for UnsafeCode {
                 }
             }
 
+            ast::ItemKind::MacroDef(..) => {
+                if let Some(attr) = AttributeParser::parse_limited(
+                    cx.builder.sess(),
+                    &it.attrs,
+                    sym::allow_internal_unsafe,
+                    it.span,
+                    DUMMY_NODE_ID,
+                    Some(cx.builder.features()),
+                ) {
+                    self.report_unsafe(cx, attr.span(), BuiltinUnsafe::AllowInternalUnsafe);
+                }
+            }
+
             _ => {}
         }
     }
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 11181d10af5..d9163d94710 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -745,12 +745,12 @@ impl<'tcx> LateContext<'tcx> {
     /// }
     /// ```
     pub fn get_def_path(&self, def_id: DefId) -> Vec<Symbol> {
-        struct AbsolutePathPrinter<'tcx> {
+        struct LintPathPrinter<'tcx> {
             tcx: TyCtxt<'tcx>,
             path: Vec<Symbol>,
         }
 
-        impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
+        impl<'tcx> Printer<'tcx> for LintPathPrinter<'tcx> {
             fn tcx(&self) -> TyCtxt<'tcx> {
                 self.tcx
             }
@@ -774,12 +774,12 @@ impl<'tcx> LateContext<'tcx> {
                 unreachable!(); // because `path_generic_args` ignores the `GenericArgs`
             }
 
-            fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
+            fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
                 self.path = vec![self.tcx.crate_name(cnum)];
                 Ok(())
             }
 
-            fn path_qualified(
+            fn print_path_with_qualified(
                 &mut self,
                 self_ty: Ty<'tcx>,
                 trait_ref: Option<ty::TraitRef<'tcx>>,
@@ -800,7 +800,7 @@ impl<'tcx> LateContext<'tcx> {
                 })
             }
 
-            fn path_append_impl(
+            fn print_path_with_impl(
                 &mut self,
                 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
                 self_ty: Ty<'tcx>,
@@ -825,7 +825,7 @@ impl<'tcx> LateContext<'tcx> {
                 Ok(())
             }
 
-            fn path_append(
+            fn print_path_with_simple(
                 &mut self,
                 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
                 disambiguated_data: &DisambiguatedDefPathData,
@@ -844,7 +844,7 @@ impl<'tcx> LateContext<'tcx> {
                 Ok(())
             }
 
-            fn path_generic_args(
+            fn print_path_with_generic_args(
                 &mut self,
                 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
                 _args: &[GenericArg<'tcx>],
@@ -853,7 +853,7 @@ impl<'tcx> LateContext<'tcx> {
             }
         }
 
-        let mut p = AbsolutePathPrinter { tcx: self.tcx, path: vec![] };
+        let mut p = LintPathPrinter { tcx: self.tcx, path: vec![] };
         p.print_def_path(def_id, &[]).unwrap();
         p.path
     }
diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
index dd16117db1c..943fcc0801b 100644
--- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
+++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
@@ -61,8 +61,8 @@ impl<'tcx> LateLintPass<'tcx> for DerefIntoDynSupertrait {
         // `Deref` is being implemented for `t`
         if let hir::ItemKind::Impl(impl_) = item.kind
             // the trait is a `Deref` implementation
-            && let Some(trait_) = &impl_.of_trait
-            && let Some(did) = trait_.trait_def_id()
+            && let Some(of_trait) = &impl_.of_trait
+            && let Some(did) = of_trait.trait_ref.trait_def_id()
             && tcx.is_lang_item(did, LangItem::Deref)
             // the self type is `dyn t_principal`
             && let self_ty = tcx.type_of(item.owner_id).instantiate_identity()
diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs
index f0fbf5bc81e..678d3d1f8ed 100644
--- a/compiler/rustc_lint/src/early/diagnostics.rs
+++ b/compiler/rustc_lint/src/early/diagnostics.rs
@@ -205,8 +205,14 @@ pub fn decorate_builtin_lint(
             }
             .decorate_lint(diag);
         }
-        BuiltinLintDiag::UnusedBuiltinAttribute { attr_name, macro_name, invoc_span } => {
-            lints::UnusedBuiltinAttribute { invoc_span, attr_name, macro_name }.decorate_lint(diag);
+        BuiltinLintDiag::UnusedBuiltinAttribute {
+            attr_name,
+            macro_name,
+            invoc_span,
+            attr_span,
+        } => {
+            lints::UnusedBuiltinAttribute { invoc_span, attr_name, macro_name, attr_span }
+                .decorate_lint(diag);
         }
         BuiltinLintDiag::TrailingMacro(is_trailing, name) => {
             lints::TrailingMacro { is_trailing, name }.decorate_lint(diag);
@@ -447,12 +453,14 @@ pub fn decorate_builtin_lint(
         BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => {
             lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag)
         }
-        BuiltinLintDiag::IllFormedAttributeInput { suggestions } => {
+        BuiltinLintDiag::IllFormedAttributeInput { suggestions, docs } => {
             lints::IllFormedAttributeInput {
                 num_suggestions: suggestions.len(),
                 suggestions: DiagArgValue::StrListSepByAnd(
                     suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
                 ),
+                has_docs: docs.is_some(),
+                docs: docs.unwrap_or(""),
             }
             .decorate_lint(diag)
         }
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 7dafcc199a3..016ff17f5d7 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -411,11 +411,11 @@ declare_lint_pass!(LintPassImpl => [LINT_PASS_IMPL_WITHOUT_MACRO]);
 
 impl EarlyLintPass for LintPassImpl {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
-        if let ast::ItemKind::Impl(box ast::Impl { of_trait: Some(lint_pass), .. }) = &item.kind
-            && let Some(last) = lint_pass.path.segments.last()
+        if let ast::ItemKind::Impl(ast::Impl { of_trait: Some(of_trait), .. }) = &item.kind
+            && let Some(last) = of_trait.trait_ref.path.segments.last()
             && last.ident.name == sym::LintPass
         {
-            let expn_data = lint_pass.path.span.ctxt().outer_expn_data();
+            let expn_data = of_trait.trait_ref.path.span.ctxt().outer_expn_data();
             let call_site = expn_data.call_site;
             if expn_data.kind != ExpnKind::Macro(MacroKind::Bang, sym::impl_lint_pass)
                 && call_site.ctxt().outer_expn_data().kind
@@ -423,7 +423,7 @@ impl EarlyLintPass for LintPassImpl {
             {
                 cx.emit_span_lint(
                     LINT_PASS_IMPL_WITHOUT_MACRO,
-                    lint_pass.path.span,
+                    of_trait.trait_ref.path.span,
                     LintPassByHand,
                 );
             }
@@ -582,8 +582,8 @@ impl Diagnostics {
         for (_hir_id, parent) in cx.tcx.hir_parent_iter(current_id) {
             debug!(?parent);
             if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) = parent
-                && let hir::Impl { of_trait: Some(of_trait), .. } = impl_
-                && let Some(def_id) = of_trait.trait_def_id()
+                && let Some(of_trait) = impl_.of_trait
+                && let Some(def_id) = of_trait.trait_ref.trait_def_id()
                 && let Some(name) = cx.tcx.get_diagnostic_name(def_id)
                 && matches!(name, sym::Diagnostic | sym::Subdiagnostic | sym::LintDiagnostic)
             {
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 73e69a1791a..a6d59af6900 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -2685,6 +2685,9 @@ pub(crate) struct UnusedCrateDependency {
 pub(crate) struct IllFormedAttributeInput {
     pub num_suggestions: usize,
     pub suggestions: DiagArgValue,
+    #[note]
+    pub has_docs: bool,
+    pub docs: &'static str,
 }
 
 #[derive(LintDiagnostic)]
@@ -2935,9 +2938,10 @@ pub(crate) struct RawPrefix {
 pub(crate) struct UnusedBuiltinAttribute {
     #[note]
     pub invoc_span: Span,
-
     pub attr_name: Symbol,
     pub macro_name: String,
+    #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
+    pub attr_span: Span,
 }
 
 #[derive(LintDiagnostic)]
diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs
index b877f909fc0..dca22b986ff 100644
--- a/compiler/rustc_lint/src/non_local_def.rs
+++ b/compiler/rustc_lint/src/non_local_def.rs
@@ -5,7 +5,7 @@ use rustc_hir::{Body, HirId, Item, ItemKind, Node, Path, TyKind};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::{declare_lint, impl_lint_pass};
 use rustc_span::def_id::{DefId, LOCAL_CRATE};
-use rustc_span::{ExpnKind, MacroKind, Span, kw, sym};
+use rustc_span::{ExpnKind, Span, kw, sym};
 
 use crate::lints::{NonLocalDefinitionsCargoUpdateNote, NonLocalDefinitionsDiag};
 use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent};
@@ -129,8 +129,8 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
                 // of the `impl` definition
                 let mut collector = PathCollector { paths: Vec::new() };
                 collector.visit_ty_unambig(&impl_.self_ty);
-                if let Some(of_trait) = &impl_.of_trait {
-                    collector.visit_trait_ref(of_trait);
+                if let Some(of_trait) = impl_.of_trait {
+                    collector.visit_trait_ref(&of_trait.trait_ref);
                 }
 
                 // 1.5. Remove any path that doesn't resolve to a `DefId` or if it resolve to a
@@ -240,7 +240,7 @@ impl<'tcx> LateLintPass<'tcx> for NonLocalDefinitions {
                     },
                 )
             }
-            ItemKind::Macro(_, _macro, MacroKind::Bang)
+            ItemKind::Macro(_, _macro, _kinds)
                 if cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export) =>
             {
                 cx.emit_span_lint(
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 7e5f43ba77f..8fafaa33d0c 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -187,7 +187,7 @@ impl EarlyLintPass for NonCamelCaseTypes {
 
             // N.B. This check is only for inherent associated types, so that we don't lint against
             // trait impls where we should have warned for the trait definition already.
-            ast::ItemKind::Impl(box ast::Impl { of_trait: None, items, .. }) => {
+            ast::ItemKind::Impl(ast::Impl { of_trait: None, items, .. }) => {
                 for it in items {
                     // FIXME: this doesn't respect `#[allow(..)]` on the item itself.
                     if let ast::AssocItemKind::Type(alias) = &it.kind {
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index fe068d96b74..3bb7bbce567 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -647,6 +647,7 @@ pub enum BuiltinLintDiag {
         attr_name: Symbol,
         macro_name: String,
         invoc_span: Span,
+        attr_span: Span,
     },
     PatternsInFnsWithoutBody {
         span: Span,
@@ -793,6 +794,7 @@ pub enum BuiltinLintDiag {
     },
     IllFormedAttributeInput {
         suggestions: Vec<String>,
+        docs: Option<&'static str>,
     },
     InnerAttributeUnstable {
         is_macro: bool,
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 588d867bbbf..cd4f80f808c 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -277,6 +277,7 @@ enum class LLVMRustAttributeKind {
   FnRetThunkExtern = 41,
   Writable = 42,
   DeadOnUnwind = 43,
+  DeadOnReturn = 44,
 };
 
 static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) {
@@ -369,6 +370,12 @@ static Attribute::AttrKind fromRust(LLVMRustAttributeKind Kind) {
     return Attribute::Writable;
   case LLVMRustAttributeKind::DeadOnUnwind:
     return Attribute::DeadOnUnwind;
+  case LLVMRustAttributeKind::DeadOnReturn:
+#if LLVM_VERSION_GE(21, 0)
+    return Attribute::DeadOnReturn;
+#else
+    report_fatal_error("DeadOnReturn attribute requires LLVM 21 or later");
+#endif
   }
   report_fatal_error("bad LLVMRustAttributeKind");
 }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index d42c8b947a4..a7e7e9985f4 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1981,7 +1981,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
                 def_key.disambiguated_data.data = DefPathData::MacroNs(name);
 
                 let def_id = id.to_def_id();
-                self.tables.def_kind.set_some(def_id.index, DefKind::Macro(macro_kind));
+                self.tables.def_kind.set_some(def_id.index, DefKind::Macro(macro_kind.into()));
                 self.tables.proc_macro.set_some(def_id.index, macro_kind);
                 self.encode_attrs(id);
                 record!(self.tables.def_keys[def_id] <- def_key);
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 99174e4ad2f..1f7d142d330 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -11,7 +11,7 @@ use rustc_abi::{FieldIdx, ReprOptions, VariantIdx};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::svh::Svh;
 use rustc_hir::attrs::StrippedCfgItem;
-use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap};
+use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap, MacroKinds};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, DefIndex, DefPathHash, StableCrateId};
 use rustc_hir::definitions::DefKey;
 use rustc_hir::lang_items::LangItem;
diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs
index 0671aa20399..2cb07a28a8a 100644
--- a/compiler/rustc_metadata/src/rmeta/table.rs
+++ b/compiler/rustc_metadata/src/rmeta/table.rs
@@ -81,7 +81,7 @@ impl FixedSizeEncoding for u64 {
 }
 
 macro_rules! fixed_size_enum {
-    ($ty:ty { $(($($pat:tt)*))* }) => {
+    ($ty:ty { $(($($pat:tt)*))* } $( unreachable { $(($($upat:tt)*))+ } )?) => {
         impl FixedSizeEncoding for Option<$ty> {
             type ByteArray = [u8;1];
 
@@ -103,12 +103,24 @@ macro_rules! fixed_size_enum {
                 b[0] = match self {
                     None => unreachable!(),
                     $(Some($($pat)*) => 1 + ${index()},)*
+                    $(Some($($($upat)*)|+) => unreachable!(),)?
                 }
             }
         }
     }
 }
 
+// Workaround; need const traits to construct bitflags in a const
+macro_rules! const_macro_kinds {
+    ($($name:ident),+$(,)?) => (MacroKinds::from_bits_truncate($(MacroKinds::$name.bits())|+))
+}
+const MACRO_KINDS_ATTR_BANG: MacroKinds = const_macro_kinds!(ATTR, BANG);
+const MACRO_KINDS_DERIVE_BANG: MacroKinds = const_macro_kinds!(DERIVE, BANG);
+const MACRO_KINDS_DERIVE_ATTR: MacroKinds = const_macro_kinds!(DERIVE, ATTR);
+const MACRO_KINDS_DERIVE_ATTR_BANG: MacroKinds = const_macro_kinds!(DERIVE, ATTR, BANG);
+// Ensure that we get a compilation error if MacroKinds gets extended without updating metadata.
+const _: () = assert!(MACRO_KINDS_DERIVE_ATTR_BANG.is_all());
+
 fixed_size_enum! {
     DefKind {
         ( Mod                                      )
@@ -151,10 +163,16 @@ fixed_size_enum! {
         ( Ctor(CtorOf::Struct, CtorKind::Const)    )
         ( Ctor(CtorOf::Variant, CtorKind::Fn)      )
         ( Ctor(CtorOf::Variant, CtorKind::Const)   )
-        ( Macro(MacroKind::Bang)                   )
-        ( Macro(MacroKind::Attr)                   )
-        ( Macro(MacroKind::Derive)                 )
+        ( Macro(MacroKinds::BANG)                  )
+        ( Macro(MacroKinds::ATTR)                  )
+        ( Macro(MacroKinds::DERIVE)                )
+        ( Macro(MACRO_KINDS_ATTR_BANG)             )
+        ( Macro(MACRO_KINDS_DERIVE_ATTR)           )
+        ( Macro(MACRO_KINDS_DERIVE_BANG)           )
+        ( Macro(MACRO_KINDS_DERIVE_ATTR_BANG)      )
         ( SyntheticCoroutineBody                   )
+    } unreachable {
+        ( Macro(_)                                 )
     }
 }
 
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index 94384e64afd..52341df0740 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -3,6 +3,7 @@ use std::borrow::Cow;
 use rustc_abi::Align;
 use rustc_ast::expand::autodiff_attrs::AutoDiffAttrs;
 use rustc_hir::attrs::{InlineAttr, InstructionSetAttr, OptimizeAttr};
+use rustc_hir::def_id::DefId;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 use rustc_span::Symbol;
 use rustc_target::spec::SanitizerSet;
@@ -193,7 +194,11 @@ impl CodegenFnAttrs {
     /// * `#[linkage]` is present
     ///
     /// Keep this in sync with the logic for the unused_attributes for `#[inline]` lint.
-    pub fn contains_extern_indicator(&self) -> bool {
+    pub fn contains_extern_indicator(&self, tcx: TyCtxt<'_>, did: DefId) -> bool {
+        if tcx.is_foreign_item(did) {
+            return false;
+        }
+
         self.flags.contains(CodegenFnAttrFlags::NO_MANGLE)
             || self.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
             || self.export_name.is_some()
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index e5864660575..0d98e055d95 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -12,7 +12,6 @@ use rustc_hashes::Hash128;
 use rustc_hir::ItemId;
 use rustc_hir::attrs::InlineAttr;
 use rustc_hir::def_id::{CrateNum, DefId, DefIdSet, LOCAL_CRATE};
-use rustc_index::Idx;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 use rustc_query_system::ich::StableHashingContext;
 use rustc_session::config::OptLevel;
@@ -151,7 +150,7 @@ impl<'tcx> MonoItem<'tcx> {
         // instantiation:
         // We emit an unused_attributes lint for this case, which should be kept in sync if possible.
         let codegen_fn_attrs = tcx.codegen_instance_attrs(instance.def);
-        if codegen_fn_attrs.contains_extern_indicator()
+        if codegen_fn_attrs.contains_extern_indicator(tcx, instance.def.def_id())
             || codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED)
         {
             return InstantiationMode::GloballyShared { may_conflict: false };
@@ -526,44 +525,50 @@ impl<'tcx> CodegenUnit<'tcx> {
         tcx: TyCtxt<'tcx>,
     ) -> Vec<(MonoItem<'tcx>, MonoItemData)> {
         // The codegen tests rely on items being process in the same order as
-        // they appear in the file, so for local items, we sort by node_id first
+        // they appear in the file, so for local items, we sort by span first
         #[derive(PartialEq, Eq, PartialOrd, Ord)]
-        struct ItemSortKey<'tcx>(Option<usize>, SymbolName<'tcx>);
-
+        struct ItemSortKey<'tcx>(Option<Span>, SymbolName<'tcx>);
+
+        // We only want to take HirIds of user-defines instances into account.
+        // The others don't matter for the codegen tests and can even make item
+        // order unstable.
+        fn local_item_id<'tcx>(item: MonoItem<'tcx>) -> Option<DefId> {
+            match item {
+                MonoItem::Fn(ref instance) => match instance.def {
+                    InstanceKind::Item(def) => def.as_local().map(|_| def),
+                    InstanceKind::VTableShim(..)
+                    | InstanceKind::ReifyShim(..)
+                    | InstanceKind::Intrinsic(..)
+                    | InstanceKind::FnPtrShim(..)
+                    | InstanceKind::Virtual(..)
+                    | InstanceKind::ClosureOnceShim { .. }
+                    | InstanceKind::ConstructCoroutineInClosureShim { .. }
+                    | InstanceKind::DropGlue(..)
+                    | InstanceKind::CloneShim(..)
+                    | InstanceKind::ThreadLocalShim(..)
+                    | InstanceKind::FnPtrAddrShim(..)
+                    | InstanceKind::AsyncDropGlue(..)
+                    | InstanceKind::FutureDropPollShim(..)
+                    | InstanceKind::AsyncDropGlueCtorShim(..) => None,
+                },
+                MonoItem::Static(def_id) => def_id.as_local().map(|_| def_id),
+                MonoItem::GlobalAsm(item_id) => Some(item_id.owner_id.def_id.to_def_id()),
+            }
+        }
         fn item_sort_key<'tcx>(tcx: TyCtxt<'tcx>, item: MonoItem<'tcx>) -> ItemSortKey<'tcx> {
             ItemSortKey(
-                match item {
-                    MonoItem::Fn(ref instance) => {
-                        match instance.def {
-                            // We only want to take HirIds of user-defined
-                            // instances into account. The others don't matter for
-                            // the codegen tests and can even make item order
-                            // unstable.
-                            InstanceKind::Item(def) => def.as_local().map(Idx::index),
-                            InstanceKind::VTableShim(..)
-                            | InstanceKind::ReifyShim(..)
-                            | InstanceKind::Intrinsic(..)
-                            | InstanceKind::FnPtrShim(..)
-                            | InstanceKind::Virtual(..)
-                            | InstanceKind::ClosureOnceShim { .. }
-                            | InstanceKind::ConstructCoroutineInClosureShim { .. }
-                            | InstanceKind::DropGlue(..)
-                            | InstanceKind::CloneShim(..)
-                            | InstanceKind::ThreadLocalShim(..)
-                            | InstanceKind::FnPtrAddrShim(..)
-                            | InstanceKind::AsyncDropGlue(..)
-                            | InstanceKind::FutureDropPollShim(..)
-                            | InstanceKind::AsyncDropGlueCtorShim(..) => None,
-                        }
-                    }
-                    MonoItem::Static(def_id) => def_id.as_local().map(Idx::index),
-                    MonoItem::GlobalAsm(item_id) => Some(item_id.owner_id.def_id.index()),
-                },
+                local_item_id(item)
+                    .map(|def_id| tcx.def_span(def_id).find_ancestor_not_from_macro())
+                    .flatten(),
                 item.symbol_name(tcx),
             )
         }
 
         let mut items: Vec<_> = self.items().iter().map(|(&i, &data)| (i, data)).collect();
+        if !tcx.sess.opts.unstable_opts.codegen_source_order {
+            // It's already deterministic, so we can just use it.
+            return items;
+        }
         items.sort_by_cached_key(|&(i, _)| item_sort_key(tcx, i));
         items
     }
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 84abcf550d2..d4d925d2057 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -1932,7 +1932,7 @@ fn pretty_print_const_value_tcx<'tcx>(
                         let args = tcx.lift(args).unwrap();
                         let mut p = FmtPrinter::new(tcx, Namespace::ValueNS);
                         p.print_alloc_ids = true;
-                        p.print_value_path(variant_def.def_id, args)?;
+                        p.pretty_print_value_path(variant_def.def_id, args)?;
                         fmt.write_str(&p.into_buffer())?;
 
                         match variant_def.ctor_kind() {
@@ -1974,7 +1974,7 @@ fn pretty_print_const_value_tcx<'tcx>(
         (ConstValue::ZeroSized, ty::FnDef(d, s)) => {
             let mut p = FmtPrinter::new(tcx, Namespace::ValueNS);
             p.print_alloc_ids = true;
-            p.print_value_path(*d, s)?;
+            p.pretty_print_value_path(*d, s)?;
             fmt.write_str(&p.into_buffer())?;
             return Ok(());
         }
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index efa017074db..e6feafea122 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -19,18 +19,16 @@ pub trait Print<'tcx, P> {
     fn print(&self, p: &mut P) -> Result<(), PrintError>;
 }
 
-/// Interface for outputting user-facing "type-system entities"
-/// (paths, types, lifetimes, constants, etc.) as a side-effect
-/// (e.g. formatting, like `PrettyPrinter` implementors do) or by
-/// constructing some alternative representation (e.g. an AST),
-/// which the associated types allow passing through the methods.
-///
-/// For pretty-printing/formatting in particular, see `PrettyPrinter`.
-//
-// FIXME(eddyb) find a better name; this is more general than "printing".
+/// A trait that "prints" user-facing type system entities: paths, types, lifetimes, constants,
+/// etc. "Printing" here means building up a representation of the entity's path, usually as a
+/// `String` (e.g. "std::io::Read") or a `Vec<Symbol>` (e.g. `[sym::std, sym::io, sym::Read]`). The
+/// representation is built up by appending one or more pieces. The specific details included in
+/// the built-up representation depend on the purpose of the printer. The more advanced printers
+/// also rely on the `PrettyPrinter` sub-trait.
 pub trait Printer<'tcx>: Sized {
     fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
 
+    /// Appends a representation of an entity with a normal path, e.g. "std::io::Read".
     fn print_def_path(
         &mut self,
         def_id: DefId,
@@ -39,6 +37,7 @@ pub trait Printer<'tcx>: Sized {
         self.default_print_def_path(def_id, args)
     }
 
+    /// Like `print_def_path`, but for `DefPathData::Impl`.
     fn print_impl_path(
         &mut self,
         impl_def_id: DefId,
@@ -64,48 +63,67 @@ pub trait Printer<'tcx>: Sized {
         self.default_print_impl_path(impl_def_id, self_ty, impl_trait_ref)
     }
 
+    /// Appends a representation of a region.
     fn print_region(&mut self, region: ty::Region<'tcx>) -> Result<(), PrintError>;
 
+    /// Appends a representation of a type.
     fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError>;
 
+    /// Appends a representation of a list of `PolyExistentialPredicate`s.
     fn print_dyn_existential(
         &mut self,
         predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
     ) -> Result<(), PrintError>;
 
+    /// Appends a representation of a const.
     fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError>;
 
-    fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError>;
+    /// Appends a representation of a crate name, e.g. `std`, or even ``.
+    fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError>;
 
-    fn path_qualified(
+    /// Appends a representation of a (full or partial) simple path, in two parts. `print_prefix`,
+    /// when called, appends the representation of the leading segments. The rest of the method
+    /// appends the representation of the final segment, the details of which are in
+    /// `disambiguated_data`.
+    ///
+    /// E.g. `std::io` + `Read` -> `std::io::Read`.
+    fn print_path_with_simple(
         &mut self,
-        self_ty: Ty<'tcx>,
-        trait_ref: Option<ty::TraitRef<'tcx>>,
+        print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
+        disambiguated_data: &DisambiguatedDefPathData,
     ) -> Result<(), PrintError>;
 
-    fn path_append_impl(
+    /// Similar to `print_path_with_simple`, but the final segment is an `impl` segment.
+    ///
+    /// E.g. `slice` + `<impl [T]>` -> `slice::<impl [T]>`, which may then be further appended to,
+    /// giving a longer path representation such as `slice::<impl [T]>::to_vec_in::ConvertVec`.
+    fn print_path_with_impl(
         &mut self,
         print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
         self_ty: Ty<'tcx>,
         trait_ref: Option<ty::TraitRef<'tcx>>,
     ) -> Result<(), PrintError>;
 
-    fn path_append(
+    /// Appends a representation of a path ending in generic args, in two parts. `print_prefix`,
+    /// when called, appends the leading segments. The rest of the method appends the
+    /// representation of the generic args. (Some printers choose to skip appending the generic
+    /// args.)
+    ///
+    /// E.g. `ImplementsTraitForUsize` + `<usize>` -> `ImplementsTraitForUsize<usize>`.
+    fn print_path_with_generic_args(
         &mut self,
         print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
-        disambiguated_data: &DisambiguatedDefPathData,
+        args: &[GenericArg<'tcx>],
     ) -> Result<(), PrintError>;
 
-    fn path_generic_args(
+    /// Appends a representation of a qualified path segment, e.g. `<OsString as From<&T>>`.
+    /// If `trait_ref` is `None`, it may fall back to simpler forms, e.g. `<Vec<T>>` or just `Foo`.
+    fn print_path_with_qualified(
         &mut self,
-        print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
-        args: &[GenericArg<'tcx>],
+        self_ty: Ty<'tcx>,
+        trait_ref: Option<ty::TraitRef<'tcx>>,
     ) -> Result<(), PrintError>;
 
-    fn should_truncate(&mut self) -> bool {
-        false
-    }
-
     // Defaults (should not be overridden):
 
     #[instrument(skip(self), level = "debug")]
@@ -120,7 +138,7 @@ pub trait Printer<'tcx>: Sized {
         match key.disambiguated_data.data {
             DefPathData::CrateRoot => {
                 assert!(key.parent.is_none());
-                self.path_crate(def_id.krate)
+                self.print_crate_name(def_id.krate)
             }
 
             DefPathData::Impl => self.print_impl_path(def_id, args),
@@ -144,7 +162,7 @@ pub trait Printer<'tcx>: Sized {
                             )) = self.tcx().coroutine_kind(def_id)
                                 && args.len() > parent_args.len()
                             {
-                                return self.path_generic_args(
+                                return self.print_path_with_generic_args(
                                     |p| p.print_def_path(def_id, parent_args),
                                     &args[..parent_args.len() + 1][..1],
                                 );
@@ -166,7 +184,7 @@ pub trait Printer<'tcx>: Sized {
                         _ => {
                             if !generics.is_own_empty() && args.len() >= generics.count() {
                                 let args = generics.own_args_no_defaults(self.tcx(), args);
-                                return self.path_generic_args(
+                                return self.print_path_with_generic_args(
                                     |p| p.print_def_path(def_id, parent_args),
                                     args,
                                 );
@@ -182,7 +200,7 @@ pub trait Printer<'tcx>: Sized {
                         && self.tcx().generics_of(parent_def_id).parent_count == 0;
                 }
 
-                self.path_append(
+                self.print_path_with_simple(
                     |p: &mut Self| {
                         if trait_qualify_parent {
                             let trait_ref = ty::TraitRef::new(
@@ -190,7 +208,7 @@ pub trait Printer<'tcx>: Sized {
                                 parent_def_id,
                                 parent_args.iter().copied(),
                             );
-                            p.path_qualified(trait_ref.self_ty(), Some(trait_ref))
+                            p.print_path_with_qualified(trait_ref.self_ty(), Some(trait_ref))
                         } else {
                             p.print_def_path(parent_def_id, parent_args)
                         }
@@ -233,11 +251,15 @@ pub trait Printer<'tcx>: Sized {
             // If the impl is not co-located with either self-type or
             // trait-type, then fallback to a format that identifies
             // the module more clearly.
-            self.path_append_impl(|p| p.print_def_path(parent_def_id, &[]), self_ty, impl_trait_ref)
+            self.print_path_with_impl(
+                |p| p.print_def_path(parent_def_id, &[]),
+                self_ty,
+                impl_trait_ref,
+            )
         } else {
             // Otherwise, try to give a good form that would be valid language
             // syntax. Preferably using associated item notation.
-            self.path_qualified(self_ty, impl_trait_ref)
+            self.print_path_with_qualified(self_ty, impl_trait_ref)
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 67244e767cb..0a976f3a0ac 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -245,7 +245,7 @@ impl<'tcx> RegionHighlightMode<'tcx> {
 /// Trait for printers that pretty-print using `fmt::Write` to the printer.
 pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
     /// Like `print_def_path` but for value paths.
-    fn print_value_path(
+    fn pretty_print_value_path(
         &mut self,
         def_id: DefId,
         args: &'tcx [GenericArg<'tcx>],
@@ -253,7 +253,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         self.print_def_path(def_id, args)
     }
 
-    fn print_in_binder<T>(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), PrintError>
+    fn pretty_print_in_binder<T>(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), PrintError>
     where
         T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>,
     {
@@ -333,6 +333,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         f: impl FnOnce(&mut Self) -> Result<(), PrintError>,
     ) -> Result<(), PrintError>;
 
+    fn should_truncate(&mut self) -> bool {
+        false
+    }
+
     /// Returns `true` if the region should be printed in
     /// optional positions, e.g., `&'a T` or `dyn Tr + 'b`.
     /// This is typically the case for all non-`'_` regions.
@@ -470,7 +474,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         // path to the crate followed by the path to the item within the crate.
         if let Some(cnum) = def_id.as_crate_root() {
             if cnum == LOCAL_CRATE {
-                self.path_crate(cnum)?;
+                self.print_crate_name(cnum)?;
                 return Ok(true);
             }
 
@@ -494,7 +498,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                         // or avoid ending up with `ExternCrateSource::Extern`,
                         // for the injected `std`/`core`.
                         if span.is_dummy() {
-                            self.path_crate(cnum)?;
+                            self.print_crate_name(cnum)?;
                             return Ok(true);
                         }
 
@@ -508,13 +512,13 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                         return Ok(true);
                     }
                     (ExternCrateSource::Path, LOCAL_CRATE) => {
-                        self.path_crate(cnum)?;
+                        self.print_crate_name(cnum)?;
                         return Ok(true);
                     }
                     _ => {}
                 },
                 None => {
-                    self.path_crate(cnum)?;
+                    self.print_crate_name(cnum)?;
                     return Ok(true);
                 }
             }
@@ -624,7 +628,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
             return Ok(false);
         }
         callers.push(visible_parent);
-        // HACK(eddyb) this bypasses `path_append`'s prefix printing to avoid
+        // HACK(eddyb) this bypasses `print_path_with_simple`'s prefix printing to avoid
         // knowing ahead of time whether the entire path will succeed or not.
         // To support printers that do not implement `PrettyPrinter`, a `Vec` or
         // linked list on the stack would need to be built, before any printing.
@@ -633,11 +637,14 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
             true => {}
         }
         callers.pop();
-        self.path_append(|_| Ok(()), &DisambiguatedDefPathData { data, disambiguator: 0 })?;
+        self.print_path_with_simple(
+            |_| Ok(()),
+            &DisambiguatedDefPathData { data, disambiguator: 0 },
+        )?;
         Ok(true)
     }
 
-    fn pretty_path_qualified(
+    fn pretty_print_path_with_qualified(
         &mut self,
         self_ty: Ty<'tcx>,
         trait_ref: Option<ty::TraitRef<'tcx>>,
@@ -672,7 +679,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         })
     }
 
-    fn pretty_path_append_impl(
+    fn pretty_print_path_with_impl(
         &mut self,
         print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
         self_ty: Ty<'tcx>,
@@ -739,7 +746,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                     }
                     sig.print(self)?;
                     write!(self, " {{")?;
-                    self.print_value_path(def_id, args)?;
+                    self.pretty_print_value_path(def_id, args)?;
                     write!(self, "}}")?;
                 }
             }
@@ -1308,10 +1315,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         alias_ty: ty::AliasTerm<'tcx>,
     ) -> Result<(), PrintError> {
         let def_key = self.tcx().def_key(alias_ty.def_id);
-        self.path_generic_args(
+        self.print_path_with_generic_args(
             |p| {
-                p.path_append(
-                    |p| p.path_qualified(alias_ty.self_ty(), None),
+                p.print_path_with_simple(
+                    |p| p.print_path_with_qualified(alias_ty.self_ty(), None),
                     &def_key.disambiguated_data,
                 )
             },
@@ -1386,7 +1393,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                     if let ty::Tuple(tys) = principal.args.type_at(0).kind() {
                         let mut projections = predicates.projection_bounds();
                         if let (Some(proj), None) = (projections.next(), projections.next()) {
-                            p.pretty_fn_sig(
+                            p.pretty_print_fn_sig(
                                 tys,
                                 false,
                                 proj.skip_binder().term.as_type().expect("Return type was a const"),
@@ -1396,7 +1403,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                     }
                 }
 
-                // HACK(eddyb) this duplicates `FmtPrinter`'s `path_generic_args`,
+                // HACK(eddyb) this duplicates `FmtPrinter`'s `print_path_with_generic_args`,
                 // in order to place the projections inside the `<...>`.
                 if !resugared {
                     let principal_with_self =
@@ -1488,7 +1495,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         Ok(())
     }
 
-    fn pretty_fn_sig(
+    fn pretty_print_fn_sig(
         &mut self,
         inputs: &[Ty<'tcx>],
         c_variadic: bool,
@@ -1525,7 +1532,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
             ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => {
                 match self.tcx().def_kind(def) {
                     DefKind::Const | DefKind::AssocConst => {
-                        self.print_value_path(def, args)?;
+                        self.pretty_print_value_path(def, args)?;
                     }
                     DefKind::AnonConst => {
                         if def.is_local()
@@ -1534,13 +1541,13 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                         {
                             write!(self, "{snip}")?;
                         } else {
-                            // Do not call `print_value_path` as if a parent of this anon const is
-                            // an impl it will attempt to print out the impl trait ref i.e. `<T as
-                            // Trait>::{constant#0}`. This would cause printing to enter an
-                            // infinite recursion if the anon const is in the self type i.e.
-                            // `impl<T: Default> Default for [T; 32 - 1 - 1 - 1] {` where we would
-                            // try to print
-                            // `<[T; /* print constant#0 again */] as // Default>::{constant#0}`.
+                            // Do not call `pretty_print_value_path` as if a parent of this anon
+                            // const is an impl it will attempt to print out the impl trait ref
+                            // i.e. `<T as Trait>::{constant#0}`. This would cause printing to
+                            // enter an infinite recursion if the anon const is in the self type
+                            // i.e. `impl<T: Default> Default for [T; 32 - 1 - 1 - 1] {` where we
+                            // would try to print `<[T; /* print constant#0 again */] as //
+                            // Default>::{constant#0}`.
                             write!(
                                 self,
                                 "{}::{}",
@@ -1742,7 +1749,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                     self.tcx().try_get_global_alloc(prov.alloc_id())
                 {
                     self.typed_value(
-                        |this| this.print_value_path(instance.def_id(), instance.args),
+                        |this| this.pretty_print_value_path(instance.def_id(), instance.args),
                         |this| this.print_type(ty),
                         " as ",
                     )?;
@@ -1936,7 +1943,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                         let variant_idx =
                             contents.variant.expect("destructed const of adt without variant idx");
                         let variant_def = &def.variant(variant_idx);
-                        self.print_value_path(variant_def.def_id, args)?;
+                        self.pretty_print_value_path(variant_def.def_id, args)?;
                         match variant_def.ctor_kind() {
                             Some(CtorKind::Const) => {}
                             Some(CtorKind::Fn) => {
@@ -1972,7 +1979,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
             }
             (_, ty::FnDef(def_id, args)) => {
                 // Never allowed today, but we still encounter them in invalid const args.
-                self.print_value_path(def_id, args)?;
+                self.pretty_print_value_path(def_id, args)?;
                 return Ok(());
             }
             // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading
@@ -1993,7 +2000,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
         Ok(())
     }
 
-    fn pretty_closure_as_impl(
+    fn pretty_print_closure_as_impl(
         &mut self,
         closure: ty::ClosureArgs<TyCtxt<'tcx>>,
     ) -> Result<(), PrintError> {
@@ -2131,8 +2138,6 @@ impl<'a, 'tcx> FmtPrinter<'a, 'tcx> {
     }
 }
 
-// HACK(eddyb) get rid of `def_path_str` and/or pass `Namespace` explicitly always
-// (but also some things just print a `DefId` generally so maybe we need this?)
 fn guess_def_namespace(tcx: TyCtxt<'_>, def_id: DefId) -> Namespace {
     match tcx.def_key(def_id).disambiguated_data.data {
         DefPathData::TypeNs(..) | DefPathData::CrateRoot | DefPathData::OpaqueTy => {
@@ -2157,6 +2162,7 @@ impl<'t> TyCtxt<'t> {
         self.def_path_str_with_args(def_id, &[])
     }
 
+    /// For this one we determine the appropriate namespace for the `def_id`.
     pub fn def_path_str_with_args(
         self,
         def_id: impl IntoQueryParam<DefId>,
@@ -2169,16 +2175,17 @@ impl<'t> TyCtxt<'t> {
         FmtPrinter::print_string(self, ns, |p| p.print_def_path(def_id, args)).unwrap()
     }
 
+    /// For this one we always use value namespace.
     pub fn value_path_str_with_args(
         self,
         def_id: impl IntoQueryParam<DefId>,
         args: &'t [GenericArg<'t>],
     ) -> String {
         let def_id = def_id.into_query_param();
-        let ns = guess_def_namespace(self, def_id);
+        let ns = Namespace::ValueNS;
         debug!("value_path_str: def_id={:?}, ns={:?}", def_id, ns);
 
-        FmtPrinter::print_string(self, ns, |p| p.print_value_path(def_id, args)).unwrap()
+        FmtPrinter::print_string(self, ns, |p| p.print_def_path(def_id, args)).unwrap()
     }
 }
 
@@ -2230,7 +2237,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
 
                 self.print_def_path(parent_def_id, &[])?;
 
-                // HACK(eddyb) copy of `path_append` to avoid
+                // HACK(eddyb) copy of `print_path_with_simple` to avoid
                 // constructing a `DisambiguatedDefPathData`.
                 if !self.empty_path {
                     write!(self, "::")?;
@@ -2295,10 +2302,6 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
         }
     }
 
-    fn should_truncate(&mut self) -> bool {
-        !self.type_length_limit.value_within_limit(self.printed_type_count)
-    }
-
     fn print_dyn_existential(
         &mut self,
         predicates: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
@@ -2310,7 +2313,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
         self.pretty_print_const(ct, false)
     }
 
-    fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
+    fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
         self.empty_path = true;
         if cnum == LOCAL_CRATE {
             if self.tcx.sess.at_least_rust_2018() {
@@ -2327,23 +2330,23 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
         Ok(())
     }
 
-    fn path_qualified(
+    fn print_path_with_qualified(
         &mut self,
         self_ty: Ty<'tcx>,
         trait_ref: Option<ty::TraitRef<'tcx>>,
     ) -> Result<(), PrintError> {
-        self.pretty_path_qualified(self_ty, trait_ref)?;
+        self.pretty_print_path_with_qualified(self_ty, trait_ref)?;
         self.empty_path = false;
         Ok(())
     }
 
-    fn path_append_impl(
+    fn print_path_with_impl(
         &mut self,
         print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
         self_ty: Ty<'tcx>,
         trait_ref: Option<ty::TraitRef<'tcx>>,
     ) -> Result<(), PrintError> {
-        self.pretty_path_append_impl(
+        self.pretty_print_path_with_impl(
             |p| {
                 print_prefix(p)?;
                 if !p.empty_path {
@@ -2359,7 +2362,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
         Ok(())
     }
 
-    fn path_append(
+    fn print_path_with_simple(
         &mut self,
         print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
         disambiguated_data: &DisambiguatedDefPathData,
@@ -2390,7 +2393,7 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> {
         Ok(())
     }
 
-    fn path_generic_args(
+    fn print_path_with_generic_args(
         &mut self,
         print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
         args: &[GenericArg<'tcx>],
@@ -2421,7 +2424,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
         self.0.const_infer_name_resolver.as_ref().and_then(|func| func(id))
     }
 
-    fn print_value_path(
+    fn pretty_print_value_path(
         &mut self,
         def_id: DefId,
         args: &'tcx [GenericArg<'tcx>],
@@ -2433,7 +2436,7 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
         Ok(())
     }
 
-    fn print_in_binder<T>(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), PrintError>
+    fn pretty_print_in_binder<T>(&mut self, value: &ty::Binder<'tcx, T>) -> Result<(), PrintError>
     where
         T: Print<'tcx, Self> + TypeFoldable<TyCtxt<'tcx>>,
     {
@@ -2487,6 +2490,10 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
         Ok(())
     }
 
+    fn should_truncate(&mut self) -> bool {
+        !self.type_length_limit.value_within_limit(self.printed_type_count)
+    }
+
     fn should_print_region(&self, region: ty::Region<'tcx>) -> bool {
         let highlight = self.region_highlight_mode;
         if highlight.region_highlighted(region).is_some() {
@@ -2892,7 +2899,7 @@ where
     T: Print<'tcx, P> + TypeFoldable<TyCtxt<'tcx>>,
 {
     fn print(&self, p: &mut P) -> Result<(), PrintError> {
-        p.print_in_binder(self)
+        p.pretty_print_in_binder(self)
     }
 }
 
@@ -3090,7 +3097,7 @@ define_print! {
         }
 
         write!(p, "fn")?;
-        p.pretty_fn_sig(self.inputs(), self.c_variadic, self.output())?;
+        p.pretty_print_fn_sig(self.inputs(), self.c_variadic, self.output())?;
     }
 
     ty::TraitRef<'tcx> {
@@ -3225,7 +3232,7 @@ define_print! {
         // The args don't contain the self ty (as it has been erased) but the corresp.
         // generics do as the trait always has a self ty param. We need to offset.
         let args = &self.args[p.tcx().generics_of(self.def_id).parent_count - 1..];
-        p.path_generic_args(|p| write!(p, "{name}"), args)?;
+        p.print_path_with_generic_args(|p| write!(p, "{name}"), args)?;
         write!(p, " = ")?;
         self.term.print(p)?;
     }
@@ -3314,7 +3321,7 @@ define_print_and_forward_display! {
     }
 
     PrintClosureAsImpl<'tcx> {
-        p.pretty_closure_as_impl(self.closure)?;
+        p.pretty_print_closure_as_impl(self.closure)?;
     }
 
     ty::ParamTy {
diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs
index b186c2bd775..03fdf9fbac5 100644
--- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs
+++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs
@@ -18,7 +18,7 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
     let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id);
     // If this has an extern indicator, then this function is globally shared and thus will not
     // generate cgu-internal copies which would make it cross-crate inlinable.
-    if codegen_fn_attrs.contains_extern_indicator() {
+    if codegen_fn_attrs.contains_extern_indicator(tcx, def_id.into()) {
         return false;
     }
 
diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs
index 12cbc7e8f91..84f8eda4f8d 100644
--- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs
@@ -48,7 +48,9 @@ where
     ) -> QueryResult<I> {
         match kind {
             PathKind::Coinductive => response_no_constraints(cx, input, Certainty::Yes),
-            PathKind::Unknown => response_no_constraints(cx, input, Certainty::overflow(false)),
+            PathKind::Unknown | PathKind::ForcedAmbiguity => {
+                response_no_constraints(cx, input, Certainty::overflow(false))
+            }
             // Even though we know these cycles to be unproductive, we still return
             // overflow during coherence. This is both as we are not 100% confident in
             // the implementation yet and any incorrect errors would be unsound there.
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index aaf1b6c05bf..3a21eea3d0a 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -869,6 +869,11 @@ parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto`
 parse_trait_alias_cannot_be_const = trait aliases cannot be `const`
 parse_trait_alias_cannot_be_unsafe = trait aliases cannot be `unsafe`
 
+parse_trait_impl_modifier_in_inherent_impl = inherent impls cannot be {$modifier_name}
+    .because = {$modifier_name} because of this
+    .type = inherent impl for this type
+    .note = only trait implementations may be annotated with `{$modifier}`
+
 parse_transpose_dyn_or_impl = `for<...>` expected after `{$kw}`, not before
     .suggestion = move `{$kw}` before the `for<...>`
 
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index ddb2c545c78..a07d0606fd0 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -71,6 +71,20 @@ pub(crate) struct BadQPathStage2 {
     pub wrap: WrapType,
 }
 
+#[derive(Diagnostic)]
+#[diag(parse_trait_impl_modifier_in_inherent_impl)]
+#[note]
+pub(crate) struct TraitImplModifierInInherentImpl {
+    #[primary_span]
+    pub span: Span,
+    pub modifier: &'static str,
+    pub modifier_name: &'static str,
+    #[label(parse_because)]
+    pub modifier_span: Span,
+    #[label(parse_type)]
+    pub self_ty: Span,
+}
+
 #[derive(Subdiagnostic)]
 #[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
 pub(crate) struct WrapType {
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 14a90e74049..607adaf0829 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -663,20 +663,44 @@ impl<'a> Parser<'a> {
                 };
                 let trait_ref = TraitRef { path, ref_id: ty_first.id };
 
-                (Some(trait_ref), ty_second)
+                let of_trait = Some(Box::new(TraitImplHeader {
+                    defaultness,
+                    safety,
+                    constness,
+                    polarity,
+                    trait_ref,
+                }));
+                (of_trait, ty_second)
+            }
+            None => {
+                let self_ty = ty_first;
+                let error = |modifier, modifier_name, modifier_span| {
+                    self.dcx().create_err(errors::TraitImplModifierInInherentImpl {
+                        span: self_ty.span,
+                        modifier,
+                        modifier_name,
+                        modifier_span,
+                        self_ty: self_ty.span,
+                    })
+                };
+
+                if let Safety::Unsafe(span) = safety {
+                    error("unsafe", "unsafe", span).with_code(E0197).emit();
+                }
+                if let ImplPolarity::Negative(span) = polarity {
+                    error("!", "negative", span).emit();
+                }
+                if let Defaultness::Default(def_span) = defaultness {
+                    error("default", "default", def_span).emit();
+                }
+                if let Const::Yes(span) = constness {
+                    error("const", "const", span).emit();
+                }
+                (None, self_ty)
             }
-            None => (None, ty_first), // impl Type
         };
-        Ok(ItemKind::Impl(Box::new(Impl {
-            safety,
-            polarity,
-            defaultness,
-            constness,
-            generics,
-            of_trait,
-            self_ty,
-            items: impl_items,
-        })))
+
+        Ok(ItemKind::Impl(Impl { generics, of_trait, self_ty, items: impl_items }))
     }
 
     fn parse_item_delegation(&mut self) -> PResult<'a, ItemKind> {
@@ -1364,10 +1388,10 @@ impl<'a> Parser<'a> {
         };
 
         match &mut item_kind {
-            ItemKind::Impl(box Impl { of_trait: Some(trai), constness, .. }) => {
-                *constness = Const::Yes(const_span);
+            ItemKind::Impl(Impl { of_trait: Some(of_trait), .. }) => {
+                of_trait.constness = Const::Yes(const_span);
 
-                let before_trait = trai.path.span.shrink_to_lo();
+                let before_trait = of_trait.trait_ref.path.span.shrink_to_lo();
                 let const_up_to_impl = const_span.with_hi(impl_span.lo());
                 err.with_multipart_suggestion(
                     "you might have meant to write a const trait impl",
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index a7f8d3b9139..68ef6d6f32c 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -298,35 +298,42 @@ fn emit_malformed_attribute(
         suggestions.push(format!("#{inner}[{name}]"));
     }
     if let Some(descr) = template.list {
-        suggestions.push(format!("#{inner}[{name}({descr})]"));
+        for descr in descr {
+            suggestions.push(format!("#{inner}[{name}({descr})]"));
+        }
     }
     suggestions.extend(template.one_of.iter().map(|&word| format!("#{inner}[{name}({word})]")));
     if let Some(descr) = template.name_value_str {
-        suggestions.push(format!("#{inner}[{name} = \"{descr}\"]"));
+        for descr in descr {
+            suggestions.push(format!("#{inner}[{name} = \"{descr}\"]"));
+        }
     }
     if should_warn(name) {
         psess.buffer_lint(
             ILL_FORMED_ATTRIBUTE_INPUT,
             span,
             ast::CRATE_NODE_ID,
-            BuiltinLintDiag::IllFormedAttributeInput { suggestions: suggestions.clone() },
+            BuiltinLintDiag::IllFormedAttributeInput {
+                suggestions: suggestions.clone(),
+                docs: template.docs,
+            },
         );
     } else {
         suggestions.sort();
-        psess
-            .dcx()
-            .struct_span_err(span, error_msg)
-            .with_span_suggestions(
-                span,
-                if suggestions.len() == 1 {
-                    "must be of the form"
-                } else {
-                    "the following are the possible correct uses"
-                },
-                suggestions,
-                Applicability::HasPlaceholders,
-            )
-            .emit();
+        let mut err = psess.dcx().struct_span_err(span, error_msg).with_span_suggestions(
+            span,
+            if suggestions.len() == 1 {
+                "must be of the form"
+            } else {
+                "the following are the possible correct uses"
+            },
+            suggestions,
+            Applicability::HasPlaceholders,
+        );
+        if let Some(link) = template.docs {
+            err.note(format!("for more information, visit <{link}>"));
+        }
+        err.emit();
     }
 }
 
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 6a28fe2617e..eb03235de0c 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -29,7 +29,7 @@ passes_allow_incoherent_impl =
     `rustc_allow_incoherent_impl` attribute should be applied to impl items
     .label = the only currently supported targets are inherent methods
 
-passes_allow_internal_unstable =
+passes_macro_only_attribute =
     attribute should be applied to a macro
     .label = not a macro
 
@@ -510,6 +510,7 @@ passes_must_not_suspend =
 
 passes_must_use_no_effect =
     `#[must_use]` has no effect when applied to {$article} {$target}
+    .suggestion = remove the attribute
 
 passes_no_link =
     attribute should be applied to an `extern crate` item
@@ -669,8 +670,8 @@ passes_rustc_std_internal_symbol =
     .label = not a function or static
 
 passes_rustc_unstable_feature_bound =
-    attribute should be applied to `impl` or free function outside of any `impl` or trait
-    .label = not an `impl` or free function
+    attribute should be applied to `impl`, trait or free function
+    .label = not an `impl`, trait or free function
 
 passes_should_be_applied_to_fn =
     attribute should be applied to a function definition
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 10c532b436a..165f8fe1995 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -207,6 +207,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 Attribute::Parsed(AttributeKind::ConstContinue(attr_span)) => {
                     self.check_const_continue(hir_id, *attr_span, target)
                 }
+                Attribute::Parsed(AttributeKind::AllowInternalUnsafe(attr_span)) => {
+                    self.check_allow_internal_unsafe(hir_id, *attr_span, span, target, attrs)
+                }
                 Attribute::Parsed(AttributeKind::AllowInternalUnstable(_, first_span)) => {
                     self.check_allow_internal_unstable(hir_id, *first_span, span, target, attrs)
                 }
@@ -413,7 +416,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                             // internal
                             | sym::prelude_import
                             | sym::panic_handler
-                            | sym::allow_internal_unsafe
                             | sym::lang
                             | sym::needs_allocator
                             | sym::default_lib_allocator
@@ -561,7 +563,24 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         match target {
             Target::Fn
             | Target::Closure
-            | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => {}
+            | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => {
+                // `#[inline]` is ignored if the symbol must be codegened upstream because it's exported.
+                if let Some(did) = hir_id.as_owner()
+                    && self.tcx.def_kind(did).has_codegen_attrs()
+                    && kind != &InlineAttr::Never
+                {
+                    let attrs = self.tcx.codegen_fn_attrs(did);
+                    // Not checking naked as `#[inline]` is forbidden for naked functions anyways.
+                    if attrs.contains_extern_indicator(self.tcx, did.into()) {
+                        self.tcx.emit_node_span_lint(
+                            UNUSED_ATTRIBUTES,
+                            hir_id,
+                            attr_span,
+                            errors::InlineIgnoredForExported {},
+                        );
+                    }
+                }
+            }
             Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
                 self.tcx.emit_node_span_lint(
                     UNUSED_ATTRIBUTES,
@@ -588,23 +607,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 self.dcx().emit_err(errors::InlineNotFnOrClosure { attr_span, defn_span });
             }
         }
-
-        // `#[inline]` is ignored if the symbol must be codegened upstream because it's exported.
-        if let Some(did) = hir_id.as_owner()
-            && self.tcx.def_kind(did).has_codegen_attrs()
-            && kind != &InlineAttr::Never
-        {
-            let attrs = self.tcx.codegen_fn_attrs(did);
-            // Not checking naked as `#[inline]` is forbidden for naked functions anyways.
-            if attrs.contains_extern_indicator() {
-                self.tcx.emit_node_span_lint(
-                    UNUSED_ATTRIBUTES,
-                    hir_id,
-                    attr_span,
-                    errors::InlineIgnoredForExported {},
-                );
-            }
-        }
     }
 
     /// Checks that `#[coverage(..)]` is applied to a function/closure/method,
@@ -1155,8 +1157,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 let is_valid = doc_fake_variadic_is_allowed_self_ty(i.self_ty)
                     || if let Some(&[hir::GenericArg::Type(ty)]) = i
                         .of_trait
-                        .as_ref()
-                        .and_then(|trait_ref| trait_ref.path.segments.last())
+                        .and_then(|of_trait| of_trait.trait_ref.path.segments.last())
                         .map(|last_segment| last_segment.args().args)
                     {
                         matches!(&ty.kind, hir::TyKind::Tup([_]))
@@ -1621,7 +1622,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             UNUSED_ATTRIBUTES,
             hir_id,
             attr_span,
-            errors::MustUseNoEffect { article, target },
+            errors::MustUseNoEffect { article, target, attr_span },
         );
     }
 
@@ -1646,8 +1647,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             && let parent_hir_id = self.tcx.parent_hir_id(hir_id)
             && let hir::Node::Item(item) = self.tcx.hir_node(parent_hir_id)
             && let hir::ItemKind::Impl(impl_) = item.kind
-            && let Some(trait_) = impl_.of_trait
-            && let Some(def_id) = trait_.trait_def_id()
+            && let Some(of_trait) = impl_.of_trait
+            && let Some(def_id) = of_trait.trait_ref.trait_def_id()
             && self.tcx.is_lang_item(def_id, hir::LangItem::Drop)
         {
             return;
@@ -2212,7 +2213,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
 
     /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
     /// (Allows proc_macro functions)
-    // FIXME(jdonszelmann): if possible, move to attr parsing
     fn check_allow_internal_unstable(
         &self,
         hir_id: HirId,
@@ -2221,6 +2221,42 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         target: Target,
         attrs: &[Attribute],
     ) {
+        self.check_macro_only_attr(
+            hir_id,
+            attr_span,
+            span,
+            target,
+            attrs,
+            "allow_internal_unstable",
+        )
+    }
+
+    /// Outputs an error for `#[allow_internal_unsafe]` which can only be applied to macros.
+    /// (Allows proc_macro functions)
+    fn check_allow_internal_unsafe(
+        &self,
+        hir_id: HirId,
+        attr_span: Span,
+        span: Span,
+        target: Target,
+        attrs: &[Attribute],
+    ) {
+        self.check_macro_only_attr(hir_id, attr_span, span, target, attrs, "allow_internal_unsafe")
+    }
+
+    /// Outputs an error for attributes that can only be applied to macros, such as
+    /// `#[allow_internal_unsafe]` and `#[allow_internal_unstable]`.
+    /// (Allows proc_macro functions)
+    // FIXME(jdonszelmann): if possible, move to attr parsing
+    fn check_macro_only_attr(
+        &self,
+        hir_id: HirId,
+        attr_span: Span,
+        span: Span,
+        target: Target,
+        attrs: &[Attribute],
+        attr_name: &str,
+    ) {
         match target {
             Target::Fn => {
                 for attr in attrs {
@@ -2238,18 +2274,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm => {
-                self.inline_attr_str_error_without_macro_def(
-                    hir_id,
-                    attr_span,
-                    "allow_internal_unstable",
-                );
+                self.inline_attr_str_error_without_macro_def(hir_id, attr_span, attr_name);
                 return;
             }
             // otherwise continue out of the match
             _ => {}
         }
 
-        self.tcx.dcx().emit_err(errors::AllowInternalUnstable { attr_span, span });
+        self.tcx.dcx().emit_err(errors::MacroOnlyAttribute { attr_span, span });
     }
 
     /// Checks if the items on the `#[debugger_visualizer]` attribute are valid.
@@ -2294,7 +2326,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         match target {
             // FIXME(staged_api): There's no reason we can't support more targets here. We're just
             // being conservative to begin with.
-            Target::Fn | Target::Impl { .. } => {}
+            Target::Fn | Target::Impl { .. } | Target::Trait => {}
             Target::ExternCrate
             | Target::Use
             | Target::Static
@@ -2309,7 +2341,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             | Target::Struct
             | Target::Field
             | Target::Union
-            | Target::Trait
             | Target::TraitAlias
             | Target::Expression
             | Target::Statement
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index fa9d0c7b1b7..de52973acbb 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -172,7 +172,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
         }
     }
 
-    #[allow(dead_code)] // FIXME(81658): should be used + lint reinstated after #83171 relands.
     fn handle_assign(&mut self, expr: &'tcx hir::Expr<'tcx>) {
         if self
             .typeck_results()
@@ -189,7 +188,6 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
         }
     }
 
-    #[allow(dead_code)] // FIXME(81658): should be used + lint reinstated after #83171 relands.
     fn check_for_self_assign(&mut self, assign: &'tcx hir::Expr<'tcx>) {
         fn check_for_self_assign_helper<'tcx>(
             typeck_results: &'tcx ty::TypeckResults<'tcx>,
@@ -576,6 +574,10 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
             hir::ExprKind::OffsetOf(..) => {
                 self.handle_offset_of(expr);
             }
+            hir::ExprKind::Assign(ref lhs, ..) => {
+                self.handle_assign(lhs);
+                self.check_for_self_assign(expr);
+            }
             _ => (),
         }
 
@@ -701,7 +703,7 @@ fn has_allow_dead_code_or_lang_attr(
 
             // #[used], #[no_mangle], #[export_name], etc also keeps the item alive
             // forcefully, e.g., for placing it in a specific section.
-            cg_attrs.contains_extern_indicator()
+            cg_attrs.contains_extern_indicator(tcx, def_id.into())
                 || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)
                 || cg_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
         }
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index c6ab6b0d601..37216656e57 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -469,6 +469,8 @@ pub(crate) struct FfiConstInvalidTarget {
 pub(crate) struct MustUseNoEffect {
     pub article: &'static str,
     pub target: rustc_hir::Target,
+    #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
+    pub attr_span: Span,
 }
 
 #[derive(Diagnostic)]
@@ -643,8 +645,8 @@ pub(crate) struct UsedStatic {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_allow_internal_unstable)]
-pub(crate) struct AllowInternalUnstable {
+#[diag(passes_macro_only_attribute)]
+pub(crate) struct MacroOnlyAttribute {
     #[primary_span]
     pub attr_span: Span,
     #[label]
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index 2f78c22c748..6cd8a54ecf4 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -183,7 +183,7 @@ impl<'tcx> ReachableContext<'tcx> {
             } else {
                 CodegenFnAttrs::EMPTY
             };
-            let is_extern = codegen_attrs.contains_extern_indicator();
+            let is_extern = codegen_attrs.contains_extern_indicator(self.tcx, search_item.into());
             if is_extern {
                 self.reachable_symbols.insert(search_item);
             }
@@ -423,8 +423,9 @@ fn has_custom_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
     if !tcx.def_kind(def_id).has_codegen_attrs() {
         return false;
     }
+
     let codegen_attrs = tcx.codegen_fn_attrs(def_id);
-    codegen_attrs.contains_extern_indicator()
+    codegen_attrs.contains_extern_indicator(tcx, def_id.into())
         // FIXME(nbdd0121): `#[used]` are marked as reachable here so it's picked up by
         // `linked_symbols` in cg_ssa. They won't be exported in binary or cdylib due to their
         // `SymbolExportLevel::Rust` export level but may end up being exported in dylibs.
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index e2f223325df..71650c6b9b9 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -590,9 +590,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
             // For implementations of traits, check the stability of each item
             // individually as it's possible to have a stable trait with unstable
             // items.
-            hir::ItemKind::Impl(hir::Impl {
-                of_trait: Some(t), self_ty, items, constness, ..
-            }) => {
+            hir::ItemKind::Impl(hir::Impl { of_trait: Some(of_trait), self_ty, items, .. }) => {
                 let features = self.tcx.features();
                 if features.staged_api() {
                     let attrs = self.tcx.hir_attrs(item.hir_id());
@@ -628,7 +626,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                     {
                         let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true };
                         c.visit_ty_unambig(self_ty);
-                        c.visit_trait_ref(t);
+                        c.visit_trait_ref(&of_trait.trait_ref);
 
                         // Skip the lint if the impl is marked as unstable using
                         // #[unstable_feature_bound(..)]
@@ -641,7 +639,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
 
                         // do not lint when the trait isn't resolved, since resolution error should
                         // be fixed first
-                        if t.path.res != Res::Err
+                        if of_trait.trait_ref.path.res != Res::Err
                             && c.fully_stable
                             && !unstable_feature_bound_in_effect
                         {
@@ -655,7 +653,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                     }
 
                     if features.const_trait_impl()
-                        && let hir::Constness::Const = constness
+                        && let hir::Constness::Const = of_trait.constness
                     {
                         let stable_or_implied_stable = match const_stab {
                             None => true,
@@ -671,7 +669,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                             Some(_) => false,
                         };
 
-                        if let Some(trait_id) = t.trait_def_id()
+                        if let Some(trait_id) = of_trait.trait_ref.trait_def_id()
                             && let Some(const_stab) = self.tcx.lookup_const_stability(trait_id)
                         {
                             // the const stability of a trait impl must match the const stability on the trait.
@@ -699,14 +697,18 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                     }
                 }
 
-                if let hir::Constness::Const = constness
-                    && let Some(def_id) = t.trait_def_id()
+                if let hir::Constness::Const = of_trait.constness
+                    && let Some(def_id) = of_trait.trait_ref.trait_def_id()
                 {
                     // FIXME(const_trait_impl): Improve the span here.
-                    self.tcx.check_const_stability(def_id, t.path.span, t.path.span);
+                    self.tcx.check_const_stability(
+                        def_id,
+                        of_trait.trait_ref.path.span,
+                        of_trait.trait_ref.path.span,
+                    );
                 }
 
-                for impl_item_ref in *items {
+                for impl_item_ref in items {
                     let impl_item = self.tcx.associated_item(impl_item_ref.owner_id);
 
                     if let Some(def_id) = impl_item.trait_item_def_id {
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 5d02c02b23c..1bddbd03cc3 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1779,7 +1779,8 @@ fn check_mod_privacy(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
         if let DefKind::Impl { of_trait: true } = tcx.def_kind(def_id) {
             let trait_ref = tcx.impl_trait_ref(def_id).unwrap();
             let trait_ref = trait_ref.instantiate_identity();
-            visitor.span = tcx.hir_expect_item(def_id).expect_impl().of_trait.unwrap().path.span;
+            visitor.span =
+                tcx.hir_expect_item(def_id).expect_impl().of_trait.unwrap().trait_ref.path.span;
             let _ =
                 visitor.visit_def_id(trait_ref.def_id, "trait", &trait_ref.print_only_trait_path());
         }
diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index ceef558c0cf..d5ff8a4b609 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -242,6 +242,9 @@ resolve_lowercase_self =
     attempt to use a non-constant value in a constant
     .suggestion = try using `Self`
 
+resolve_macro_cannot_use_as_fn_like =
+    `{$ident}` exists, but has no rules for function-like invocation
+
 resolve_macro_cannot_use_as_attr =
     `{$ident}` exists, but has no `attr` rules
 
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index d18d0fc16a8..988586334fa 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -11,7 +11,7 @@ use std::sync::Arc;
 use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind};
 use rustc_ast::{
     self as ast, AssocItem, AssocItemKind, Block, ConstItem, Delegation, Fn, ForeignItem,
-    ForeignItemKind, Impl, Item, ItemKind, NodeId, StaticItem, StmtKind, TyAlias,
+    ForeignItemKind, Item, ItemKind, NodeId, StaticItem, StmtKind, TyAlias,
 };
 use rustc_attr_parsing as attr;
 use rustc_attr_parsing::AttributeParser;
@@ -906,10 +906,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
             }
 
             // These items do not add names to modules.
-            ItemKind::Impl(box Impl { of_trait: Some(..), .. })
-            | ItemKind::Impl { .. }
-            | ItemKind::ForeignMod(..)
-            | ItemKind::GlobalAsm(..) => {}
+            ItemKind::Impl { .. } | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {}
 
             ItemKind::MacroDef(..) | ItemKind::MacCall(_) | ItemKind::DelegationMac(..) => {
                 unreachable!()
@@ -1235,7 +1232,8 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
             ItemKind::Fn(box ast::Fn { ident: fn_ident, .. }) => {
                 match self.proc_macro_stub(item, *fn_ident) {
                     Some((macro_kind, ident, span)) => {
-                        let res = Res::Def(DefKind::Macro(macro_kind), def_id.to_def_id());
+                        let macro_kinds = macro_kind.into();
+                        let res = Res::Def(DefKind::Macro(macro_kinds), def_id.to_def_id());
                         let macro_data = MacroData::new(self.r.dummy_ext(macro_kind));
                         self.r.new_local_macro(def_id, macro_data);
                         self.r.proc_macro_stubs.insert(def_id);
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 7d51fef28d3..1e4513eb787 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -149,9 +149,9 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
 
                 let macro_data =
                     self.resolver.compile_macro(def, *ident, &attrs, i.span, i.id, edition);
-                let macro_kind = macro_data.ext.macro_kind();
+                let macro_kinds = macro_data.ext.macro_kinds();
                 opt_macro_data = Some(macro_data);
-                DefKind::Macro(macro_kind)
+                DefKind::Macro(macro_kinds)
             }
             ItemKind::GlobalAsm(..) => DefKind::GlobalAsm,
             ItemKind::Use(use_tree) => {
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 210ab72678c..a78cf028795 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -13,7 +13,7 @@ use rustc_errors::{
 use rustc_feature::BUILTIN_ATTRIBUTES;
 use rustc_hir::attrs::{AttributeKind, CfgEntry, StrippedCfgItem};
 use rustc_hir::def::Namespace::{self, *};
-use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS};
+use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, MacroKinds, NonMacroAttrKind, PerNS};
 use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
 use rustc_hir::{PrimTy, Stability, StabilityLevel, find_attr};
 use rustc_middle::bug;
@@ -1491,11 +1491,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                     let Some(binding) = resolution.borrow().best_binding() else {
                         continue;
                     };
-                    let Res::Def(DefKind::Macro(MacroKind::Derive | MacroKind::Attr), def_id) =
-                        binding.res()
-                    else {
+                    let Res::Def(DefKind::Macro(kinds), def_id) = binding.res() else {
                         continue;
                     };
+                    if !kinds.intersects(MacroKinds::ATTR | MacroKinds::DERIVE) {
+                        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);
@@ -1504,7 +1505,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             },
         );
 
-        let is_expected = &|res: Res| res.macro_kind() == Some(macro_kind);
+        let is_expected =
+            &|res: Res| res.macro_kinds().is_some_and(|k| k.contains(macro_kind.into()));
         let suggestion = self.early_lookup_typo_candidate(
             ScopeSet::Macro(macro_kind),
             parent_scope,
@@ -1553,11 +1555,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         if let Some((def_id, unused_ident)) = unused_macro {
             let scope = self.local_macro_def_scopes[&def_id];
             let parent_nearest = parent_scope.module.nearest_parent_mod();
-            if Some(parent_nearest) == scope.opt_def_id() {
+            let unused_macro_kinds = self.local_macro_map[def_id].ext.macro_kinds();
+            if !unused_macro_kinds.contains(macro_kind.into()) {
                 match macro_kind {
                     MacroKind::Bang => {
-                        err.subdiagnostic(MacroDefinedLater { span: unused_ident.span });
-                        err.subdiagnostic(MacroSuggMovePosition { span: ident.span, ident });
+                        err.subdiagnostic(MacroRulesNot::Func { span: unused_ident.span, ident });
                     }
                     MacroKind::Attr => {
                         err.subdiagnostic(MacroRulesNot::Attr { span: unused_ident.span, ident });
@@ -1566,14 +1568,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                         err.subdiagnostic(MacroRulesNot::Derive { span: unused_ident.span, ident });
                     }
                 }
-
                 return;
             }
-        }
-
-        if self.macro_names.contains(&ident.normalize_to_macros_2_0()) {
-            err.subdiagnostic(AddedMacroUse);
-            return;
+            if Some(parent_nearest) == scope.opt_def_id() {
+                err.subdiagnostic(MacroDefinedLater { span: unused_ident.span });
+                err.subdiagnostic(MacroSuggMovePosition { span: ident.span, ident });
+                return;
+            }
         }
 
         if ident.name == kw::Default
@@ -1601,13 +1602,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             };
 
             let desc = match binding.res() {
-                Res::Def(DefKind::Macro(MacroKind::Bang), _) => "a function-like macro".to_string(),
-                Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => {
+                Res::Def(DefKind::Macro(MacroKinds::BANG), _) => {
+                    "a function-like macro".to_string()
+                }
+                Res::Def(DefKind::Macro(MacroKinds::ATTR), _) | Res::NonMacroAttr(..) => {
                     format!("an attribute: `#[{ident}]`")
                 }
-                Res::Def(DefKind::Macro(MacroKind::Derive), _) => {
+                Res::Def(DefKind::Macro(MacroKinds::DERIVE), _) => {
                     format!("a derive macro: `#[derive({ident})]`")
                 }
+                Res::Def(DefKind::Macro(kinds), _) => {
+                    format!("{} {}", kinds.article(), kinds.descr())
+                }
                 Res::ToolMod => {
                     // Don't confuse the user with tool modules.
                     continue;
@@ -1644,6 +1650,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             err.subdiagnostic(note);
             return;
         }
+
+        if self.macro_names.contains(&ident.normalize_to_macros_2_0()) {
+            err.subdiagnostic(AddedMacroUse);
+            return;
+        }
     }
 
     /// Given an attribute macro that failed to be resolved, look for `derive` macros that could
@@ -2748,9 +2759,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
 
         let binding_key = BindingKey::new(ident, MacroNS);
         let binding = self.resolution(crate_module, binding_key)?.binding()?;
-        let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() else {
+        let Res::Def(DefKind::Macro(kinds), _) = binding.res() else {
             return None;
         };
+        if !kinds.contains(MacroKinds::BANG) {
+            return None;
+        }
         let module_name = crate_module.kind.name().unwrap_or(kw::Crate);
         let import_snippet = match import.kind {
             ImportKind::Single { source, target, .. } if source != target => {
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index 2747ba135ed..a1d62ba7a68 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -672,6 +672,12 @@ pub(crate) struct MacroSuggMovePosition {
 
 #[derive(Subdiagnostic)]
 pub(crate) enum MacroRulesNot {
+    #[label(resolve_macro_cannot_use_as_fn_like)]
+    Func {
+        #[primary_span]
+        span: Span,
+        ident: Ident,
+    },
     #[label(resolve_macro_cannot_use_as_attr)]
     Attr {
         #[primary_span]
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 9efcef695b7..87b3fc76c96 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -2,7 +2,7 @@ use Determinacy::*;
 use Namespace::*;
 use rustc_ast::{self as ast, NodeId};
 use rustc_errors::ErrorGuaranteed;
-use rustc_hir::def::{DefKind, Namespace, NonMacroAttrKind, PartialRes, PerNS};
+use rustc_hir::def::{DefKind, MacroKinds, Namespace, NonMacroAttrKind, PartialRes, PerNS};
 use rustc_middle::bug;
 use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK;
@@ -259,7 +259,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         {
             let ext = &self.get_macro_by_def_id(def_id).ext;
             if ext.builtin_name.is_none()
-                && ext.macro_kind() == MacroKind::Derive
+                && ext.macro_kinds() == MacroKinds::DERIVE
                 && parent.expansion.outer_expn_is_descendant_of(*ctxt)
             {
                 return Some((parent, derive_fallback_lint_id));
@@ -632,17 +632,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
 
                 match result {
                     Ok((binding, flags)) => {
-                        let binding_macro_kind = binding.macro_kind();
-                        // If we're looking for an attribute, that might be supported by a
-                        // `macro_rules!` macro.
-                        // FIXME: Replace this with tracking multiple macro kinds for one Def.
-                        if !(sub_namespace_match(binding_macro_kind, macro_kind)
-                            || (binding_macro_kind == Some(MacroKind::Bang)
-                                && macro_kind == Some(MacroKind::Attr)
-                                && this
-                                    .get_macro(binding.res())
-                                    .is_some_and(|macro_data| macro_data.attr_ext.is_some())))
-                        {
+                        if !sub_namespace_match(binding.macro_kinds(), macro_kind) {
                             return None;
                         }
 
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 953b72fd72b..e52cbeb733a 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -2620,7 +2620,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                 self.resolve_adt(item, generics);
             }
 
-            ItemKind::Impl(box Impl {
+            ItemKind::Impl(Impl {
                 ref generics,
                 ref of_trait,
                 ref self_ty,
@@ -2631,7 +2631,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                 self.resolve_implementation(
                     &item.attrs,
                     generics,
-                    of_trait,
+                    of_trait.as_deref(),
                     self_ty,
                     item.id,
                     impl_items,
@@ -3177,7 +3177,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         &mut self,
         attrs: &[ast::Attribute],
         generics: &'ast Generics,
-        opt_trait_reference: &'ast Option<TraitRef>,
+        of_trait: Option<&'ast ast::TraitImplHeader>,
         self_type: &'ast Ty,
         item_id: NodeId,
         impl_items: &'ast [Box<AssocItem>],
@@ -3201,7 +3201,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                         |this| {
                             // Resolve the trait reference, if necessary.
                             this.with_optional_trait_ref(
-                                opt_trait_reference.as_ref(),
+                                of_trait.map(|t| &t.trait_ref),
                                 self_type,
                                 |this, trait_id| {
                                     this.resolve_doc_links(attrs, MaybeExported::Impl(trait_id));
@@ -3224,9 +3224,9 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
                                         is_trait_impl: trait_id.is_some()
                                     };
                                     this.with_self_rib(res, |this| {
-                                        if let Some(trait_ref) = opt_trait_reference.as_ref() {
+                                        if let Some(of_trait) = of_trait {
                                             // Resolve type arguments in the trait path.
-                                            visit::walk_trait_ref(this, trait_ref);
+                                            visit::walk_trait_ref(this, &of_trait.trait_ref);
                                         }
                                         // Resolve the self type.
                                         this.visit_ty(self_type);
@@ -5183,7 +5183,7 @@ impl<'ast> Visitor<'ast> for ItemInfoCollector<'_, '_, '_> {
             | ItemKind::Enum(_, generics, _)
             | ItemKind::Struct(_, generics, _)
             | ItemKind::Union(_, generics, _)
-            | ItemKind::Impl(box Impl { generics, .. })
+            | ItemKind::Impl(Impl { generics, .. })
             | ItemKind::Trait(box Trait { generics, .. })
             | ItemKind::TraitAlias(_, generics, _) => {
                 if let ItemKind::Fn(box Fn { sig, .. }) = &item.kind {
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index aca251da71d..c8cab5a0fe9 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -19,14 +19,13 @@ use rustc_errors::{
 };
 use rustc_hir as hir;
 use rustc_hir::def::Namespace::{self, *};
-use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
+use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, MacroKinds};
 use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
 use rustc_hir::{MissingLifetimeKind, PrimTy};
 use rustc_middle::ty;
 use rustc_session::{Session, lint};
 use rustc_span::edit_distance::{edit_distance, find_best_match_for_name};
 use rustc_span::edition::Edition;
-use rustc_span::hygiene::MacroKind;
 use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
 use thin_vec::ThinVec;
 use tracing::debug;
@@ -1850,12 +1849,12 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
 
         match (res, source) {
             (
-                Res::Def(DefKind::Macro(MacroKind::Bang), def_id),
+                Res::Def(DefKind::Macro(kinds), def_id),
                 PathSource::Expr(Some(Expr {
                     kind: ExprKind::Index(..) | ExprKind::Call(..), ..
                 }))
                 | PathSource::Struct(_),
-            ) => {
+            ) if kinds.contains(MacroKinds::BANG) => {
                 // Don't suggest macro if it's unstable.
                 let suggestable = def_id.is_local()
                     || self.r.tcx.lookup_stability(def_id).is_none_or(|s| s.is_stable());
@@ -1880,7 +1879,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                     err.note("if you want the `try` keyword, you need Rust 2018 or later");
                 }
             }
-            (Res::Def(DefKind::Macro(MacroKind::Bang), _), _) => {
+            (Res::Def(DefKind::Macro(kinds), _), _) if kinds.contains(MacroKinds::BANG) => {
                 err.span_label(span, fallback_label.to_string());
             }
             (Res::Def(DefKind::TyAlias, def_id), PathSource::Trait(_)) => {
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index b43f71913d9..797f4f619e3 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -53,7 +53,8 @@ use rustc_feature::BUILTIN_ATTRIBUTES;
 use rustc_hir::attrs::StrippedCfgItem;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{
-    self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS,
+    self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, MacroKinds, NonMacroAttrKind, PartialRes,
+    PerNS,
 };
 use rustc_hir::def_id::{CRATE_DEF_ID, CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalDefIdMap};
 use rustc_hir::definitions::DisambiguatorState;
@@ -969,8 +970,8 @@ impl<'ra> NameBindingData<'ra> {
         matches!(self.res(), Res::Def(DefKind::AssocConst | DefKind::AssocFn | DefKind::AssocTy, _))
     }
 
-    fn macro_kind(&self) -> Option<MacroKind> {
-        self.res().macro_kind()
+    fn macro_kinds(&self) -> Option<MacroKinds> {
+        self.res().macro_kinds()
     }
 
     // Suppose that we resolved macro invocation with `invoc_parent_expansion` to binding `binding`
@@ -1030,14 +1031,13 @@ struct DeriveData {
 
 struct MacroData {
     ext: Arc<SyntaxExtension>,
-    attr_ext: Option<Arc<SyntaxExtension>>,
     nrules: usize,
     macro_rules: bool,
 }
 
 impl MacroData {
     fn new(ext: Arc<SyntaxExtension>) -> MacroData {
-        MacroData { ext, attr_ext: None, nrules: 0, macro_rules: false }
+        MacroData { ext, nrules: 0, macro_rules: false }
     }
 }
 
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 9173d0d3ea5..9f25635f1fd 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -1,7 +1,6 @@
 //! A bunch of methods and structures more or less related to resolving macros and
 //! interface provided by `Resolver` to macro expander.
 
-use std::any::Any;
 use std::cell::Cell;
 use std::mem;
 use std::sync::Arc;
@@ -13,13 +12,13 @@ use rustc_expand::base::{
     Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension,
     SyntaxExtensionKind,
 };
+use rustc_expand::compile_declarative_macro;
 use rustc_expand::expand::{
     AstFragment, AstFragmentKind, Invocation, InvocationKind, SupportsMacroExpansion,
 };
-use rustc_expand::{MacroRulesMacroExpander, compile_declarative_macro};
 use rustc_hir::StabilityLevel;
 use rustc_hir::attrs::{CfgEntry, StrippedCfgItem};
-use rustc_hir::def::{self, DefKind, Namespace, NonMacroAttrKind};
+use rustc_hir::def::{self, DefKind, MacroKinds, Namespace, NonMacroAttrKind};
 use rustc_hir::def_id::{CrateNum, DefId, LocalDefId};
 use rustc_middle::middle::stability;
 use rustc_middle::ty::{RegisteredTools, TyCtxt};
@@ -86,22 +85,19 @@ pub(crate) type MacroRulesScopeRef<'ra> = &'ra Cell<MacroRulesScope<'ra>>;
 /// one for attribute-like macros (attributes, derives).
 /// We ignore resolutions from one sub-namespace when searching names in scope for another.
 pub(crate) fn sub_namespace_match(
-    candidate: Option<MacroKind>,
+    candidate: Option<MacroKinds>,
     requirement: Option<MacroKind>,
 ) -> bool {
-    #[derive(PartialEq)]
-    enum SubNS {
-        Bang,
-        AttrLike,
-    }
-    let sub_ns = |kind| match kind {
-        MacroKind::Bang => SubNS::Bang,
-        MacroKind::Attr | MacroKind::Derive => SubNS::AttrLike,
-    };
-    let candidate = candidate.map(sub_ns);
-    let requirement = requirement.map(sub_ns);
     // "No specific sub-namespace" means "matches anything" for both requirements and candidates.
-    candidate.is_none() || requirement.is_none() || candidate == requirement
+    let (Some(candidate), Some(requirement)) = (candidate, requirement) else {
+        return true;
+    };
+    match requirement {
+        MacroKind::Bang => candidate.contains(MacroKinds::BANG),
+        MacroKind::Attr | MacroKind::Derive => {
+            candidate.intersects(MacroKinds::ATTR | MacroKinds::DERIVE)
+        }
+    }
 }
 
 // We don't want to format a path using pretty-printing,
@@ -323,6 +319,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
                 parent_scope.expansion,
                 span,
                 fast_print_path(path),
+                kind,
                 def_id,
                 def_id.map(|def_id| self.macro_def_scope(def_id).nearest_parent_mod()),
             ),
@@ -356,11 +353,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
             }
             let def_id = self.local_def_id(node_id);
             let m = &self.local_macro_map[&def_id];
-            let SyntaxExtensionKind::LegacyBang(ref ext) = m.ext.kind else {
-                continue;
-            };
-            let ext: &dyn Any = ext.as_ref();
-            let Some(m) = ext.downcast_ref::<MacroRulesMacroExpander>() else {
+            let SyntaxExtensionKind::MacroRules(ref m) = m.ext.kind else {
                 continue;
             };
             for arm_i in unused_arms.iter() {
@@ -633,7 +626,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
 
         self.check_stability_and_deprecation(&ext, path, node_id);
 
-        let unexpected_res = if ext.macro_kind() != kind {
+        let unexpected_res = if !ext.macro_kinds().contains(kind.into()) {
             Some((kind.article(), kind.descr_expected()))
         } else if matches!(res, Res::Def(..)) {
             match supports_macro_expansion {
@@ -665,7 +658,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             // Suggest moving the macro out of the derive() if the macro isn't Derive
             if !path.span.from_expansion()
                 && kind == MacroKind::Derive
-                && ext.macro_kind() != MacroKind::Derive
+                && !ext.macro_kinds().contains(MacroKinds::DERIVE)
+                && ext.macro_kinds().contains(MacroKinds::ATTR)
             {
                 err.remove_surrounding_derive = Some(RemoveSurroundingDerive { span: path.span });
                 err.add_as_non_derive = Some(AddAsNonDerive { macro_path: &path_str });
@@ -842,10 +836,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 }
                 _ => None,
             },
-            None => self.get_macro(res).map(|macro_data| match kind {
-                Some(MacroKind::Attr) if let Some(ref ext) = macro_data.attr_ext => Arc::clone(ext),
-                _ => Arc::clone(&macro_data.ext),
-            }),
+            None => self.get_macro(res).map(|macro_data| Arc::clone(&macro_data.ext)),
         };
         Ok((ext, res))
     }
@@ -1114,7 +1105,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             && let Some(binding) = binding
             // This is a `macro_rules` itself, not some import.
             && let NameBindingKind::Res(res) = binding.kind
-            && let Res::Def(DefKind::Macro(MacroKind::Bang), def_id) = res
+            && let Res::Def(DefKind::Macro(kinds), def_id) = res
+            && kinds.contains(MacroKinds::BANG)
             // And the `macro_rules` is defined inside the attribute's module,
             // so it cannot be in scope unless imported.
             && self.tcx.is_descendant_of(def_id, mod_def_id.to_def_id())
@@ -1161,8 +1153,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         // Reserve some names that are not quite covered by the general check
         // performed on `Resolver::builtin_attrs`.
         if ident.name == sym::cfg || ident.name == sym::cfg_attr {
-            let macro_kind = self.get_macro(res).map(|macro_data| macro_data.ext.macro_kind());
-            if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) {
+            let macro_kinds = self.get_macro(res).map(|macro_data| macro_data.ext.macro_kinds());
+            if macro_kinds.is_some() && sub_namespace_match(macro_kinds, Some(MacroKind::Attr)) {
                 self.dcx()
                     .emit_err(errors::NameReservedInAttributeNamespace { span: ident.span, ident });
             }
@@ -1181,7 +1173,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         node_id: NodeId,
         edition: Edition,
     ) -> MacroData {
-        let (mut ext, mut attr_ext, mut nrules) = compile_declarative_macro(
+        let (mut ext, mut nrules) = compile_declarative_macro(
             self.tcx.sess,
             self.tcx.features(),
             macro_def,
@@ -1198,14 +1190,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
                 // The macro is a built-in, replace its expander function
                 // while still taking everything else from the source code.
                 ext.kind = builtin_ext_kind.clone();
-                attr_ext = None;
                 nrules = 0;
             } else {
                 self.dcx().emit_err(errors::CannotFindBuiltinMacroWithName { span, ident });
             }
         }
 
-        MacroData { ext: Arc::new(ext), attr_ext, nrules, macro_rules: macro_def.macro_rules }
+        MacroData { ext: Arc::new(ext), nrules, macro_rules: macro_def.macro_rules }
     }
 
     fn path_accessible(
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 7c18fd89098..0e112edc733 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -2165,6 +2165,8 @@ options! {
         "hash algorithm of source files used to check freshness in cargo (`blake3` or `sha256`)"),
     codegen_backend: Option<String> = (None, parse_opt_string, [TRACKED],
         "the backend to use"),
+    codegen_source_order: bool = (false, parse_bool, [UNTRACKED],
+        "emit mono items in the order of spans in source files (default: no)"),
     contract_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "emit runtime checks for contract pre- and post-conditions (default: no)"),
     coverage_options: CoverageOptions = (CoverageOptions::default(), parse_coverage_options, [TRACKED],
diff --git a/compiler/rustc_symbol_mangling/src/export.rs b/compiler/rustc_symbol_mangling/src/export.rs
index 956c996326b..76ac82cf95a 100644
--- a/compiler/rustc_symbol_mangling/src/export.rs
+++ b/compiler/rustc_symbol_mangling/src/export.rs
@@ -21,7 +21,7 @@ macro_rules! default_hash_impl {
     };
 }
 
-default_hash_impl! { i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, }
+default_hash_impl! { u8, u64, usize, }
 
 impl<'tcx> AbiHashStable<'tcx> for bool {
     #[inline]
@@ -37,13 +37,6 @@ impl<'tcx> AbiHashStable<'tcx> for str {
     }
 }
 
-impl<'tcx> AbiHashStable<'tcx> for String {
-    #[inline]
-    fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
-        self[..].abi_hash(tcx, hasher);
-    }
-}
-
 impl<'tcx> AbiHashStable<'tcx> for Symbol {
     #[inline]
     fn abi_hash(&self, tcx: TyCtxt<'tcx>, hasher: &mut StableHasher) {
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index a7f64085bd9..025fa299826 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -58,7 +58,7 @@ pub(super) fn mangle<'tcx>(
 
     let hash = get_symbol_hash(tcx, instance, instance_ty, instantiating_crate);
 
-    let mut p = SymbolPrinter { tcx, path: SymbolPath::new(), keep_within_component: false };
+    let mut p = LegacySymbolMangler { tcx, path: SymbolPath::new(), keep_within_component: false };
     p.print_def_path(
         def_id,
         if let ty::InstanceKind::DropGlue(_, _)
@@ -213,13 +213,13 @@ impl SymbolPath {
     }
 }
 
-struct SymbolPrinter<'tcx> {
+struct LegacySymbolMangler<'tcx> {
     tcx: TyCtxt<'tcx>,
     path: SymbolPath,
 
     // When `true`, `finalize_pending_component` isn't used.
-    // This is needed when recursing into `path_qualified`,
-    // or `path_generic_args`, as any nested paths are
+    // This is needed when recursing into `print_path_with_qualified`,
+    // or `print_path_with_generic_args`, as any nested paths are
     // logically within one component.
     keep_within_component: bool,
 }
@@ -228,7 +228,7 @@ struct SymbolPrinter<'tcx> {
 // `PrettyPrinter` aka pretty printing of e.g. types in paths,
 // symbol names should have their own printing machinery.
 
-impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
+impl<'tcx> Printer<'tcx> for LegacySymbolMangler<'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
@@ -305,16 +305,17 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
         Ok(())
     }
 
-    fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
+    fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
         self.write_str(self.tcx.crate_name(cnum).as_str())?;
         Ok(())
     }
-    fn path_qualified(
+
+    fn print_path_with_qualified(
         &mut self,
         self_ty: Ty<'tcx>,
         trait_ref: Option<ty::TraitRef<'tcx>>,
     ) -> Result<(), PrintError> {
-        // Similar to `pretty_path_qualified`, but for the other
+        // Similar to `pretty_print_path_with_qualified`, but for the other
         // types that are printed as paths (see `print_type` above).
         match self_ty.kind() {
             ty::FnDef(..)
@@ -327,17 +328,17 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
                 self.print_type(self_ty)
             }
 
-            _ => self.pretty_path_qualified(self_ty, trait_ref),
+            _ => self.pretty_print_path_with_qualified(self_ty, trait_ref),
         }
     }
 
-    fn path_append_impl(
+    fn print_path_with_impl(
         &mut self,
         print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
         self_ty: Ty<'tcx>,
         trait_ref: Option<ty::TraitRef<'tcx>>,
     ) -> Result<(), PrintError> {
-        self.pretty_path_append_impl(
+        self.pretty_print_path_with_impl(
             |cx| {
                 print_prefix(cx)?;
 
@@ -354,7 +355,8 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
             trait_ref,
         )
     }
-    fn path_append(
+
+    fn print_path_with_simple(
         &mut self,
         print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
         disambiguated_data: &DisambiguatedDefPathData,
@@ -377,7 +379,8 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
 
         Ok(())
     }
-    fn path_generic_args(
+
+    fn print_path_with_generic_args(
         &mut self,
         print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
         args: &[GenericArg<'tcx>],
@@ -455,7 +458,7 @@ impl<'tcx> Printer<'tcx> for SymbolPrinter<'tcx> {
     }
 }
 
-impl<'tcx> PrettyPrinter<'tcx> for SymbolPrinter<'tcx> {
+impl<'tcx> PrettyPrinter<'tcx> for LegacySymbolMangler<'tcx> {
     fn should_print_region(&self, _region: ty::Region<'_>) -> bool {
         false
     }
@@ -491,7 +494,7 @@ impl<'tcx> PrettyPrinter<'tcx> for SymbolPrinter<'tcx> {
     }
 }
 
-impl fmt::Write for SymbolPrinter<'_> {
+impl fmt::Write for LegacySymbolMangler<'_> {
     fn write_str(&mut self, s: &str) -> fmt::Result {
         // Name sanitation. LLVM will happily accept identifiers with weird names, but
         // gas doesn't!
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index 6bcb7f6e093..f3c96f64190 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -218,32 +218,33 @@ fn compute_symbol_name<'tcx>(
         }
     }
 
-    // Foreign items by default use no mangling for their symbol name. There's a
-    // few exceptions to this rule though:
-    //
-    // * This can be overridden with the `#[link_name]` attribute
-    //
-    // * On the wasm32 targets there is a bug (or feature) in LLD [1] where the
-    //   same-named symbol when imported from different wasm modules will get
-    //   hooked up incorrectly. As a result foreign symbols, on the wasm target,
-    //   with a wasm import module, get mangled. Additionally our codegen will
-    //   deduplicate symbols based purely on the symbol name, but for wasm this
-    //   isn't quite right because the same-named symbol on wasm can come from
-    //   different modules. For these reasons if `#[link(wasm_import_module)]`
-    //   is present we mangle everything on wasm because the demangled form will
-    //   show up in the `wasm-import-name` custom attribute in LLVM IR.
-    //
-    // * `#[rustc_std_internal_symbol]` mangles the symbol name in a special way
-    //   both for exports and imports through foreign items. This is handled above.
-    // [1]: https://bugs.llvm.org/show_bug.cgi?id=44316
-    if tcx.is_foreign_item(def_id)
-        && (!tcx.sess.target.is_like_wasm
-            || !tcx.wasm_import_module_map(def_id.krate).contains_key(&def_id))
+    let wasm_import_module_exception_force_mangling = {
+        // * On the wasm32 targets there is a bug (or feature) in LLD [1] where the
+        //   same-named symbol when imported from different wasm modules will get
+        //   hooked up incorrectly. As a result foreign symbols, on the wasm target,
+        //   with a wasm import module, get mangled. Additionally our codegen will
+        //   deduplicate symbols based purely on the symbol name, but for wasm this
+        //   isn't quite right because the same-named symbol on wasm can come from
+        //   different modules. For these reasons if `#[link(wasm_import_module)]`
+        //   is present we mangle everything on wasm because the demangled form will
+        //   show up in the `wasm-import-name` custom attribute in LLVM IR.
+        //
+        // [1]: https://bugs.llvm.org/show_bug.cgi?id=44316
+        //
+        // So, on wasm if a foreign item loses its `#[no_mangle]`, it might *still*
+        // be mangled if we're forced to. Note: I don't like this.
+        // These kinds of exceptions should be added during the `codegen_attrs` query.
+        // However, we don't have the wasm import module map there yet.
+        tcx.is_foreign_item(def_id)
+            && tcx.sess.target.is_like_wasm
+            && tcx.wasm_import_module_map(LOCAL_CRATE).contains_key(&def_id.into())
+    };
+
+    if let Some(name) = attrs.link_name
+        && !wasm_import_module_exception_force_mangling
     {
-        if let Some(name) = attrs.link_name {
-            return name.to_string();
-        }
-        return tcx.item_name(def_id).to_string();
+        // Use provided name
+        return name.to_string();
     }
 
     if let Some(name) = attrs.export_name {
@@ -251,7 +252,9 @@ fn compute_symbol_name<'tcx>(
         return name.to_string();
     }
 
-    if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) {
+    if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE)
+        && !wasm_import_module_exception_force_mangling
+    {
         // Don't mangle
         return tcx.item_name(def_id).to_string();
     }
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index c2458ae814b..0cbd48ba08c 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -33,7 +33,7 @@ pub(super) fn mangle<'tcx>(
     let args = tcx.normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), instance.args);
 
     let prefix = "_R";
-    let mut p: SymbolMangler<'_> = SymbolMangler {
+    let mut p: V0SymbolMangler<'_> = V0SymbolMangler {
         tcx,
         start_offset: prefix.len(),
         is_exportable,
@@ -88,7 +88,7 @@ pub fn mangle_internal_symbol<'tcx>(tcx: TyCtxt<'tcx>, item_name: &str) -> Strin
     }
 
     let prefix = "_R";
-    let mut p: SymbolMangler<'_> = SymbolMangler {
+    let mut p: V0SymbolMangler<'_> = V0SymbolMangler {
         tcx,
         start_offset: prefix.len(),
         is_exportable: false,
@@ -131,7 +131,7 @@ pub(super) fn mangle_typeid_for_trait_ref<'tcx>(
     trait_ref: ty::ExistentialTraitRef<'tcx>,
 ) -> String {
     // FIXME(flip1995): See comment in `mangle_typeid_for_fnabi`.
-    let mut p = SymbolMangler {
+    let mut p = V0SymbolMangler {
         tcx,
         start_offset: 0,
         is_exportable: false,
@@ -159,7 +159,7 @@ struct BinderLevel {
     lifetime_depths: Range<u32>,
 }
 
-struct SymbolMangler<'tcx> {
+struct V0SymbolMangler<'tcx> {
     tcx: TyCtxt<'tcx>,
     binders: Vec<BinderLevel>,
     out: String,
@@ -173,7 +173,7 @@ struct SymbolMangler<'tcx> {
     consts: FxHashMap<ty::Const<'tcx>, usize>,
 }
 
-impl<'tcx> SymbolMangler<'tcx> {
+impl<'tcx> V0SymbolMangler<'tcx> {
     fn push(&mut self, s: &str) {
         self.out.push_str(s);
     }
@@ -272,7 +272,7 @@ impl<'tcx> SymbolMangler<'tcx> {
     }
 }
 
-impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
+impl<'tcx> Printer<'tcx> for V0SymbolMangler<'tcx> {
     fn tcx(&self) -> TyCtxt<'tcx> {
         self.tcx
     }
@@ -365,7 +365,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
         // Encode impl generic params if the generic parameters contain non-region parameters
         // and this isn't an inherent impl.
         if impl_trait_ref.is_some() && args.iter().any(|a| a.has_non_region_param()) {
-            self.path_generic_args(
+            self.print_path_with_generic_args(
                 |this| {
                     this.path_append_ns(
                         |p| p.print_def_path(parent_def_id, &[]),
@@ -786,7 +786,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
                             None => {
                                 self.push("S");
                                 for (field_def, field) in iter::zip(&variant_def.fields, fields) {
-                                    // HACK(eddyb) this mimics `path_append`,
+                                    // HACK(eddyb) this mimics `print_path_with_simple`,
                                     // instead of simply using `field_def.ident`,
                                     // just to be able to handle disambiguators.
                                     let disambiguated_field =
@@ -819,7 +819,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
         Ok(())
     }
 
-    fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
+    fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
         self.push("C");
         if !self.is_exportable {
             let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
@@ -830,7 +830,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
         Ok(())
     }
 
-    fn path_qualified(
+    fn print_path_with_qualified(
         &mut self,
         self_ty: Ty<'tcx>,
         trait_ref: Option<ty::TraitRef<'tcx>>,
@@ -843,7 +843,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
         self.print_def_path(trait_ref.def_id, trait_ref.args)
     }
 
-    fn path_append_impl(
+    fn print_path_with_impl(
         &mut self,
         _: impl FnOnce(&mut Self) -> Result<(), PrintError>,
         _: Ty<'tcx>,
@@ -853,7 +853,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
         unreachable!()
     }
 
-    fn path_append(
+    fn print_path_with_simple(
         &mut self,
         print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
         disambiguated_data: &DisambiguatedDefPathData,
@@ -873,7 +873,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
             DefPathData::SyntheticCoroutineBody => 's',
             DefPathData::NestedStatic => 'n',
 
-            // These should never show up as `path_append` arguments.
+            // These should never show up as `print_path_with_simple` arguments.
             DefPathData::CrateRoot
             | DefPathData::Use
             | DefPathData::GlobalAsm
@@ -896,7 +896,7 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> {
         )
     }
 
-    fn path_generic_args(
+    fn print_path_with_generic_args(
         &mut self,
         print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
         args: &[GenericArg<'tcx>],
diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs
index da9f96ce37d..ecc74264160 100644
--- a/compiler/rustc_target/src/spec/base/apple/mod.rs
+++ b/compiler/rustc_target/src/spec/base/apple/mod.rs
@@ -1,5 +1,4 @@
 use std::borrow::Cow;
-use std::env;
 use std::fmt::{Display, from_fn};
 use std::num::ParseIntError;
 use std::str::FromStr;
@@ -209,29 +208,10 @@ fn link_env_remove(os: &'static str) -> StaticCow<[StaticCow<str>]> {
     // that's only applicable to cross-OS compilation. Always leave anything for the
     // host OS alone though.
     if os == "macos" {
-        let mut env_remove = Vec::with_capacity(2);
-        // Remove the `SDKROOT` environment variable if it's clearly set for the wrong platform, which
-        // may occur when we're linking a custom build script while targeting iOS for example.
-        if let Ok(sdkroot) = env::var("SDKROOT") {
-            if sdkroot.contains("iPhoneOS.platform")
-                || sdkroot.contains("iPhoneSimulator.platform")
-                || sdkroot.contains("AppleTVOS.platform")
-                || sdkroot.contains("AppleTVSimulator.platform")
-                || sdkroot.contains("WatchOS.platform")
-                || sdkroot.contains("WatchSimulator.platform")
-                || sdkroot.contains("XROS.platform")
-                || sdkroot.contains("XRSimulator.platform")
-            {
-                env_remove.push("SDKROOT".into())
-            }
-        }
-        // Additionally, `IPHONEOS_DEPLOYMENT_TARGET` must not be set when using the Xcode linker at
+        // `IPHONEOS_DEPLOYMENT_TARGET` must not be set when using the Xcode linker at
         // "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld",
         // although this is apparently ignored when using the linker at "/usr/bin/ld".
-        env_remove.push("IPHONEOS_DEPLOYMENT_TARGET".into());
-        env_remove.push("TVOS_DEPLOYMENT_TARGET".into());
-        env_remove.push("XROS_DEPLOYMENT_TARGET".into());
-        env_remove.into()
+        cvs!["IPHONEOS_DEPLOYMENT_TARGET", "TVOS_DEPLOYMENT_TARGET", "XROS_DEPLOYMENT_TARGET"]
     } else {
         // Otherwise if cross-compiling for a different OS/SDK (including Mac Catalyst), remove any part
         // of the linking environment that's wrong and reversed.
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index b9fbff8db05..ee408c76006 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -2147,6 +2147,7 @@ supported_targets! {
 
     ("aarch64-unknown-none", aarch64_unknown_none),
     ("aarch64-unknown-none-softfloat", aarch64_unknown_none_softfloat),
+    ("aarch64_be-unknown-none-softfloat", aarch64_be_unknown_none_softfloat),
     ("aarch64-unknown-nuttx", aarch64_unknown_nuttx),
 
     ("x86_64-fortanix-unknown-sgx", x86_64_fortanix_unknown_sgx),
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_none_softfloat.rs
new file mode 100644
index 00000000000..7f918e85080
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/aarch64_be_unknown_none_softfloat.rs
@@ -0,0 +1,43 @@
+// Generic big-endian AArch64 target for bare-metal code - Floating point disabled
+//
+// Can be used in conjunction with the `target-feature` and
+// `target-cpu` compiler flags to opt-in more hardware-specific
+// features.
+//
+// For example, `-C target-cpu=cortex-a53`.
+use rustc_abi::Endian;
+
+use crate::spec::{
+    Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, SanitizerSet, StackProbeType, Target,
+    TargetMetadata, TargetOptions,
+};
+
+pub(crate) fn target() -> Target {
+    let opts = TargetOptions {
+        abi: "softfloat".into(),
+        linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
+        linker: Some("rust-lld".into()),
+        features: "+v8a,+strict-align,-neon,-fp-armv8".into(),
+        relocation_model: RelocModel::Static,
+        disable_redzone: true,
+        max_atomic_width: Some(128),
+        supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS,
+        stack_probes: StackProbeType::Inline,
+        panic_strategy: PanicStrategy::Abort,
+        endian: Endian::Big,
+        ..Default::default()
+    };
+    Target {
+        llvm_target: "aarch64_be-unknown-none".into(),
+        metadata: TargetMetadata {
+            description: Some("Bare ARM64 (big-endian), softfloat".into()),
+            tier: Some(3),
+            host_tools: Some(false),
+            std: Some(false),
+        },
+        pointer_width: 64,
+        data_layout: "E-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(),
+        arch: "aarch64".into(),
+        options: opts,
+    }
+}
diff --git a/compiler/rustc_target/src/spec/targets/avr_none.rs b/compiler/rustc_target/src/spec/targets/avr_none.rs
index 07ed2a37803..ad056d02326 100644
--- a/compiler/rustc_target/src/spec/targets/avr_none.rs
+++ b/compiler/rustc_target/src/spec/targets/avr_none.rs
@@ -9,7 +9,7 @@ pub(crate) fn target() -> Target {
             host_tools: None,
             std: None,
         },
-        data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".into(),
+        data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8:16-a:8".into(),
         llvm_target: "avr-unknown-unknown".into(),
         pointer_width: 16,
         options: TargetOptions {
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 297d9ed84c5..4b450804f3b 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -248,6 +248,10 @@ static AARCH64_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     ("mte", Stable, &[]),
     // FEAT_AdvSimd & FEAT_FP
     ("neon", Stable, &[]),
+    // Backend option to turn atomic operations into an intrinsic call when `lse` is not known to be
+    // available, so the intrinsic can do runtime LSE feature detection rather than unconditionally
+    // using slower non-LSE operations. Unstable since it doesn't need to user-togglable.
+    ("outline-atomics", Unstable(sym::aarch64_unstable_target_feature), &[]),
     // FEAT_PAUTH (address authentication)
     ("paca", Stable, &[]),
     // FEAT_PAUTH (generic authentication)
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index 8551780bcd5..20e425bfad1 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -224,12 +224,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         use ty::GenericArg;
         use ty::print::Printer;
 
-        struct AbsolutePathPrinter<'tcx> {
+        struct ConflictingPathPrinter<'tcx> {
             tcx: TyCtxt<'tcx>,
             segments: Vec<Symbol>,
         }
 
-        impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
+        impl<'tcx> Printer<'tcx> for ConflictingPathPrinter<'tcx> {
             fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
                 self.tcx
             }
@@ -253,12 +253,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 unreachable!(); // because `path_generic_args` ignores the `GenericArgs`
             }
 
-            fn path_crate(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
+            fn print_crate_name(&mut self, cnum: CrateNum) -> Result<(), PrintError> {
                 self.segments = vec![self.tcx.crate_name(cnum)];
                 Ok(())
             }
 
-            fn path_qualified(
+            fn print_path_with_qualified(
                 &mut self,
                 _self_ty: Ty<'tcx>,
                 _trait_ref: Option<ty::TraitRef<'tcx>>,
@@ -266,7 +266,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 Err(fmt::Error)
             }
 
-            fn path_append_impl(
+            fn print_path_with_impl(
                 &mut self,
                 _print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
                 _self_ty: Ty<'tcx>,
@@ -275,7 +275,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 Err(fmt::Error)
             }
 
-            fn path_append(
+            fn print_path_with_simple(
                 &mut self,
                 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
                 disambiguated_data: &DisambiguatedDefPathData,
@@ -285,7 +285,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 Ok(())
             }
 
-            fn path_generic_args(
+            fn print_path_with_generic_args(
                 &mut self,
                 print_prefix: impl FnOnce(&mut Self) -> Result<(), PrintError>,
                 _args: &[GenericArg<'tcx>],
@@ -300,28 +300,27 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             // let _ = [{struct Foo; Foo}, {struct Foo; Foo}];
             if did1.krate != did2.krate {
                 let abs_path = |def_id| {
-                    let mut p = AbsolutePathPrinter { tcx: self.tcx, segments: vec![] };
+                    let mut p = ConflictingPathPrinter { tcx: self.tcx, segments: vec![] };
                     p.print_def_path(def_id, &[]).map(|_| p.segments)
                 };
 
-                // We compare strings because DefPath can be different
-                // for imported and non-imported crates
+                // We compare strings because DefPath can be different for imported and
+                // non-imported crates.
                 let expected_str = self.tcx.def_path_str(did1);
                 let found_str = self.tcx.def_path_str(did2);
                 let Ok(expected_abs) = abs_path(did1) else { return false };
                 let Ok(found_abs) = abs_path(did2) else { return false };
-                let same_path = || -> Result<_, PrintError> {
-                    Ok(expected_str == found_str || expected_abs == found_abs)
-                };
-                // We want to use as unique a type path as possible. If both types are "locally
-                // known" by the same name, we use the "absolute path" which uses the original
-                // crate name instead.
-                let (expected, found) = if expected_str == found_str {
-                    (join_path_syms(&expected_abs), join_path_syms(&found_abs))
-                } else {
-                    (expected_str.clone(), found_str.clone())
-                };
-                if same_path().unwrap_or(false) {
+                let same_path = expected_str == found_str || expected_abs == found_abs;
+                if same_path {
+                    // We want to use as unique a type path as possible. If both types are "locally
+                    // known" by the same name, we use the "absolute path" which uses the original
+                    // crate name instead.
+                    let (expected, found) = if expected_str == found_str {
+                        (join_path_syms(&expected_abs), join_path_syms(&found_abs))
+                    } else {
+                        (expected_str.clone(), found_str.clone())
+                    };
+
                     // We've displayed "expected `a::b`, found `a::b`". We add context to
                     // differentiate the different cases where that might happen.
                     let expected_crate_name = self.tcx.crate_name(did1.krate);
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
index 8f0f6d0bf26..f31a85ec07a 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
@@ -946,7 +946,7 @@ fn foo(&self) -> Self::T { String::new() }
 
     pub fn format_generic_args(&self, args: &[ty::GenericArg<'tcx>]) -> String {
         FmtPrinter::print_string(self.tcx, hir::def::Namespace::TypeNS, |p| {
-            p.path_generic_args(|_| Ok(()), args)
+            p.print_path_with_generic_args(|_| Ok(()), args)
         })
         .expect("could not write to `String`.")
     }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index ae72178c052..bc8c8a44405 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -3471,8 +3471,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         ..
                     })) => {
                         let mut spans = Vec::with_capacity(2);
-                        if let Some(trait_ref) = of_trait {
-                            spans.push(trait_ref.path.span);
+                        if let Some(of_trait) = of_trait {
+                            spans.push(of_trait.trait_ref.path.span);
                         }
                         spans.push(self_ty.span);
                         let mut spans: MultiSpan = spans.into();
@@ -3480,7 +3480,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             self_ty.span.ctxt().outer_expn_data().kind,
                             ExpnKind::Macro(MacroKind::Derive, _)
                         ) || matches!(
-                            of_trait.as_ref().map(|t| t.path.span.ctxt().outer_expn_data().kind),
+                            of_trait.map(|t| t.trait_ref.path.span.ctxt().outer_expn_data().kind),
                             Some(ExpnKind::Macro(MacroKind::Derive, _))
                         ) {
                             spans.push_span_label(
@@ -3592,7 +3592,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         ..
                     })) => {
                         let mut spans = vec![self_ty.span];
-                        spans.extend(of_trait.as_ref().map(|t| t.path.span));
+                        spans.extend(of_trait.map(|t| t.trait_ref.path.span));
                         let mut spans: MultiSpan = spans.into();
                         spans.push_span_label(data.span, "unsatisfied trait bound introduced here");
                         err.span_note(spans, msg);
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index b1b331d1b61..de404532899 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -319,39 +319,65 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
         }
 
         ty::Coroutine(def_id, args) => {
-            // rust-lang/rust#49918: types can be constructed, stored
-            // in the interior, and sit idle when coroutine yields
-            // (and is subsequently dropped).
+            // rust-lang/rust#49918: Locals can be stored across await points in the coroutine,
+            // called interior/witness types. Since we do not compute these witnesses until after
+            // building MIR, we consider all coroutines to unconditionally require a drop during
+            // MIR building. However, considering the coroutine to unconditionally require a drop
+            // here may unnecessarily require its upvars' regions to be live when they don't need
+            // to be, leading to borrowck errors: <https://github.com/rust-lang/rust/issues/116242>.
             //
-            // It would be nice to descend into interior of a
-            // coroutine to determine what effects dropping it might
-            // have (by looking at any drop effects associated with
-            // its interior).
+            // Here, we implement a more precise approximation for the coroutine's dtorck constraint
+            // by considering whether any of the interior types needs drop. Note that this is still
+            // an approximation because the coroutine interior has its regions erased, so we must add
+            // *all* of the upvars to live types set if we find that *any* interior type needs drop.
+            // This is because any of the regions captured in the upvars may be stored in the interior,
+            // which then has its regions replaced by a binder (conceptually erasing the regions),
+            // so there's no way to enforce that the precise region in the interior type is live
+            // since we've lost that information by this point.
             //
-            // However, the interior's representation uses things like
-            // CoroutineWitness that explicitly assume they are not
-            // traversed in such a manner. So instead, we will
-            // simplify things for now by treating all coroutines as
-            // if they were like trait objects, where its upvars must
-            // all be alive for the coroutine's (potential)
-            // destructor.
+            // Note also that this check requires that the coroutine's upvars are use-live, since
+            // a region from a type that does not have a destructor that was captured in an upvar
+            // may flow into an interior type with a destructor. This is stronger than requiring
+            // the upvars are drop-live.
             //
-            // In particular, skipping over `_interior` is safe
-            // because any side-effects from dropping `_interior` can
-            // only take place through references with lifetimes
-            // derived from lifetimes attached to the upvars and resume
-            // argument, and we *do* incorporate those here.
+            // For example, if we capture two upvar references `&'1 (), &'2 ()` and have some type
+            // in the interior, `for<'r> { NeedsDrop<'r> }`, we have no way to tell whether the
+            // region `'r` came from the `'1` or `'2` region, so we require both are live. This
+            // could even be unnecessary if `'r` was actually a `'static` region or some region
+            // local to the coroutine! That's why it's an approximation.
             let args = args.as_coroutine();
 
-            // While we conservatively assume that all coroutines require drop
-            // to avoid query cycles during MIR building, we can check the actual
-            // witness during borrowck to avoid unnecessary liveness constraints.
+            // Note that we don't care about whether the resume type has any drops since this is
+            // redundant; there is no storage for the resume type, so if it is actually stored
+            // in the interior, we'll already detect the need for a drop by checking the interior.
             let typing_env = tcx.erase_regions(typing_env);
-            if tcx.mir_coroutine_witnesses(def_id).is_some_and(|witness| {
+            let needs_drop = tcx.mir_coroutine_witnesses(def_id).is_some_and(|witness| {
                 witness.field_tys.iter().any(|field| field.ty.needs_drop(tcx, typing_env))
-            }) {
+            });
+            if needs_drop {
+                // Pushing types directly to `constraints.outlives` is equivalent
+                // to requiring them to be use-live, since if we were instead to
+                // recurse on them like we do below, we only end up collecting the
+                // types that are relevant for drop-liveness.
                 constraints.outlives.extend(args.upvar_tys().iter().map(ty::GenericArg::from));
                 constraints.outlives.push(args.resume_ty().into());
+            } else {
+                // Even if a witness type doesn't need a drop, we still require that
+                // the upvars are drop-live. This is only needed if we aren't already
+                // counting *all* of the upvars as use-live above, since use-liveness
+                // is a *stronger requirement* than drop-liveness. Recursing here
+                // unconditionally would just be collecting duplicated types for no
+                // reason.
+                for ty in args.upvar_tys() {
+                    dtorck_constraint_for_ty_inner(
+                        tcx,
+                        typing_env,
+                        span,
+                        depth + 1,
+                        ty,
+                        constraints,
+                    );
+                }
             }
         }
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 7ea1548f8f2..468c42abf48 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2333,10 +2333,23 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
 
             ty::Coroutine(def_id, args) => {
                 let ty = self.infcx.shallow_resolve(args.as_coroutine().tupled_upvars_ty());
+                let tcx = self.tcx();
                 let witness = Ty::new_coroutine_witness(
-                    self.tcx(),
+                    tcx,
                     def_id,
-                    self.tcx().mk_args(args.as_coroutine().parent_args()),
+                    ty::GenericArgs::for_item(tcx, def_id, |def, _| match def.kind {
+                        // HACK: Coroutine witnesse types are lifetime erased, so they
+                        // never reference any lifetime args from the coroutine. We erase
+                        // the regions here since we may get into situations where a
+                        // coroutine is recursively contained within itself, leading to
+                        // witness types that differ by region args. This means that
+                        // cycle detection in fulfillment will not kick in, which leads
+                        // to unnecessary overflows in async code. See the issue:
+                        // <https://github.com/rust-lang/rust/issues/145151>.
+                        ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(),
+                        ty::GenericParamDefKind::Type { .. }
+                        | ty::GenericParamDefKind::Const { .. } => args[def.index as usize],
+                    }),
                 );
                 ty::Binder::dummy(AutoImplConstituents {
                     types: [ty].into_iter().chain(iter::once(witness)).collect(),
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index 37cb64511c7..e9629e31482 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -174,10 +174,10 @@ fn associated_types_for_impl_traits_in_trait_or_impl<'tcx>(
             })
             .collect(),
         ItemKind::Impl(impl_) => {
-            let Some(trait_ref) = impl_.of_trait else {
+            let Some(of_trait) = impl_.of_trait else {
                 return Default::default();
             };
-            let Some(trait_def_id) = trait_ref.trait_def_id() else {
+            let Some(trait_def_id) = of_trait.trait_ref.trait_def_id() else {
                 return Default::default();
             };
             let in_trait_def = tcx.associated_types_for_impl_traits_in_trait_or_impl(trait_def_id);
diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs
index 6fa763f18ef..cdfb93c4e7d 100644
--- a/compiler/rustc_ty_utils/src/implied_bounds.rs
+++ b/compiler/rustc_ty_utils/src/implied_bounds.rs
@@ -172,10 +172,12 @@ fn impl_spans(tcx: TyCtxt<'_>, def_id: LocalDefId) -> impl Iterator<Item = Span>
         let trait_args = impl_
             .of_trait
             .into_iter()
-            .flat_map(|trait_ref| trait_ref.path.segments.last().unwrap().args().args)
+            .flat_map(|of_trait| of_trait.trait_ref.path.segments.last().unwrap().args().args)
             .map(|arg| arg.span());
-        let dummy_spans_for_default_args =
-            impl_.of_trait.into_iter().flat_map(|trait_ref| iter::repeat(trait_ref.path.span));
+        let dummy_spans_for_default_args = impl_
+            .of_trait
+            .into_iter()
+            .flat_map(|of_trait| iter::repeat(of_trait.trait_ref.path.span));
         iter::once(impl_.self_ty.span).chain(trait_args).chain(dummy_spans_for_default_args)
     } else {
         bug!("unexpected item for impl {def_id:?}: {item:?}")
diff --git a/compiler/rustc_ty_utils/src/sig_types.rs b/compiler/rustc_ty_utils/src/sig_types.rs
index dc6009116ac..d95660810e5 100644
--- a/compiler/rustc_ty_utils/src/sig_types.rs
+++ b/compiler/rustc_ty_utils/src/sig_types.rs
@@ -87,7 +87,7 @@ pub fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>(
         DefKind::InlineConst | DefKind::Closure | DefKind::SyntheticCoroutineBody => {}
         DefKind::Impl { of_trait } => {
             if of_trait {
-                let span = tcx.hir_node_by_def_id(item).expect_item().expect_impl().of_trait.unwrap().path.span;
+                let span = tcx.hir_node_by_def_id(item).expect_item().expect_impl().of_trait.unwrap().trait_ref.path.span;
                 let args = &tcx.impl_trait_ref(item).unwrap().instantiate_identity().args[1..];
                 try_visit!(visitor.visit(span, args));
             }
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 2e0b16d9227..b22c326b9f2 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -81,7 +81,11 @@ fn sizedness_constraint_for_ty<'tcx>(
 fn defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness {
     match tcx.hir_node_by_def_id(def_id) {
         hir::Node::Item(hir::Item {
-            kind: hir::ItemKind::Impl(hir::Impl { defaultness, of_trait: Some(_), .. }),
+            kind:
+                hir::ItemKind::Impl(hir::Impl {
+                    of_trait: Some(hir::TraitImplHeader { defaultness, .. }),
+                    ..
+                }),
             ..
         })
         | hir::Node::ImplItem(hir::ImplItem { defaultness, .. })
diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs
index 7433c215e6f..24094eeea8d 100644
--- a/compiler/rustc_type_ir/src/search_graph/mod.rs
+++ b/compiler/rustc_type_ir/src/search_graph/mod.rs
@@ -12,19 +12,19 @@
 //! The global cache has to be completely unobservable, while the per-cycle cache may impact
 //! behavior as long as the resulting behavior is still correct.
 use std::cmp::Ordering;
-use std::collections::BTreeMap;
 use std::collections::hash_map::Entry;
+use std::collections::{BTreeMap, btree_map};
 use std::fmt::Debug;
 use std::hash::Hash;
+use std::iter;
 use std::marker::PhantomData;
 
 use derive_where::derive_where;
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
+use rustc_type_ir::data_structures::HashMap;
 use tracing::{debug, instrument};
 
-use crate::data_structures::HashMap;
-
 mod stack;
 use stack::{Stack, StackDepth, StackEntry};
 mod global_cache;
@@ -137,6 +137,12 @@ pub enum PathKind {
     Unknown,
     /// A path with at least one coinductive step. Such cycles hold.
     Coinductive,
+    /// A path which is treated as ambiguous. Once a path has this path kind
+    /// any other segment does not change its kind.
+    ///
+    /// This is currently only used when fuzzing to support negative reasoning.
+    /// For more details, see #143054.
+    ForcedAmbiguity,
 }
 
 impl PathKind {
@@ -149,6 +155,9 @@ impl PathKind {
     /// to `max(self, rest)`.
     fn extend(self, rest: PathKind) -> PathKind {
         match (self, rest) {
+            (PathKind::ForcedAmbiguity, _) | (_, PathKind::ForcedAmbiguity) => {
+                PathKind::ForcedAmbiguity
+            }
             (PathKind::Coinductive, _) | (_, PathKind::Coinductive) => PathKind::Coinductive,
             (PathKind::Unknown, _) | (_, PathKind::Unknown) => PathKind::Unknown,
             (PathKind::Inductive, PathKind::Inductive) => PathKind::Inductive,
@@ -187,41 +196,6 @@ impl UsageKind {
     }
 }
 
-/// For each goal we track whether the paths from this goal
-/// to its cycle heads are coinductive.
-///
-/// This is a necessary condition to rebase provisional cache
-/// entries.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum AllPathsToHeadCoinductive {
-    Yes,
-    No,
-}
-impl From<PathKind> for AllPathsToHeadCoinductive {
-    fn from(path: PathKind) -> AllPathsToHeadCoinductive {
-        match path {
-            PathKind::Coinductive => AllPathsToHeadCoinductive::Yes,
-            _ => AllPathsToHeadCoinductive::No,
-        }
-    }
-}
-impl AllPathsToHeadCoinductive {
-    #[must_use]
-    fn merge(self, other: impl Into<Self>) -> Self {
-        match (self, other.into()) {
-            (AllPathsToHeadCoinductive::Yes, AllPathsToHeadCoinductive::Yes) => {
-                AllPathsToHeadCoinductive::Yes
-            }
-            (AllPathsToHeadCoinductive::No, _) | (_, AllPathsToHeadCoinductive::No) => {
-                AllPathsToHeadCoinductive::No
-            }
-        }
-    }
-    fn and_merge(&mut self, other: impl Into<Self>) {
-        *self = self.merge(other);
-    }
-}
-
 #[derive(Debug, Clone, Copy)]
 struct AvailableDepth(usize);
 impl AvailableDepth {
@@ -257,13 +231,19 @@ impl AvailableDepth {
     }
 }
 
+#[derive(Clone, Copy, Debug)]
+struct CycleHead {
+    paths_to_head: PathsToNested,
+    usage_kind: UsageKind,
+}
+
 /// All cycle heads a given goal depends on, ordered by their stack depth.
 ///
 /// We also track all paths from this goal to that head. This is necessary
 /// when rebasing provisional cache results.
-#[derive(Clone, Debug, PartialEq, Eq, Default)]
+#[derive(Clone, Debug, Default)]
 struct CycleHeads {
-    heads: BTreeMap<StackDepth, AllPathsToHeadCoinductive>,
+    heads: BTreeMap<StackDepth, CycleHead>,
 }
 
 impl CycleHeads {
@@ -283,62 +263,46 @@ impl CycleHeads {
         self.heads.first_key_value().map(|(k, _)| *k)
     }
 
-    fn remove_highest_cycle_head(&mut self) {
+    fn remove_highest_cycle_head(&mut self) -> CycleHead {
         let last = self.heads.pop_last();
-        debug_assert_ne!(last, None);
+        last.unwrap().1
     }
 
     fn insert(
         &mut self,
-        head: StackDepth,
-        path_from_entry: impl Into<AllPathsToHeadCoinductive> + Copy,
+        head_index: StackDepth,
+        path_from_entry: impl Into<PathsToNested> + Copy,
+        usage_kind: UsageKind,
     ) {
-        self.heads.entry(head).or_insert(path_from_entry.into()).and_merge(path_from_entry);
-    }
-
-    fn merge(&mut self, heads: &CycleHeads) {
-        for (&head, &path_from_entry) in heads.heads.iter() {
-            self.insert(head, path_from_entry);
-            debug_assert!(matches!(self.heads[&head], AllPathsToHeadCoinductive::Yes));
+        match self.heads.entry(head_index) {
+            btree_map::Entry::Vacant(entry) => {
+                entry.insert(CycleHead { paths_to_head: path_from_entry.into(), usage_kind });
+            }
+            btree_map::Entry::Occupied(entry) => {
+                let head = entry.into_mut();
+                head.paths_to_head |= path_from_entry.into();
+                head.usage_kind = head.usage_kind.merge(usage_kind);
+            }
         }
     }
 
-    fn iter(&self) -> impl Iterator<Item = (StackDepth, AllPathsToHeadCoinductive)> + '_ {
+    fn iter(&self) -> impl Iterator<Item = (StackDepth, CycleHead)> + '_ {
         self.heads.iter().map(|(k, v)| (*k, *v))
     }
-
-    /// Update the cycle heads of a goal at depth `this` given the cycle heads
-    /// of a nested goal. This merges the heads after filtering the parent goal
-    /// itself.
-    fn extend_from_child(&mut self, this: StackDepth, step_kind: PathKind, child: &CycleHeads) {
-        for (&head, &path_from_entry) in child.heads.iter() {
-            match head.cmp(&this) {
-                Ordering::Less => {}
-                Ordering::Equal => continue,
-                Ordering::Greater => unreachable!(),
-            }
-
-            let path_from_entry = match step_kind {
-                PathKind::Coinductive => AllPathsToHeadCoinductive::Yes,
-                PathKind::Unknown | PathKind::Inductive => path_from_entry,
-            };
-
-            self.insert(head, path_from_entry);
-        }
-    }
 }
 
 bitflags::bitflags! {
     /// Tracks how nested goals have been accessed. This is necessary to disable
     /// global cache entries if computing them would otherwise result in a cycle or
     /// access a provisional cache entry.
-    #[derive(Debug, Clone, Copy)]
+    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
     pub struct PathsToNested: u8 {
         /// The initial value when adding a goal to its own nested goals.
         const EMPTY                      = 1 << 0;
         const INDUCTIVE                  = 1 << 1;
         const UNKNOWN                    = 1 << 2;
         const COINDUCTIVE                = 1 << 3;
+        const FORCED_AMBIGUITY           = 1 << 4;
     }
 }
 impl From<PathKind> for PathsToNested {
@@ -347,6 +311,7 @@ impl From<PathKind> for PathsToNested {
             PathKind::Inductive => PathsToNested::INDUCTIVE,
             PathKind::Unknown => PathsToNested::UNKNOWN,
             PathKind::Coinductive => PathsToNested::COINDUCTIVE,
+            PathKind::ForcedAmbiguity => PathsToNested::FORCED_AMBIGUITY,
         }
     }
 }
@@ -379,10 +344,45 @@ impl PathsToNested {
                     self.insert(PathsToNested::COINDUCTIVE);
                 }
             }
+            PathKind::ForcedAmbiguity => {
+                if self.intersects(
+                    PathsToNested::EMPTY
+                        | PathsToNested::INDUCTIVE
+                        | PathsToNested::UNKNOWN
+                        | PathsToNested::COINDUCTIVE,
+                ) {
+                    self.remove(
+                        PathsToNested::EMPTY
+                            | PathsToNested::INDUCTIVE
+                            | PathsToNested::UNKNOWN
+                            | PathsToNested::COINDUCTIVE,
+                    );
+                    self.insert(PathsToNested::FORCED_AMBIGUITY);
+                }
+            }
         }
 
         self
     }
+
+    #[must_use]
+    fn extend_with_paths(self, path: PathsToNested) -> Self {
+        let mut new = PathsToNested::empty();
+        for p in path.iter_paths() {
+            new |= self.extend_with(p);
+        }
+        new
+    }
+
+    fn iter_paths(self) -> impl Iterator<Item = PathKind> {
+        let (PathKind::Inductive
+        | PathKind::Unknown
+        | PathKind::Coinductive
+        | PathKind::ForcedAmbiguity);
+        [PathKind::Inductive, PathKind::Unknown, PathKind::Coinductive, PathKind::ForcedAmbiguity]
+            .into_iter()
+            .filter(move |&p| self.contains(p.into()))
+    }
 }
 
 /// The nested goals of each stack entry and the path from the
@@ -494,9 +494,6 @@ impl<X: Cx> EvaluationResult<X> {
 
 pub struct SearchGraph<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> {
     root_depth: AvailableDepth,
-    /// The stack of goals currently being computed.
-    ///
-    /// An element is *deeper* in the stack if its index is *lower*.
     stack: Stack<X>,
     /// The provisional cache contains entries for already computed goals which
     /// still depend on goals higher-up in the stack. We don't move them to the
@@ -518,6 +515,7 @@ pub struct SearchGraph<D: Delegate<Cx = X>, X: Cx = <D as Delegate>::Cx> {
 /// cache entry.
 enum UpdateParentGoalCtxt<'a, X: Cx> {
     Ordinary(&'a NestedGoals<X>),
+    CycleOnStack(X::Input),
     ProvisionalCacheHit,
 }
 
@@ -539,21 +537,42 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
         stack: &mut Stack<X>,
         step_kind_from_parent: PathKind,
         required_depth_for_nested: usize,
-        heads: &CycleHeads,
+        heads: impl Iterator<Item = (StackDepth, CycleHead)>,
         encountered_overflow: bool,
         context: UpdateParentGoalCtxt<'_, X>,
     ) {
-        if let Some(parent_index) = stack.last_index() {
-            let parent = &mut stack[parent_index];
+        if let Some((parent_index, parent)) = stack.last_mut_with_index() {
             parent.required_depth = parent.required_depth.max(required_depth_for_nested + 1);
             parent.encountered_overflow |= encountered_overflow;
 
-            parent.heads.extend_from_child(parent_index, step_kind_from_parent, heads);
+            for (head_index, head) in heads {
+                match head_index.cmp(&parent_index) {
+                    Ordering::Less => parent.heads.insert(
+                        head_index,
+                        head.paths_to_head.extend_with(step_kind_from_parent),
+                        head.usage_kind,
+                    ),
+                    Ordering::Equal => {
+                        let usage_kind = parent
+                            .has_been_used
+                            .map_or(head.usage_kind, |prev| prev.merge(head.usage_kind));
+                        parent.has_been_used = Some(usage_kind);
+                    }
+                    Ordering::Greater => unreachable!(),
+                }
+            }
             let parent_depends_on_cycle = match context {
                 UpdateParentGoalCtxt::Ordinary(nested_goals) => {
                     parent.nested_goals.extend_from_child(step_kind_from_parent, nested_goals);
                     !nested_goals.is_empty()
                 }
+                UpdateParentGoalCtxt::CycleOnStack(head) => {
+                    // We lookup provisional cache entries before detecting cycles.
+                    // We therefore can't use a global cache entry if it contains a cycle
+                    // whose head is in the provisional cache.
+                    parent.nested_goals.insert(head, step_kind_from_parent.into());
+                    true
+                }
                 UpdateParentGoalCtxt::ProvisionalCacheHit => true,
             };
             // Once we've got goals which encountered overflow or a cycle,
@@ -681,7 +700,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
             &mut self.stack,
             step_kind_from_parent,
             evaluation_result.required_depth,
-            &evaluation_result.heads,
+            evaluation_result.heads.iter(),
             evaluation_result.encountered_overflow,
             UpdateParentGoalCtxt::Ordinary(&evaluation_result.nested_goals),
         );
@@ -693,7 +712,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
             if let Some((_scope, expected)) = validate_cache {
                 // Do not try to move a goal into the cache again if we're testing
                 // the global cache.
-                assert_eq!(evaluation_result.result, expected, "input={input:?}");
+                assert_eq!(expected, evaluation_result.result, "input={input:?}");
             } else if D::inspect_is_noop(inspect) {
                 self.insert_global_cache(cx, input, evaluation_result, dep_node)
             }
@@ -763,14 +782,11 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
     /// provisional cache entry is still applicable. We need to keep the cache entries to
     /// prevent hangs.
     ///
-    /// What we therefore do is check whether the cycle kind of all cycles the goal of a
-    /// provisional cache entry is involved in would stay the same when computing the
-    /// goal without its cycle head on the stack. For more details, see the relevant
+    /// This can be thought of as pretending to reevaluate the popped head as nested goals
+    /// of this provisional result. For this to be correct, all cycles encountered while
+    /// we'd reevaluate the cycle head as a nested goal must keep the same cycle kind.
     /// [rustc-dev-guide chapter](https://rustc-dev-guide.rust-lang.org/solve/caching.html).
     ///
-    /// This can be thought of rotating the sub-tree of this provisional result and changing
-    /// its entry point while making sure that all paths through this sub-tree stay the same.
-    ///
     /// In case the popped cycle head failed to reach a fixpoint anything which depends on
     /// its provisional result is invalid. Actually discarding provisional cache entries in
     /// this case would cause hangs, so we instead change the result of dependant provisional
@@ -782,7 +798,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
         stack_entry: &StackEntry<X>,
         mut mutate_result: impl FnMut(X::Input, X::Result) -> X::Result,
     ) {
-        let head = self.stack.next_index();
+        let popped_head_index = self.stack.next_index();
         #[allow(rustc::potential_query_instability)]
         self.provisional_cache.retain(|&input, entries| {
             entries.retain_mut(|entry| {
@@ -792,30 +808,49 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
                     path_from_head,
                     result,
                 } = entry;
-                if heads.highest_cycle_head() == head {
+                let popped_head = if heads.highest_cycle_head() == popped_head_index {
                     heads.remove_highest_cycle_head()
                 } else {
                     return true;
-                }
+                };
 
-                // We only try to rebase if all paths from the cache entry
-                // to its heads are coinductive. In this case these cycle
-                // kinds won't change, no matter the goals between these
-                // heads and the provisional cache entry.
-                if heads.iter().any(|(_, p)| matches!(p, AllPathsToHeadCoinductive::No)) {
-                    return false;
-                }
+                // We're rebasing an entry `e` over a head `p`. This head
+                // has a number of own heads `h` it depends on. We need to
+                // make sure that the path kind of all paths `hph` remain the
+                // same after rebasing.
+                //
+                // After rebasing the cycles `hph` will go through `e`. We need to make
+                // sure that forall possible paths `hep`, `heph` is equal to `hph.`
+                let ep = popped_head.paths_to_head;
+                for (head_index, head) in stack_entry.heads.iter() {
+                    let ph = head.paths_to_head;
+                    let hp = Self::cycle_path_kind(
+                        &self.stack,
+                        stack_entry.step_kind_from_parent,
+                        head_index,
+                    );
 
-                // The same for nested goals of the cycle head.
-                if stack_entry.heads.iter().any(|(_, p)| matches!(p, AllPathsToHeadCoinductive::No))
-                {
-                    return false;
+                    // We first validate that all cycles while computing `p` would stay
+                    // the same if we were to recompute it as a nested goal of `e`.
+                    let he = hp.extend(*path_from_head);
+                    for ph in ph.iter_paths() {
+                        let hph = hp.extend(ph);
+                        for ep in ep.iter_paths() {
+                            let hep = ep.extend(he);
+                            let heph = hep.extend(ph);
+                            if hph != heph {
+                                return false;
+                            }
+                        }
+                    }
+
+                    // If so, all paths reached while computing `p` have to get added
+                    // the heads of `e` to make sure that rebasing `e` again also considers
+                    // them.
+                    let eph = ep.extend_with_paths(ph);
+                    heads.insert(head_index, eph, head.usage_kind);
                 }
 
-                // Merge the cycle heads of the provisional cache entry and the
-                // popped head. If the popped cycle head was a root, discard all
-                // provisional cache entries which depend on it.
-                heads.merge(&stack_entry.heads);
                 let Some(head) = heads.opt_highest_cycle_head() else {
                     return false;
                 };
@@ -873,11 +908,10 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
                     &mut self.stack,
                     step_kind_from_parent,
                     0,
-                    heads,
+                    heads.iter(),
                     encountered_overflow,
                     UpdateParentGoalCtxt::ProvisionalCacheHit,
                 );
-                debug_assert!(self.stack[head].has_been_used.is_some());
                 debug!(?head, ?path_from_head, "provisional cache hit");
                 return Some(result);
             }
@@ -989,12 +1023,12 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
 
             // We don't move cycle participants to the global cache, so the
             // cycle heads are always empty.
-            let heads = Default::default();
+            let heads = iter::empty();
             Self::update_parent_goal(
                 &mut self.stack,
                 step_kind_from_parent,
                 required_depth,
-                &heads,
+                heads,
                 encountered_overflow,
                 UpdateParentGoalCtxt::Ordinary(nested_goals),
             );
@@ -1010,34 +1044,31 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
         input: X::Input,
         step_kind_from_parent: PathKind,
     ) -> Option<X::Result> {
-        let head = self.stack.find(input)?;
+        let head_index = self.stack.find(input)?;
         // We have a nested goal which directly relies on a goal deeper in the stack.
         //
         // We start by tagging all cycle participants, as that's necessary for caching.
         //
         // Finally we can return either the provisional response or the initial response
         // in case we're in the first fixpoint iteration for this goal.
-        let path_kind = Self::cycle_path_kind(&self.stack, step_kind_from_parent, head);
-        debug!(?path_kind, "encountered cycle with depth {head:?}");
-        let usage_kind = UsageKind::Single(path_kind);
-        self.stack[head].has_been_used =
-            Some(self.stack[head].has_been_used.map_or(usage_kind, |prev| prev.merge(usage_kind)));
-
-        // Subtle: when encountering a cyclic goal, we still first checked for overflow,
-        // so we have to update the reached depth.
-        let last_index = self.stack.last_index().unwrap();
-        let last = &mut self.stack[last_index];
-        last.required_depth = last.required_depth.max(1);
-
-        last.nested_goals.insert(input, step_kind_from_parent.into());
-        last.nested_goals.insert(last.input, PathsToNested::EMPTY);
-        if last_index != head {
-            last.heads.insert(head, step_kind_from_parent);
-        }
+        let path_kind = Self::cycle_path_kind(&self.stack, step_kind_from_parent, head_index);
+        debug!(?path_kind, "encountered cycle with depth {head_index:?}");
+        let head = CycleHead {
+            paths_to_head: step_kind_from_parent.into(),
+            usage_kind: UsageKind::Single(path_kind),
+        };
+        Self::update_parent_goal(
+            &mut self.stack,
+            step_kind_from_parent,
+            0,
+            iter::once((head_index, head)),
+            false,
+            UpdateParentGoalCtxt::CycleOnStack(input),
+        );
 
         // Return the provisional result or, if we're in the first iteration,
         // start with no constraints.
-        if let Some(result) = self.stack[head].provisional_result {
+        if let Some(result) = self.stack[head_index].provisional_result {
             Some(result)
         } else {
             Some(D::initial_provisional_result(cx, path_kind, input))
diff --git a/compiler/rustc_type_ir/src/search_graph/stack.rs b/compiler/rustc_type_ir/src/search_graph/stack.rs
index e0fd934df69..ea99dc6e7fd 100644
--- a/compiler/rustc_type_ir/src/search_graph/stack.rs
+++ b/compiler/rustc_type_ir/src/search_graph/stack.rs
@@ -1,9 +1,9 @@
-use std::ops::{Index, IndexMut};
+use std::ops::Index;
 
 use derive_where::derive_where;
 use rustc_index::IndexVec;
 
-use super::{AvailableDepth, Cx, CycleHeads, NestedGoals, PathKind, UsageKind};
+use crate::search_graph::{AvailableDepth, Cx, CycleHeads, NestedGoals, PathKind, UsageKind};
 
 rustc_index::newtype_index! {
     #[orderable]
@@ -48,6 +48,12 @@ pub(super) struct StackEntry<X: Cx> {
     pub nested_goals: NestedGoals<X>,
 }
 
+/// The stack of goals currently being computed.
+///
+/// An element is *deeper* in the stack if its index is *lower*.
+///
+/// Only the last entry of the stack is mutable. All other entries get
+/// lazily updated in `update_parent_goal`.
 #[derive_where(Default; X: Cx)]
 pub(super) struct Stack<X: Cx> {
     entries: IndexVec<StackDepth, StackEntry<X>>,
@@ -62,10 +68,6 @@ impl<X: Cx> Stack<X> {
         self.entries.len()
     }
 
-    pub(super) fn last_index(&self) -> Option<StackDepth> {
-        self.entries.last_index()
-    }
-
     pub(super) fn last(&self) -> Option<&StackEntry<X>> {
         self.entries.raw.last()
     }
@@ -74,11 +76,18 @@ impl<X: Cx> Stack<X> {
         self.entries.raw.last_mut()
     }
 
+    pub(super) fn last_mut_with_index(&mut self) -> Option<(StackDepth, &mut StackEntry<X>)> {
+        self.entries.last_index().map(|idx| (idx, &mut self.entries[idx]))
+    }
+
     pub(super) fn next_index(&self) -> StackDepth {
         self.entries.next_index()
     }
 
     pub(super) fn push(&mut self, entry: StackEntry<X>) -> StackDepth {
+        if cfg!(debug_assertions) && self.entries.iter().any(|e| e.input == entry.input) {
+            panic!("pushing duplicate entry on stack: {entry:?} {:?}", self.entries);
+        }
         self.entries.push(entry)
     }
 
@@ -105,9 +114,3 @@ impl<X: Cx> Index<StackDepth> for Stack<X> {
         &self.entries[index]
     }
 }
-
-impl<X: Cx> IndexMut<StackDepth> for Stack<X> {
-    fn index_mut(&mut self, index: StackDepth) -> &mut Self::Output {
-        &mut self.entries[index]
-    }
-}
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index c091e496c50..639c5d4c930 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -102,6 +102,7 @@
 #![feature(async_iterator)]
 #![feature(bstr)]
 #![feature(bstr_internals)]
+#![feature(cast_maybe_uninit)]
 #![feature(char_internals)]
 #![feature(char_max_len)]
 #![feature(clone_to_uninit)]
diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs
index 2321aab2c51..2e40227a058 100644
--- a/library/alloc/src/vec/mod.rs
+++ b/library/alloc/src/vec/mod.rs
@@ -49,7 +49,27 @@
 //! v[1] = v[1] + 5;
 //! ```
 //!
+//! # Memory layout
+//!
+//! When the type is non-zero-sized and the capacity is nonzero, [`Vec`] uses the [`Global`]
+//! allocator for its allocation. It is valid to convert both ways between such a [`Vec`] and a raw
+//! pointer allocated with the [`Global`] allocator, provided that the [`Layout`] used with the
+//! allocator is correct for a sequence of `capacity` elements of the type, and the first `len`
+//! values pointed to by the raw pointer are valid. More precisely, a `ptr: *mut T` that has been
+//! allocated with the [`Global`] allocator with [`Layout::array::<T>(capacity)`][Layout::array] may
+//! be converted into a vec using
+//! [`Vec::<T>::from_raw_parts(ptr, len, capacity)`](Vec::from_raw_parts). Conversely, the memory
+//! backing a `value: *mut T` obtained from [`Vec::<T>::as_mut_ptr`] may be deallocated using the
+//! [`Global`] allocator with the same layout.
+//!
+//! For zero-sized types (ZSTs), or when the capacity is zero, the `Vec` pointer must be non-null
+//! and sufficiently aligned. The recommended way to build a `Vec` of ZSTs if [`vec!`] cannot be
+//! used is to use [`ptr::NonNull::dangling`].
+//!
 //! [`push`]: Vec::push
+//! [`ptr::NonNull::dangling`]: NonNull::dangling
+//! [`Layout`]: crate::alloc::Layout
+//! [Layout::array]: crate::alloc::Layout::array
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -523,18 +543,23 @@ impl<T> Vec<T> {
     /// This is highly unsafe, due to the number of invariants that aren't
     /// checked:
     ///
-    /// * `ptr` must have been allocated using the global allocator, such as via
-    ///   the [`alloc::alloc`] function.
-    /// * `T` needs to have the same alignment as what `ptr` was allocated with.
+    /// * If `T` is not a zero-sized type and the capacity is nonzero, `ptr` must have
+    ///   been allocated using the global allocator, such as via the [`alloc::alloc`]
+    ///   function. If `T` is a zero-sized type or the capacity is zero, `ptr` need
+    ///   only be non-null and aligned.
+    /// * `T` needs to have the same alignment as what `ptr` was allocated with,
+    ///   if the pointer is required to be allocated.
     ///   (`T` having a less strict alignment is not sufficient, the alignment really
     ///   needs to be equal to satisfy the [`dealloc`] requirement that memory must be
     ///   allocated and deallocated with the same layout.)
-    /// * The size of `T` times the `capacity` (ie. the allocated size in bytes) needs
-    ///   to be the same size as the pointer was allocated with. (Because similar to
-    ///   alignment, [`dealloc`] must be called with the same layout `size`.)
+    /// * The size of `T` times the `capacity` (ie. the allocated size in bytes), if
+    ///   nonzero, needs to be the same size as the pointer was allocated with.
+    ///   (Because similar to alignment, [`dealloc`] must be called with the same
+    ///   layout `size`.)
     /// * `length` needs to be less than or equal to `capacity`.
     /// * The first `length` values must be properly initialized values of type `T`.
-    /// * `capacity` needs to be the capacity that the pointer was allocated with.
+    /// * `capacity` needs to be the capacity that the pointer was allocated with,
+    ///   if the pointer is required to be allocated.
     /// * The allocated size in bytes must be no larger than `isize::MAX`.
     ///   See the safety documentation of [`pointer::offset`].
     ///
@@ -770,12 +795,16 @@ impl<T> Vec<T> {
     /// order as the arguments to [`from_raw_parts`].
     ///
     /// After calling this function, the caller is responsible for the
-    /// memory previously managed by the `Vec`. The only way to do
-    /// this is to convert the raw pointer, length, and capacity back
-    /// into a `Vec` with the [`from_raw_parts`] function, allowing
-    /// the destructor to perform the cleanup.
+    /// memory previously managed by the `Vec`. Most often, one does
+    /// this by converting the raw pointer, length, and capacity back
+    /// into a `Vec` with the [`from_raw_parts`] function; more generally,
+    /// if `T` is non-zero-sized and the capacity is nonzero, one may use
+    /// any method that calls [`dealloc`] with a layout of
+    /// `Layout::array::<T>(capacity)`; if `T` is zero-sized or the
+    /// capacity is zero, nothing needs to be done.
     ///
     /// [`from_raw_parts`]: Vec::from_raw_parts
+    /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
     ///
     /// # Examples
     ///
@@ -1755,6 +1784,12 @@ impl<T, A: Allocator> Vec<T, A> {
     /// may still invalidate this pointer.
     /// See the second example below for how this guarantee can be used.
     ///
+    /// The method also guarantees that, as long as `T` is not zero-sized and the capacity is
+    /// nonzero, the pointer may be passed into [`dealloc`] with a layout of
+    /// `Layout::array::<T>(capacity)` in order to deallocate the backing memory. If this is done,
+    /// be careful not to run the destructor of the `Vec`, as dropping it will result in
+    /// double-frees. Wrapping the `Vec` in a [`ManuallyDrop`] is the typical way to achieve this.
+    ///
     /// # Examples
     ///
     /// ```
@@ -1787,9 +1822,24 @@ impl<T, A: Allocator> Vec<T, A> {
     /// }
     /// ```
     ///
+    /// Deallocating a vector using [`Box`] (which uses [`dealloc`] internally):
+    ///
+    /// ```
+    /// use std::mem::{ManuallyDrop, MaybeUninit};
+    ///
+    /// let mut v = ManuallyDrop::new(vec![0, 1, 2]);
+    /// let ptr = v.as_mut_ptr();
+    /// let capacity = v.capacity();
+    /// let slice_ptr: *mut [MaybeUninit<i32>] =
+    ///     std::ptr::slice_from_raw_parts_mut(ptr.cast(), capacity);
+    /// drop(unsafe { Box::from_raw(slice_ptr) });
+    /// ```
+    ///
     /// [`as_mut_ptr`]: Vec::as_mut_ptr
     /// [`as_ptr`]: Vec::as_ptr
     /// [`as_non_null`]: Vec::as_non_null
+    /// [`dealloc`]: crate::alloc::GlobalAlloc::dealloc
+    /// [`ManuallyDrop`]: core::mem::ManuallyDrop
     #[stable(feature = "vec_as_ptr", since = "1.37.0")]
     #[rustc_const_stable(feature = "const_vec_string_slice", since = "1.87.0")]
     #[rustc_never_returns_null_ptr]
@@ -3126,7 +3176,7 @@ impl<T, A: Allocator> Vec<T, A> {
         // - but the allocation extends out to `self.buf.capacity()` elements, possibly
         // uninitialized
         let spare_ptr = unsafe { ptr.add(self.len) };
-        let spare_ptr = spare_ptr.cast::<MaybeUninit<T>>();
+        let spare_ptr = spare_ptr.cast_uninit();
         let spare_len = self.buf.capacity() - self.len;
 
         // SAFETY:
diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs
index 49275975f04..cd5fd77f865 100644
--- a/library/core/src/alloc/layout.rs
+++ b/library/core/src/alloc/layout.rs
@@ -226,10 +226,10 @@ impl Layout {
 
     /// Creates a `NonNull` that is dangling, but well-aligned for this Layout.
     ///
-    /// Note that the pointer value may potentially represent a valid pointer,
-    /// which means this must not be used as a "not yet initialized"
-    /// sentinel value. Types that lazily allocate must track initialization by
-    /// some other means.
+    /// Note that the address of the returned pointer may potentially
+    /// be that of a valid pointer, which means this must not be used
+    /// as a "not yet initialized" sentinel value.
+    /// Types that lazily allocate must track initialization by some other means.
     #[unstable(feature = "alloc_layout_extra", issue = "55724")]
     #[must_use]
     #[inline]
diff --git a/library/core/src/ascii/ascii_char.rs b/library/core/src/ascii/ascii_char.rs
index 054ddf84470..419e4694594 100644
--- a/library/core/src/ascii/ascii_char.rs
+++ b/library/core/src/ascii/ascii_char.rs
@@ -445,7 +445,15 @@ pub enum AsciiChar {
 }
 
 impl AsciiChar {
-    /// Creates an ascii character from the byte `b`,
+    /// The character with the lowest ASCII code.
+    #[unstable(feature = "ascii_char", issue = "110998")]
+    pub const MIN: Self = Self::Null;
+
+    /// The character with the highest ASCII code.
+    #[unstable(feature = "ascii_char", issue = "110998")]
+    pub const MAX: Self = Self::Delete;
+
+    /// Creates an ASCII character from the byte `b`,
     /// or returns `None` if it's too large.
     #[unstable(feature = "ascii_char", issue = "110998")]
     #[inline]
@@ -540,6 +548,608 @@ impl AsciiChar {
     pub const fn as_str(&self) -> &str {
         crate::slice::from_ref(self).as_str()
     }
+
+    /// Makes a copy of the value in its upper case equivalent.
+    ///
+    /// Letters 'a' to 'z' are mapped to 'A' to 'Z'.
+    ///
+    /// To uppercase the value in-place, use [`make_uppercase`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_char, ascii_char_variants)]
+    /// use std::ascii;
+    ///
+    /// let lowercase_a = ascii::Char::SmallA;
+    ///
+    /// assert_eq!(
+    ///     ascii::Char::CapitalA,
+    ///     lowercase_a.to_uppercase(),
+    /// );
+    /// ```
+    ///
+    /// [`make_uppercase`]: Self::make_uppercase
+    #[must_use = "to uppercase the value in-place, use `make_uppercase()`"]
+    #[unstable(feature = "ascii_char", issue = "110998")]
+    #[inline]
+    pub const fn to_uppercase(self) -> Self {
+        let uppercase_byte = self.to_u8().to_ascii_uppercase();
+        // SAFETY: Toggling the 6th bit won't convert ASCII to non-ASCII.
+        unsafe { Self::from_u8_unchecked(uppercase_byte) }
+    }
+
+    /// Makes a copy of the value in its lower case equivalent.
+    ///
+    /// Letters 'A' to 'Z' are mapped to 'a' to 'z'.
+    ///
+    /// To lowercase the value in-place, use [`make_lowercase`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_char, ascii_char_variants)]
+    /// use std::ascii;
+    ///
+    /// let uppercase_a = ascii::Char::CapitalA;
+    ///
+    /// assert_eq!(
+    ///     ascii::Char::SmallA,
+    ///     uppercase_a.to_lowercase(),
+    /// );
+    /// ```
+    ///
+    /// [`make_lowercase`]: Self::make_lowercase
+    #[must_use = "to lowercase the value in-place, use `make_lowercase()`"]
+    #[unstable(feature = "ascii_char", issue = "110998")]
+    #[inline]
+    pub const fn to_lowercase(self) -> Self {
+        let lowercase_byte = self.to_u8().to_ascii_lowercase();
+        // SAFETY: Setting the 6th bit won't convert ASCII to non-ASCII.
+        unsafe { Self::from_u8_unchecked(lowercase_byte) }
+    }
+
+    /// Checks that two values are a case-insensitive match.
+    ///
+    /// This is equivalent to `to_lowercase(a) == to_lowercase(b)`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_char, ascii_char_variants)]
+    /// use std::ascii;
+    ///
+    /// let lowercase_a = ascii::Char::SmallA;
+    /// let uppercase_a = ascii::Char::CapitalA;
+    ///
+    /// assert!(lowercase_a.eq_ignore_case(uppercase_a));
+    /// ```
+    #[unstable(feature = "ascii_char", issue = "110998")]
+    #[inline]
+    pub const fn eq_ignore_case(self, other: Self) -> bool {
+        // FIXME(const-hack) `arg.to_u8().to_ascii_lowercase()` -> `arg.to_lowercase()`
+        // once `PartialEq` is const for `Self`.
+        self.to_u8().to_ascii_lowercase() == other.to_u8().to_ascii_lowercase()
+    }
+
+    /// Converts this value to its upper case equivalent in-place.
+    ///
+    /// Letters 'a' to 'z' are mapped to 'A' to 'Z'.
+    ///
+    /// To return a new uppercased value without modifying the existing one, use
+    /// [`to_uppercase`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_char, ascii_char_variants)]
+    /// use std::ascii;
+    ///
+    /// let mut letter_a = ascii::Char::SmallA;
+    ///
+    /// letter_a.make_uppercase();
+    ///
+    /// assert_eq!(ascii::Char::CapitalA, letter_a);
+    /// ```
+    ///
+    /// [`to_uppercase`]: Self::to_uppercase
+    #[unstable(feature = "ascii_char", issue = "110998")]
+    #[inline]
+    pub const fn make_uppercase(&mut self) {
+        *self = self.to_uppercase();
+    }
+
+    /// Converts this value to its lower case equivalent in-place.
+    ///
+    /// Letters 'A' to 'Z' are mapped to 'a' to 'z'.
+    ///
+    /// To return a new lowercased value without modifying the existing one, use
+    /// [`to_lowercase`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_char, ascii_char_variants)]
+    /// use std::ascii;
+    ///
+    /// let mut letter_a = ascii::Char::CapitalA;
+    ///
+    /// letter_a.make_lowercase();
+    ///
+    /// assert_eq!(ascii::Char::SmallA, letter_a);
+    /// ```
+    ///
+    /// [`to_lowercase`]: Self::to_lowercase
+    #[unstable(feature = "ascii_char", issue = "110998")]
+    #[inline]
+    pub const fn make_lowercase(&mut self) {
+        *self = self.to_lowercase();
+    }
+
+    /// Checks if the value is an alphabetic character:
+    ///
+    /// - 0x41 'A' ..= 0x5A 'Z', or
+    /// - 0x61 'a' ..= 0x7A 'z'.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_char, ascii_char_variants)]
+    /// use std::ascii;
+    ///
+    /// let uppercase_a = ascii::Char::CapitalA;
+    /// let uppercase_g = ascii::Char::CapitalG;
+    /// let a = ascii::Char::SmallA;
+    /// let g = ascii::Char::SmallG;
+    /// let zero = ascii::Char::Digit0;
+    /// let percent = ascii::Char::PercentSign;
+    /// let space = ascii::Char::Space;
+    /// let lf = ascii::Char::LineFeed;
+    /// let esc = ascii::Char::Escape;
+    ///
+    /// assert!(uppercase_a.is_alphabetic());
+    /// assert!(uppercase_g.is_alphabetic());
+    /// assert!(a.is_alphabetic());
+    /// assert!(g.is_alphabetic());
+    /// assert!(!zero.is_alphabetic());
+    /// assert!(!percent.is_alphabetic());
+    /// assert!(!space.is_alphabetic());
+    /// assert!(!lf.is_alphabetic());
+    /// assert!(!esc.is_alphabetic());
+    /// ```
+    #[must_use]
+    #[unstable(feature = "ascii_char", issue = "110998")]
+    #[inline]
+    pub const fn is_alphabetic(self) -> bool {
+        self.to_u8().is_ascii_alphabetic()
+    }
+
+    /// Checks if the value is an uppercase character:
+    /// 0x41 'A' ..= 0x5A 'Z'.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_char, ascii_char_variants)]
+    /// use std::ascii;
+    ///
+    /// let uppercase_a = ascii::Char::CapitalA;
+    /// let uppercase_g = ascii::Char::CapitalG;
+    /// let a = ascii::Char::SmallA;
+    /// let g = ascii::Char::SmallG;
+    /// let zero = ascii::Char::Digit0;
+    /// let percent = ascii::Char::PercentSign;
+    /// let space = ascii::Char::Space;
+    /// let lf = ascii::Char::LineFeed;
+    /// let esc = ascii::Char::Escape;
+    ///
+    /// assert!(uppercase_a.is_uppercase());
+    /// assert!(uppercase_g.is_uppercase());
+    /// assert!(!a.is_uppercase());
+    /// assert!(!g.is_uppercase());
+    /// assert!(!zero.is_uppercase());
+    /// assert!(!percent.is_uppercase());
+    /// assert!(!space.is_uppercase());
+    /// assert!(!lf.is_uppercase());
+    /// assert!(!esc.is_uppercase());
+    /// ```
+    #[must_use]
+    #[unstable(feature = "ascii_char", issue = "110998")]
+    #[inline]
+    pub const fn is_uppercase(self) -> bool {
+        self.to_u8().is_ascii_uppercase()
+    }
+
+    /// Checks if the value is a lowercase character:
+    /// 0x61 'a' ..= 0x7A 'z'.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_char, ascii_char_variants)]
+    /// use std::ascii;
+    ///
+    /// let uppercase_a = ascii::Char::CapitalA;
+    /// let uppercase_g = ascii::Char::CapitalG;
+    /// let a = ascii::Char::SmallA;
+    /// let g = ascii::Char::SmallG;
+    /// let zero = ascii::Char::Digit0;
+    /// let percent = ascii::Char::PercentSign;
+    /// let space = ascii::Char::Space;
+    /// let lf = ascii::Char::LineFeed;
+    /// let esc = ascii::Char::Escape;
+    ///
+    /// assert!(!uppercase_a.is_lowercase());
+    /// assert!(!uppercase_g.is_lowercase());
+    /// assert!(a.is_lowercase());
+    /// assert!(g.is_lowercase());
+    /// assert!(!zero.is_lowercase());
+    /// assert!(!percent.is_lowercase());
+    /// assert!(!space.is_lowercase());
+    /// assert!(!lf.is_lowercase());
+    /// assert!(!esc.is_lowercase());
+    /// ```
+    #[must_use]
+    #[unstable(feature = "ascii_char", issue = "110998")]
+    #[inline]
+    pub const fn is_lowercase(self) -> bool {
+        self.to_u8().is_ascii_lowercase()
+    }
+
+    /// Checks if the value is an alphanumeric character:
+    ///
+    /// - 0x41 'A' ..= 0x5A 'Z', or
+    /// - 0x61 'a' ..= 0x7A 'z', or
+    /// - 0x30 '0' ..= 0x39 '9'.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_char, ascii_char_variants)]
+    /// use std::ascii;
+    ///
+    /// let uppercase_a = ascii::Char::CapitalA;
+    /// let uppercase_g = ascii::Char::CapitalG;
+    /// let a = ascii::Char::SmallA;
+    /// let g = ascii::Char::SmallG;
+    /// let zero = ascii::Char::Digit0;
+    /// let percent = ascii::Char::PercentSign;
+    /// let space = ascii::Char::Space;
+    /// let lf = ascii::Char::LineFeed;
+    /// let esc = ascii::Char::Escape;
+    ///
+    /// assert!(uppercase_a.is_alphanumeric());
+    /// assert!(uppercase_g.is_alphanumeric());
+    /// assert!(a.is_alphanumeric());
+    /// assert!(g.is_alphanumeric());
+    /// assert!(zero.is_alphanumeric());
+    /// assert!(!percent.is_alphanumeric());
+    /// assert!(!space.is_alphanumeric());
+    /// assert!(!lf.is_alphanumeric());
+    /// assert!(!esc.is_alphanumeric());
+    /// ```
+    #[must_use]
+    #[unstable(feature = "ascii_char", issue = "110998")]
+    #[inline]
+    pub const fn is_alphanumeric(self) -> bool {
+        self.to_u8().is_ascii_alphanumeric()
+    }
+
+    /// Checks if the value is a decimal digit:
+    /// 0x30 '0' ..= 0x39 '9'.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_char, ascii_char_variants)]
+    /// use std::ascii;
+    ///
+    /// let uppercase_a = ascii::Char::CapitalA;
+    /// let uppercase_g = ascii::Char::CapitalG;
+    /// let a = ascii::Char::SmallA;
+    /// let g = ascii::Char::SmallG;
+    /// let zero = ascii::Char::Digit0;
+    /// let percent = ascii::Char::PercentSign;
+    /// let space = ascii::Char::Space;
+    /// let lf = ascii::Char::LineFeed;
+    /// let esc = ascii::Char::Escape;
+    ///
+    /// assert!(!uppercase_a.is_digit());
+    /// assert!(!uppercase_g.is_digit());
+    /// assert!(!a.is_digit());
+    /// assert!(!g.is_digit());
+    /// assert!(zero.is_digit());
+    /// assert!(!percent.is_digit());
+    /// assert!(!space.is_digit());
+    /// assert!(!lf.is_digit());
+    /// assert!(!esc.is_digit());
+    /// ```
+    #[must_use]
+    #[unstable(feature = "ascii_char", issue = "110998")]
+    #[inline]
+    pub const fn is_digit(self) -> bool {
+        self.to_u8().is_ascii_digit()
+    }
+
+    /// Checks if the value is an octal digit:
+    /// 0x30 '0' ..= 0x37 '7'.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_char, ascii_char_variants, is_ascii_octdigit)]
+    ///
+    /// use std::ascii;
+    ///
+    /// let uppercase_a = ascii::Char::CapitalA;
+    /// let a = ascii::Char::SmallA;
+    /// let zero = ascii::Char::Digit0;
+    /// let seven = ascii::Char::Digit7;
+    /// let eight = ascii::Char::Digit8;
+    /// let percent = ascii::Char::PercentSign;
+    /// let lf = ascii::Char::LineFeed;
+    /// let esc = ascii::Char::Escape;
+    ///
+    /// assert!(!uppercase_a.is_octdigit());
+    /// assert!(!a.is_octdigit());
+    /// assert!(zero.is_octdigit());
+    /// assert!(seven.is_octdigit());
+    /// assert!(!eight.is_octdigit());
+    /// assert!(!percent.is_octdigit());
+    /// assert!(!lf.is_octdigit());
+    /// assert!(!esc.is_octdigit());
+    /// ```
+    #[must_use]
+    // This is blocked on two unstable features. Please ensure both are
+    // stabilized before marking this method as stable.
+    #[unstable(feature = "ascii_char", issue = "110998")]
+    // #[unstable(feature = "is_ascii_octdigit", issue = "101288")]
+    #[inline]
+    pub const fn is_octdigit(self) -> bool {
+        self.to_u8().is_ascii_octdigit()
+    }
+
+    /// Checks if the value is a hexadecimal digit:
+    ///
+    /// - 0x30 '0' ..= 0x39 '9', or
+    /// - 0x41 'A' ..= 0x46 'F', or
+    /// - 0x61 'a' ..= 0x66 'f'.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_char, ascii_char_variants)]
+    /// use std::ascii;
+    ///
+    /// let uppercase_a = ascii::Char::CapitalA;
+    /// let uppercase_g = ascii::Char::CapitalG;
+    /// let a = ascii::Char::SmallA;
+    /// let g = ascii::Char::SmallG;
+    /// let zero = ascii::Char::Digit0;
+    /// let percent = ascii::Char::PercentSign;
+    /// let space = ascii::Char::Space;
+    /// let lf = ascii::Char::LineFeed;
+    /// let esc = ascii::Char::Escape;
+    ///
+    /// assert!(uppercase_a.is_hexdigit());
+    /// assert!(!uppercase_g.is_hexdigit());
+    /// assert!(a.is_hexdigit());
+    /// assert!(!g.is_hexdigit());
+    /// assert!(zero.is_hexdigit());
+    /// assert!(!percent.is_hexdigit());
+    /// assert!(!space.is_hexdigit());
+    /// assert!(!lf.is_hexdigit());
+    /// assert!(!esc.is_hexdigit());
+    /// ```
+    #[must_use]
+    #[unstable(feature = "ascii_char", issue = "110998")]
+    #[inline]
+    pub const fn is_hexdigit(self) -> bool {
+        self.to_u8().is_ascii_hexdigit()
+    }
+
+    /// Checks if the value is a punctuation character:
+    ///
+    /// - 0x21 ..= 0x2F `! " # $ % & ' ( ) * + , - . /`, or
+    /// - 0x3A ..= 0x40 `: ; < = > ? @`, or
+    /// - 0x5B ..= 0x60 `` [ \ ] ^ _ ` ``, or
+    /// - 0x7B ..= 0x7E `{ | } ~`
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_char, ascii_char_variants)]
+    /// use std::ascii;
+    ///
+    /// let uppercase_a = ascii::Char::CapitalA;
+    /// let uppercase_g = ascii::Char::CapitalG;
+    /// let a = ascii::Char::SmallA;
+    /// let g = ascii::Char::SmallG;
+    /// let zero = ascii::Char::Digit0;
+    /// let percent = ascii::Char::PercentSign;
+    /// let space = ascii::Char::Space;
+    /// let lf = ascii::Char::LineFeed;
+    /// let esc = ascii::Char::Escape;
+    ///
+    /// assert!(!uppercase_a.is_punctuation());
+    /// assert!(!uppercase_g.is_punctuation());
+    /// assert!(!a.is_punctuation());
+    /// assert!(!g.is_punctuation());
+    /// assert!(!zero.is_punctuation());
+    /// assert!(percent.is_punctuation());
+    /// assert!(!space.is_punctuation());
+    /// assert!(!lf.is_punctuation());
+    /// assert!(!esc.is_punctuation());
+    /// ```
+    #[must_use]
+    #[unstable(feature = "ascii_char", issue = "110998")]
+    #[inline]
+    pub const fn is_punctuation(self) -> bool {
+        self.to_u8().is_ascii_punctuation()
+    }
+
+    /// Checks if the value is a graphic character:
+    /// 0x21 '!' ..= 0x7E '~'.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_char, ascii_char_variants)]
+    /// use std::ascii;
+    ///
+    /// let uppercase_a = ascii::Char::CapitalA;
+    /// let uppercase_g = ascii::Char::CapitalG;
+    /// let a = ascii::Char::SmallA;
+    /// let g = ascii::Char::SmallG;
+    /// let zero = ascii::Char::Digit0;
+    /// let percent = ascii::Char::PercentSign;
+    /// let space = ascii::Char::Space;
+    /// let lf = ascii::Char::LineFeed;
+    /// let esc = ascii::Char::Escape;
+    ///
+    /// assert!(uppercase_a.is_graphic());
+    /// assert!(uppercase_g.is_graphic());
+    /// assert!(a.is_graphic());
+    /// assert!(g.is_graphic());
+    /// assert!(zero.is_graphic());
+    /// assert!(percent.is_graphic());
+    /// assert!(!space.is_graphic());
+    /// assert!(!lf.is_graphic());
+    /// assert!(!esc.is_graphic());
+    /// ```
+    #[must_use]
+    #[unstable(feature = "ascii_char", issue = "110998")]
+    #[inline]
+    pub const fn is_graphic(self) -> bool {
+        self.to_u8().is_ascii_graphic()
+    }
+
+    /// Checks if the value is a whitespace character:
+    /// 0x20 SPACE, 0x09 HORIZONTAL TAB, 0x0A LINE FEED,
+    /// 0x0C FORM FEED, or 0x0D CARRIAGE RETURN.
+    ///
+    /// Rust uses the WhatWG Infra Standard's [definition of ASCII
+    /// whitespace][infra-aw]. There are several other definitions in
+    /// wide use. For instance, [the POSIX locale][pct] includes
+    /// 0x0B VERTICAL TAB as well as all the above characters,
+    /// but—from the very same specification—[the default rule for
+    /// "field splitting" in the Bourne shell][bfs] considers *only*
+    /// SPACE, HORIZONTAL TAB, and LINE FEED as whitespace.
+    ///
+    /// If you are writing a program that will process an existing
+    /// file format, check what that format's definition of whitespace is
+    /// before using this function.
+    ///
+    /// [infra-aw]: https://infra.spec.whatwg.org/#ascii-whitespace
+    /// [pct]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html#tag_07_03_01
+    /// [bfs]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_char, ascii_char_variants)]
+    /// use std::ascii;
+    ///
+    /// let uppercase_a = ascii::Char::CapitalA;
+    /// let uppercase_g = ascii::Char::CapitalG;
+    /// let a = ascii::Char::SmallA;
+    /// let g = ascii::Char::SmallG;
+    /// let zero = ascii::Char::Digit0;
+    /// let percent = ascii::Char::PercentSign;
+    /// let space = ascii::Char::Space;
+    /// let lf = ascii::Char::LineFeed;
+    /// let esc = ascii::Char::Escape;
+    ///
+    /// assert!(!uppercase_a.is_whitespace());
+    /// assert!(!uppercase_g.is_whitespace());
+    /// assert!(!a.is_whitespace());
+    /// assert!(!g.is_whitespace());
+    /// assert!(!zero.is_whitespace());
+    /// assert!(!percent.is_whitespace());
+    /// assert!(space.is_whitespace());
+    /// assert!(lf.is_whitespace());
+    /// assert!(!esc.is_whitespace());
+    /// ```
+    #[must_use]
+    #[unstable(feature = "ascii_char", issue = "110998")]
+    #[inline]
+    pub const fn is_whitespace(self) -> bool {
+        self.to_u8().is_ascii_whitespace()
+    }
+
+    /// Checks if the value is a control character:
+    /// 0x00 NUL ..= 0x1F UNIT SEPARATOR, or 0x7F DELETE.
+    /// Note that most whitespace characters are control
+    /// characters, but SPACE is not.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_char, ascii_char_variants)]
+    /// use std::ascii;
+    ///
+    /// let uppercase_a = ascii::Char::CapitalA;
+    /// let uppercase_g = ascii::Char::CapitalG;
+    /// let a = ascii::Char::SmallA;
+    /// let g = ascii::Char::SmallG;
+    /// let zero = ascii::Char::Digit0;
+    /// let percent = ascii::Char::PercentSign;
+    /// let space = ascii::Char::Space;
+    /// let lf = ascii::Char::LineFeed;
+    /// let esc = ascii::Char::Escape;
+    ///
+    /// assert!(!uppercase_a.is_control());
+    /// assert!(!uppercase_g.is_control());
+    /// assert!(!a.is_control());
+    /// assert!(!g.is_control());
+    /// assert!(!zero.is_control());
+    /// assert!(!percent.is_control());
+    /// assert!(!space.is_control());
+    /// assert!(lf.is_control());
+    /// assert!(esc.is_control());
+    /// ```
+    #[must_use]
+    #[unstable(feature = "ascii_char", issue = "110998")]
+    #[inline]
+    pub const fn is_control(self) -> bool {
+        self.to_u8().is_ascii_control()
+    }
+
+    /// Returns an iterator that produces an escaped version of a
+    /// character.
+    ///
+    /// The behavior is identical to
+    /// [`ascii::escape_default`](crate::ascii::escape_default).
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(ascii_char, ascii_char_variants)]
+    /// use std::ascii;
+    ///
+    /// let zero = ascii::Char::Digit0;
+    /// let tab = ascii::Char::CharacterTabulation;
+    /// let cr = ascii::Char::CarriageReturn;
+    /// let lf = ascii::Char::LineFeed;
+    /// let apostrophe = ascii::Char::Apostrophe;
+    /// let double_quote = ascii::Char::QuotationMark;
+    /// let backslash = ascii::Char::ReverseSolidus;
+    ///
+    /// assert_eq!("0", zero.escape_ascii().to_string());
+    /// assert_eq!("\\t", tab.escape_ascii().to_string());
+    /// assert_eq!("\\r", cr.escape_ascii().to_string());
+    /// assert_eq!("\\n", lf.escape_ascii().to_string());
+    /// assert_eq!("\\'", apostrophe.escape_ascii().to_string());
+    /// assert_eq!("\\\"", double_quote.escape_ascii().to_string());
+    /// assert_eq!("\\\\", backslash.escape_ascii().to_string());
+    /// ```
+    #[must_use = "this returns the escaped character as an iterator, \
+                  without modifying the original"]
+    #[unstable(feature = "ascii_char", issue = "110998")]
+    #[inline]
+    pub fn escape_ascii(self) -> super::EscapeDefault {
+        super::escape_default(self.to_u8())
+    }
 }
 
 macro_rules! into_int_impl {
diff --git a/library/core/src/iter/adapters/map_windows.rs b/library/core/src/iter/adapters/map_windows.rs
index a9c07fee2a9..0dada9eb6aa 100644
--- a/library/core/src/iter/adapters/map_windows.rs
+++ b/library/core/src/iter/adapters/map_windows.rs
@@ -195,7 +195,7 @@ impl<T, const N: usize> Buffer<T, N> {
 
         // SAFETY: the index is valid and this is element `a` in the
         // diagram above and has not been dropped yet.
-        unsafe { ptr::drop_in_place(to_drop.cast::<T>()) };
+        unsafe { ptr::drop_in_place(to_drop.cast_init()) };
     }
 }
 
diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs
index f33a33e6b75..95d1e2069ac 100644
--- a/library/core/src/ops/range.rs
+++ b/library/core/src/ops/range.rs
@@ -853,7 +853,7 @@ pub trait RangeBounds<T: ?Sized> {
     /// assert!( RangeBounds::is_empty(&(f32::NAN..5.0)));
     /// ```
     ///
-    /// But never empty is either side is unbounded:
+    /// But never empty if either side is unbounded:
     ///
     /// ```
     /// #![feature(range_bounds_is_empty)]
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 8b3703bd4b3..6546dde39ac 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -1430,6 +1430,28 @@ impl<T: PointeeSized> *const T {
     }
 }
 
+impl<T> *const T {
+    /// Casts from a type to its maybe-uninitialized version.
+    #[must_use]
+    #[inline(always)]
+    #[unstable(feature = "cast_maybe_uninit", issue = "145036")]
+    pub const fn cast_uninit(self) -> *const MaybeUninit<T> {
+        self as _
+    }
+}
+impl<T> *const MaybeUninit<T> {
+    /// Casts from a maybe-uninitialized type to its initialized version.
+    ///
+    /// This is always safe, since UB can only occur if the pointer is read
+    /// before being initialized.
+    #[must_use]
+    #[inline(always)]
+    #[unstable(feature = "cast_maybe_uninit", issue = "145036")]
+    pub const fn cast_init(self) -> *const T {
+        self as _
+    }
+}
+
 impl<T> *const [T] {
     /// Returns the length of a raw slice.
     ///
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 1a2a5182567..b2607e45324 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -885,10 +885,10 @@ pub const fn without_provenance<T>(addr: usize) -> *const T {
 /// This is useful for initializing types which lazily allocate, like
 /// `Vec::new` does.
 ///
-/// Note that the pointer value may potentially represent a valid pointer to
-/// a `T`, which means this must not be used as a "not yet initialized"
-/// sentinel value. Types that lazily allocate must track initialization by
-/// some other means.
+/// Note that the address of the returned pointer may potentially
+/// be that of a valid pointer, which means this must not be used
+/// as a "not yet initialized" sentinel value.
+/// Types that lazily allocate must track initialization by some other means.
 #[inline(always)]
 #[must_use]
 #[stable(feature = "strict_provenance", since = "1.84.0")]
@@ -928,10 +928,10 @@ pub const fn without_provenance_mut<T>(addr: usize) -> *mut T {
 /// This is useful for initializing types which lazily allocate, like
 /// `Vec::new` does.
 ///
-/// Note that the pointer value may potentially represent a valid pointer to
-/// a `T`, which means this must not be used as a "not yet initialized"
-/// sentinel value. Types that lazily allocate must track initialization by
-/// some other means.
+/// Note that the address of the returned pointer may potentially
+/// be that of a valid pointer, which means this must not be used
+/// as a "not yet initialized" sentinel value.
+/// Types that lazily allocate must track initialization by some other means.
 #[inline(always)]
 #[must_use]
 #[stable(feature = "strict_provenance", since = "1.84.0")]
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index af39ec86d7a..4add964141a 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -1687,6 +1687,31 @@ impl<T: PointeeSized> *mut T {
     }
 }
 
+impl<T> *mut T {
+    /// Casts from a type to its maybe-uninitialized version.
+    ///
+    /// This is always safe, since UB can only occur if the pointer is read
+    /// before being initialized.
+    #[must_use]
+    #[inline(always)]
+    #[unstable(feature = "cast_maybe_uninit", issue = "145036")]
+    pub const fn cast_uninit(self) -> *mut MaybeUninit<T> {
+        self as _
+    }
+}
+impl<T> *mut MaybeUninit<T> {
+    /// Casts from a maybe-uninitialized type to its initialized version.
+    ///
+    /// This is always safe, since UB can only occur if the pointer is read
+    /// before being initialized.
+    #[must_use]
+    #[inline(always)]
+    #[unstable(feature = "cast_maybe_uninit", issue = "145036")]
+    pub const fn cast_init(self) -> *mut T {
+        self as _
+    }
+}
+
 impl<T> *mut [T] {
     /// Returns the length of a raw slice.
     ///
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 8667361fecc..da382b8715e 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -109,10 +109,10 @@ impl<T: Sized> NonNull<T> {
     /// This is useful for initializing types which lazily allocate, like
     /// `Vec::new` does.
     ///
-    /// Note that the pointer value may potentially represent a valid pointer to
-    /// a `T`, which means this must not be used as a "not yet initialized"
-    /// sentinel value. Types that lazily allocate must track initialization by
-    /// some other means.
+    /// Note that the address of the returned pointer may potentially
+    /// be that of a valid pointer, which means this must not be used
+    /// as a "not yet initialized" sentinel value.
+    /// Types that lazily allocate must track initialization by some other means.
     ///
     /// # Examples
     ///
@@ -1357,6 +1357,28 @@ impl<T: PointeeSized> NonNull<T> {
     }
 }
 
+impl<T> NonNull<T> {
+    /// Casts from a type to its maybe-uninitialized version.
+    #[must_use]
+    #[inline(always)]
+    #[unstable(feature = "cast_maybe_uninit", issue = "145036")]
+    pub const fn cast_uninit(self) -> NonNull<MaybeUninit<T>> {
+        self.cast()
+    }
+}
+impl<T> NonNull<MaybeUninit<T>> {
+    /// Casts from a maybe-uninitialized type to its initialized version.
+    ///
+    /// This is always safe, since UB can only occur if the pointer is read
+    /// before being initialized.
+    #[must_use]
+    #[inline(always)]
+    #[unstable(feature = "cast_maybe_uninit", issue = "145036")]
+    pub const fn cast_init(self) -> NonNull<T> {
+        self.cast()
+    }
+}
+
 impl<T> NonNull<[T]> {
     /// Creates a non-null raw slice from a thin pointer and a length.
     ///
diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs
index e9e13f9e97f..4302c1b1e44 100644
--- a/library/core/src/ptr/unique.rs
+++ b/library/core/src/ptr/unique.rs
@@ -63,10 +63,10 @@ impl<T: Sized> Unique<T> {
     /// This is useful for initializing types which lazily allocate, like
     /// `Vec::new` does.
     ///
-    /// Note that the pointer value may potentially represent a valid pointer to
-    /// a `T`, which means this must not be used as a "not yet initialized"
-    /// sentinel value. Types that lazily allocate must track initialization by
-    /// some other means.
+    /// Note that the address of the returned pointer may potentially
+    /// be that of a valid pointer, which means this must not be used
+    /// as a "not yet initialized" sentinel value.
+    /// Types that lazily allocate must track initialization by some other means.
     #[must_use]
     #[inline]
     pub const fn dangling() -> Self {
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 0c537530647..07b38c65898 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -281,9 +281,11 @@
 #![feature(cfg_target_thread_local)]
 #![feature(cfi_encoding)]
 #![feature(char_max_len)]
+#![feature(const_trait_impl)]
 #![feature(core_float_math)]
 #![feature(decl_macro)]
 #![feature(deprecated_suggestion)]
+#![feature(derive_const)]
 #![feature(doc_cfg)]
 #![feature(doc_cfg_hide)]
 #![feature(doc_masked)]
@@ -327,8 +329,13 @@
 // tidy-alphabetical-start
 #![feature(bstr)]
 #![feature(bstr_internals)]
+#![feature(cast_maybe_uninit)]
 #![feature(char_internals)]
 #![feature(clone_to_uninit)]
+#![feature(const_cmp)]
+#![feature(const_ops)]
+#![feature(const_option_ops)]
+#![feature(const_try)]
 #![feature(core_intrinsics)]
 #![feature(core_io_borrowed_buf)]
 #![feature(drop_guard)]
diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs
index cff4f20b5a8..5e8d2f8e78e 100644
--- a/library/std/src/panic.rs
+++ b/library/std/src/panic.rs
@@ -60,6 +60,7 @@ impl<'a> PanicHookInfo<'a> {
     /// Returns the payload associated with the panic.
     ///
     /// This will commonly, but not always, be a `&'static str` or [`String`].
+    /// If you only care about such payloads, use [`payload_as_str`] instead.
     ///
     /// A invocation of the `panic!()` macro in Rust 2021 or later will always result in a
     /// panic payload of type `&'static str` or `String`.
@@ -69,6 +70,7 @@ impl<'a> PanicHookInfo<'a> {
     /// can result in a panic payload other than a `&'static str` or `String`.
     ///
     /// [`String`]: ../../std/string/struct.String.html
+    /// [`payload_as_str`]: PanicHookInfo::payload_as_str
     ///
     /// # Examples
     ///
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index e7ba6936435..3b52804d6be 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -2678,7 +2678,6 @@ impl Path {
     /// # Examples
     ///
     /// ```
-    /// # #![feature(path_file_prefix)]
     /// use std::path::Path;
     ///
     /// assert_eq!("foo", Path::new("foo.rs").file_prefix().unwrap());
@@ -2693,7 +2692,7 @@ impl Path {
     ///
     /// [`Path::file_stem`]: Path::file_stem
     ///
-    #[unstable(feature = "path_file_prefix", issue = "86319")]
+    #[stable(feature = "path_file_prefix", since = "CURRENT_RUSTC_VERSION")]
     #[must_use]
     pub fn file_prefix(&self) -> Option<&OsStr> {
         self.file_name().map(split_file_at_dot).and_then(|(before, _after)| Some(before))
diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs
index 09feddd0be9..bb3e4bc30ca 100644
--- a/library/std/src/sys/fs/windows.rs
+++ b/library/std/src/sys/fs/windows.rs
@@ -1606,7 +1606,7 @@ pub fn junction_point(original: &Path, link: &Path) -> io::Result<()> {
     };
     unsafe {
         let ptr = header.PathBuffer.as_mut_ptr();
-        ptr.copy_from(abs_path.as_ptr().cast::<MaybeUninit<u16>>(), abs_path.len());
+        ptr.copy_from(abs_path.as_ptr().cast_uninit(), abs_path.len());
 
         let mut ret = 0;
         cvt(c::DeviceIoControl(
diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs
index f76a5f96c87..89a427ab88b 100644
--- a/library/std/src/sys/pal/hermit/time.rs
+++ b/library/std/src/sys/pal/hermit/time.rs
@@ -25,8 +25,15 @@ impl Timespec {
         Timespec { t: timespec { tv_sec, tv_nsec } }
     }
 
-    fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
-        if self >= other {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    const fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
+        // FIXME: const PartialOrd
+        let mut cmp = self.t.tv_sec - other.t.tv_sec;
+        if cmp == 0 {
+            cmp = self.t.tv_nsec as i64 - other.t.tv_nsec as i64;
+        }
+
+        if cmp >= 0 {
             Ok(if self.t.tv_nsec >= other.t.tv_nsec {
                 Duration::new(
                     (self.t.tv_sec - other.t.tv_sec) as u64,
@@ -46,20 +53,22 @@ impl Timespec {
         }
     }
 
-    fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    const fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
         let mut secs = self.t.tv_sec.checked_add_unsigned(other.as_secs())?;
 
         // Nano calculations can't overflow because nanos are <1B which fit
         // in a u32.
-        let mut nsec = other.subsec_nanos() + u32::try_from(self.t.tv_nsec).unwrap();
-        if nsec >= NSEC_PER_SEC.try_into().unwrap() {
-            nsec -= u32::try_from(NSEC_PER_SEC).unwrap();
+        let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
+        if nsec >= NSEC_PER_SEC as u32 {
+            nsec -= NSEC_PER_SEC as u32;
             secs = secs.checked_add(1)?;
         }
         Some(Timespec { t: timespec { tv_sec: secs, tv_nsec: nsec as _ } })
     }
 
-    fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    const fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
         let mut secs = self.t.tv_sec.checked_sub_unsigned(other.as_secs())?;
 
         // Similar to above, nanos can't overflow.
@@ -213,15 +222,18 @@ impl SystemTime {
         SystemTime(time)
     }
 
-    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
         self.0.sub_timespec(&other.0)
     }
 
-    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_add_duration(other)?))
     }
 
-    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_sub_duration(other)?))
     }
 }
diff --git a/library/std/src/sys/pal/sgx/time.rs b/library/std/src/sys/pal/sgx/time.rs
index db4cf2804bf..603dae952ab 100644
--- a/library/std/src/sys/pal/sgx/time.rs
+++ b/library/std/src/sys/pal/sgx/time.rs
@@ -32,15 +32,22 @@ impl SystemTime {
         SystemTime(usercalls::insecure_time())
     }
 
-    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
-        self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+        // FIXME: ok_or_else with const closures
+        match self.0.checked_sub(other.0) {
+            Some(duration) => Ok(duration),
+            None => Err(other.0 - self.0),
+        }
     }
 
-    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_add(*other)?))
     }
 
-    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_sub(*other)?))
     }
 }
diff --git a/library/std/src/sys/pal/solid/time.rs b/library/std/src/sys/pal/solid/time.rs
index c39d715c6a6..e35e60df1a0 100644
--- a/library/std/src/sys/pal/solid/time.rs
+++ b/library/std/src/sys/pal/solid/time.rs
@@ -39,7 +39,8 @@ impl SystemTime {
         Self(t)
     }
 
-    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
         if self.0 >= other.0 {
             Ok(Duration::from_secs((self.0 as u64).wrapping_sub(other.0 as u64)))
         } else {
@@ -47,11 +48,13 @@ impl SystemTime {
         }
     }
 
-    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_add_unsigned(other.as_secs())?))
     }
 
-    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_sub_unsigned(other.as_secs())?))
     }
 }
diff --git a/library/std/src/sys/pal/uefi/tests.rs b/library/std/src/sys/pal/uefi/tests.rs
index 49e75a1a70d..56ca999cc7e 100644
--- a/library/std/src/sys/pal/uefi/tests.rs
+++ b/library/std/src/sys/pal/uefi/tests.rs
@@ -1,8 +1,13 @@
+//! These tests are not run automatically right now. Please run these tests manually by copying them
+//! to a separate project when modifying any related code.
+
 use super::alloc::*;
-use super::time::*;
+use super::time::system_time_internal::{from_uefi, to_uefi};
 use crate::io::{IoSlice, IoSliceMut};
 use crate::time::Duration;
 
+const SECS_IN_MINUTE: u64 = 60;
+
 #[test]
 fn align() {
     // UEFI ABI specifies that allocation alignment minimum is always 8. So this can be
@@ -24,21 +29,61 @@ fn align() {
 }
 
 #[test]
-fn epoch() {
-    let t = r_efi::system::Time {
-        year: 1970,
+fn systemtime_start() {
+    let t = r_efi::efi::Time {
+        year: 1900,
+        month: 1,
+        day: 1,
+        hour: 0,
+        minute: 0,
+        second: 0,
+        nanosecond: 0,
+        timezone: -1440,
+        daylight: 0,
+        pad2: 0,
+    };
+    assert_eq!(from_uefi(&t), Duration::new(0, 0));
+    assert_eq!(t, to_uefi(&from_uefi(&t), -1440, 0).unwrap());
+    assert!(to_uefi(&from_uefi(&t), 0, 0).is_none());
+}
+
+#[test]
+fn systemtime_utc_start() {
+    let t = r_efi::efi::Time {
+        year: 1900,
         month: 1,
         day: 1,
         hour: 0,
         minute: 0,
         second: 0,
+        pad1: 0,
         nanosecond: 0,
-        timezone: r_efi::efi::UNSPECIFIED_TIMEZONE,
+        timezone: 0,
         daylight: 0,
+        pad2: 0,
+    };
+    assert_eq!(from_uefi(&t), Duration::new(1440 * SECS_IN_MINUTE, 0));
+    assert_eq!(t, to_uefi(&from_uefi(&t), 0, 0).unwrap());
+    assert!(to_uefi(&from_uefi(&t), -1440, 0).is_some());
+}
+
+#[test]
+fn systemtime_end() {
+    let t = r_efi::efi::Time {
+        year: 9999,
+        month: 12,
+        day: 31,
+        hour: 23,
+        minute: 59,
+        second: 59,
         pad1: 0,
+        nanosecond: 0,
+        timezone: 1440,
+        daylight: 0,
         pad2: 0,
     };
-    assert_eq!(system_time_internal::uefi_time_to_duration(t), Duration::new(0, 0));
+    assert!(to_uefi(&from_uefi(&t), 1440, 0).is_some());
+    assert!(to_uefi(&from_uefi(&t), 1439, 0).is_none());
 }
 
 // UEFI IoSlice and IoSliceMut Tests
diff --git a/library/std/src/sys/pal/uefi/time.rs b/library/std/src/sys/pal/uefi/time.rs
index eeb2c35ffbb..df5611b2ddd 100644
--- a/library/std/src/sys/pal/uefi/time.rs
+++ b/library/std/src/sys/pal/uefi/time.rs
@@ -1,16 +1,42 @@
 use crate::time::Duration;
 
-const SECS_IN_MINUTE: u64 = 60;
-const SECS_IN_HOUR: u64 = SECS_IN_MINUTE * 60;
-const SECS_IN_DAY: u64 = SECS_IN_HOUR * 24;
-
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
 pub struct Instant(Duration);
 
+/// When a Timezone is specified, the stored Duration is in UTC. If timezone is unspecified, then
+/// the timezone is assumed to be in UTC.
+///
+/// UEFI SystemTime is stored as Duration from 1900-01-01-00:00:00 with timezone -1440 as anchor
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
 pub struct SystemTime(Duration);
 
-pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
+pub const UNIX_EPOCH: SystemTime = SystemTime::from_uefi(r_efi::efi::Time {
+    year: 1970,
+    month: 1,
+    day: 1,
+    hour: 0,
+    minute: 0,
+    second: 0,
+    nanosecond: 0,
+    timezone: 0,
+    daylight: 0,
+    pad1: 0,
+    pad2: 0,
+});
+
+const MAX_UEFI_TIME: SystemTime = SystemTime::from_uefi(r_efi::efi::Time {
+    year: 9999,
+    month: 12,
+    day: 31,
+    hour: 23,
+    minute: 59,
+    second: 59,
+    nanosecond: 999_999_999,
+    timezone: 1440,
+    daylight: 0,
+    pad1: 0,
+    pad2: 0,
+});
 
 impl Instant {
     pub fn now() -> Instant {
@@ -40,20 +66,45 @@ impl Instant {
 }
 
 impl SystemTime {
+    pub(crate) const fn from_uefi(t: r_efi::efi::Time) -> Self {
+        Self(system_time_internal::from_uefi(&t))
+    }
+
+    #[expect(dead_code)]
+    pub(crate) const fn to_uefi(self, timezone: i16, daylight: u8) -> Option<r_efi::efi::Time> {
+        system_time_internal::to_uefi(&self.0, timezone, daylight)
+    }
+
     pub fn now() -> SystemTime {
         system_time_internal::now()
             .unwrap_or_else(|| panic!("time not implemented on this platform"))
     }
 
-    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
-        self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+        // FIXME: ok_or_else with const closures
+        match self.0.checked_sub(other.0) {
+            Some(duration) => Ok(duration),
+            None => Err(other.0 - self.0),
+        }
     }
 
-    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
-        Some(SystemTime(self.0.checked_add(*other)?))
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+        let temp = self.0.checked_add(*other)?;
+
+        // Check if can be represented in UEFI
+        // FIXME: const PartialOrd
+        let mut cmp = temp.as_secs() - MAX_UEFI_TIME.0.as_secs();
+        if cmp == 0 {
+            cmp = temp.subsec_nanos() as u64 - MAX_UEFI_TIME.0.subsec_nanos() as u64;
+        }
+
+        if cmp <= 0 { Some(SystemTime(temp)) } else { None }
     }
 
-    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_sub(*other)?))
     }
 }
@@ -66,51 +117,132 @@ pub(crate) mod system_time_internal {
     use crate::mem::MaybeUninit;
     use crate::ptr::NonNull;
 
+    const SECS_IN_MINUTE: u64 = 60;
+    const SECS_IN_HOUR: u64 = SECS_IN_MINUTE * 60;
+    const SECS_IN_DAY: u64 = SECS_IN_HOUR * 24;
+    const TIMEZONE_DELTA: u64 = 1440 * SECS_IN_MINUTE;
+
     pub fn now() -> Option<SystemTime> {
         let runtime_services: NonNull<RuntimeServices> = helpers::runtime_services()?;
         let mut t: MaybeUninit<Time> = MaybeUninit::uninit();
         let r = unsafe {
             ((*runtime_services.as_ptr()).get_time)(t.as_mut_ptr(), crate::ptr::null_mut())
         };
-
         if r.is_error() {
             return None;
         }
 
         let t = unsafe { t.assume_init() };
 
-        Some(SystemTime(uefi_time_to_duration(t)))
+        Some(SystemTime::from_uefi(t))
     }
 
-    // This algorithm is based on the one described in the post
-    // https://blog.reverberate.org/2020/05/12/optimizing-date-algorithms.html
-    pub(crate) const fn uefi_time_to_duration(t: r_efi::system::Time) -> Duration {
-        assert!(t.month <= 12);
-        assert!(t.month != 0);
+    /// This algorithm is a modified form of the one described in the post
+    /// https://blog.reverberate.org/2020/05/12/optimizing-date-algorithms.html
+    ///
+    /// The changes are to use 1900-01-01-00:00:00 with timezone -1440 as anchor instead of UNIX
+    /// epoch used in the original algorithm.
+    pub(crate) const fn from_uefi(t: &Time) -> Duration {
+        assert!(t.month <= 12 && t.month != 0);
+        assert!(t.year >= 1900 && t.year <= 9999);
+        assert!(t.day <= 31 && t.day != 0);
+
+        assert!(t.second < 60);
+        assert!(t.minute < 60);
+        assert!(t.hour < 24);
+        assert!(t.nanosecond < 1_000_000_000);
+
+        assert!(
+            (t.timezone <= 1440 && t.timezone >= -1440)
+                || t.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE
+        );
 
         const YEAR_BASE: u32 = 4800; /* Before min year, multiple of 400. */
 
-        // Calculate the number of days since 1/1/1970
+        // Calculate the number of days since 1/1/1900. This is the earliest supported date in UEFI
+        // time.
         // Use 1 March as the start
         let (m_adj, overflow): (u32, bool) = (t.month as u32).overflowing_sub(3);
         let (carry, adjust): (u32, u32) = if overflow { (1, 12) } else { (0, 0) };
         let y_adj: u32 = (t.year as u32) + YEAR_BASE - carry;
         let month_days: u32 = (m_adj.wrapping_add(adjust) * 62719 + 769) / 2048;
         let leap_days: u32 = y_adj / 4 - y_adj / 100 + y_adj / 400;
-        let days: u32 = y_adj * 365 + leap_days + month_days + (t.day as u32 - 1) - 2472632;
+        let days: u32 = y_adj * 365 + leap_days + month_days + (t.day as u32 - 1) - 2447065;
 
         let localtime_epoch: u64 = (days as u64) * SECS_IN_DAY
             + (t.second as u64)
             + (t.minute as u64) * SECS_IN_MINUTE
             + (t.hour as u64) * SECS_IN_HOUR;
 
-        let utc_epoch: u64 = if t.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE {
-            localtime_epoch
+        // Calculate the offset from 1/1/1900 at timezone -1440 min
+        let adjusted_localtime_epoc: u64 = localtime_epoch + TIMEZONE_DELTA;
+
+        let epoch: u64 = if t.timezone == r_efi::efi::UNSPECIFIED_TIMEZONE {
+            adjusted_localtime_epoc
         } else {
-            (localtime_epoch as i64 + (t.timezone as i64) * SECS_IN_MINUTE as i64) as u64
+            adjusted_localtime_epoc
+                .checked_add_signed((t.timezone as i64) * SECS_IN_MINUTE as i64)
+                .unwrap()
         };
 
-        Duration::new(utc_epoch, t.nanosecond)
+        Duration::new(epoch, t.nanosecond)
+    }
+
+    /// This algorithm is a modifed version of the one described in the post:
+    /// https://howardhinnant.github.io/date_algorithms.html#clive_from_days
+    ///
+    /// The changes are to use 1900-01-01-00:00:00 with timezone -1440 as anchor instead of UNIX
+    /// epoch used in the original algorithm.
+    pub(crate) const fn to_uefi(dur: &Duration, timezone: i16, daylight: u8) -> Option<Time> {
+        // Check timzone validity
+        assert!(timezone <= 1440 && timezone >= -1440);
+
+        // FIXME(#126043): use checked_sub_signed once stablized
+        let secs =
+            dur.as_secs().checked_add_signed((-timezone as i64) * SECS_IN_MINUTE as i64).unwrap();
+
+        // Convert to seconds since 1900-01-01-00:00:00 in timezone.
+        let Some(secs) = secs.checked_sub(TIMEZONE_DELTA) else { return None };
+
+        let days = secs / SECS_IN_DAY;
+        let remaining_secs = secs % SECS_IN_DAY;
+
+        let z = days + 693901;
+        let era = z / 146097;
+        let doe = z - (era * 146097);
+        let yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
+        let mut y = yoe + era * 400;
+        let doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
+        let mp = (5 * doy + 2) / 153;
+        let d = doy - (153 * mp + 2) / 5 + 1;
+        let m = if mp < 10 { mp + 3 } else { mp - 9 };
+
+        if m <= 2 {
+            y += 1;
+        }
+
+        let hour = (remaining_secs / SECS_IN_HOUR) as u8;
+        let minute = ((remaining_secs % SECS_IN_HOUR) / SECS_IN_MINUTE) as u8;
+        let second = (remaining_secs % SECS_IN_MINUTE) as u8;
+
+        // Check Bounds
+        if y >= 1900 && y <= 9999 {
+            Some(Time {
+                year: y as u16,
+                month: m as u8,
+                day: d as u8,
+                hour,
+                minute,
+                second,
+                nanosecond: dur.subsec_nanos(),
+                timezone,
+                daylight,
+                pad1: 0,
+                pad2: 0,
+            })
+        } else {
+            None
+        }
     }
 }
 
diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs
index bd7f74fea6a..328fe0bc960 100644
--- a/library/std/src/sys/pal/unix/time.rs
+++ b/library/std/src/sys/pal/unix/time.rs
@@ -38,15 +38,18 @@ impl SystemTime {
         SystemTime { t: Timespec::now(libc::CLOCK_REALTIME) }
     }
 
-    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
         self.t.sub_timespec(&other.t)
     }
 
-    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime { t: self.t.checked_add_duration(other)? })
     }
 
-    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime { t: self.t.checked_sub_duration(other)? })
     }
 }
@@ -133,8 +136,15 @@ impl Timespec {
         Timespec::new(t.tv_sec as i64, t.tv_nsec as i64).unwrap()
     }
 
-    pub fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
-        if self >= other {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
+        // FIXME: const PartialOrd
+        let mut cmp = self.tv_sec - other.tv_sec;
+        if cmp == 0 {
+            cmp = self.tv_nsec.as_inner() as i64 - other.tv_nsec.as_inner() as i64;
+        }
+
+        if cmp >= 0 {
             // NOTE(eddyb) two aspects of this `if`-`else` are required for LLVM
             // to optimize it into a branchless form (see also #75545):
             //
@@ -169,7 +179,8 @@ impl Timespec {
         }
     }
 
-    pub fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> {
         let mut secs = self.tv_sec.checked_add_unsigned(other.as_secs())?;
 
         // Nano calculations can't overflow because nanos are <1B which fit
@@ -179,10 +190,11 @@ impl Timespec {
             nsec -= NSEC_PER_SEC as u32;
             secs = secs.checked_add(1)?;
         }
-        Some(unsafe { Timespec::new_unchecked(secs, nsec.into()) })
+        Some(unsafe { Timespec::new_unchecked(secs, nsec as i64) })
     }
 
-    pub fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> {
         let mut secs = self.tv_sec.checked_sub_unsigned(other.as_secs())?;
 
         // Similar to above, nanos can't overflow.
@@ -191,7 +203,7 @@ impl Timespec {
             nsec += NSEC_PER_SEC as i32;
             secs = secs.checked_sub(1)?;
         }
-        Some(unsafe { Timespec::new_unchecked(secs, nsec.into()) })
+        Some(unsafe { Timespec::new_unchecked(secs, nsec as i64) })
     }
 
     #[allow(dead_code)]
diff --git a/library/std/src/sys/pal/unsupported/time.rs b/library/std/src/sys/pal/unsupported/time.rs
index 6d67b538a96..0c387917044 100644
--- a/library/std/src/sys/pal/unsupported/time.rs
+++ b/library/std/src/sys/pal/unsupported/time.rs
@@ -31,15 +31,22 @@ impl SystemTime {
         panic!("time not implemented on this platform")
     }
 
-    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
-        self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+        // FIXME: ok_or_else with const closures
+        match self.0.checked_sub(other.0) {
+            Some(duration) => Ok(duration),
+            None => Err(other.0 - self.0),
+        }
     }
 
-    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_add(*other)?))
     }
 
-    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_sub(*other)?))
     }
 }
diff --git a/library/std/src/sys/pal/wasi/time.rs b/library/std/src/sys/pal/wasi/time.rs
index 0d8d0b59ac1..892661b312b 100644
--- a/library/std/src/sys/pal/wasi/time.rs
+++ b/library/std/src/sys/pal/wasi/time.rs
@@ -43,23 +43,34 @@ impl SystemTime {
         SystemTime(current_time(wasi::CLOCKID_REALTIME))
     }
 
-    pub fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn from_wasi_timestamp(ts: wasi::Timestamp) -> SystemTime {
         SystemTime(Duration::from_nanos(ts))
     }
 
-    pub fn to_wasi_timestamp(&self) -> Option<wasi::Timestamp> {
-        self.0.as_nanos().try_into().ok()
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn to_wasi_timestamp(&self) -> Option<wasi::Timestamp> {
+        // FIXME: const TryInto
+        let ns = self.0.as_nanos();
+        if ns <= u64::MAX as u128 { Some(ns as u64) } else { None }
     }
 
-    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
-        self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+        // FIXME: ok_or_else with const closures
+        match self.0.checked_sub(other.0) {
+            Some(duration) => Ok(duration),
+            None => Err(other.0 - self.0),
+        }
     }
 
-    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_add(*other)?))
     }
 
-    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_sub(*other)?))
     }
 }
diff --git a/library/std/src/sys/pal/windows/time.rs b/library/std/src/sys/pal/windows/time.rs
index 68126bd8d2f..a948c07e0a3 100644
--- a/library/std/src/sys/pal/windows/time.rs
+++ b/library/std/src/sys/pal/windows/time.rs
@@ -72,7 +72,8 @@ impl SystemTime {
         }
     }
 
-    fn from_intervals(intervals: i64) -> SystemTime {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    const fn from_intervals(intervals: i64) -> SystemTime {
         SystemTime {
             t: c::FILETIME {
                 dwLowDateTime: intervals as u32,
@@ -81,11 +82,13 @@ impl SystemTime {
         }
     }
 
-    fn intervals(&self) -> i64 {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    const fn intervals(&self) -> i64 {
         (self.t.dwLowDateTime as i64) | ((self.t.dwHighDateTime as i64) << 32)
     }
 
-    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
         let me = self.intervals();
         let other = other.intervals();
         if me >= other {
@@ -95,12 +98,14 @@ impl SystemTime {
         }
     }
 
-    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
         let intervals = self.intervals().checked_add(checked_dur2intervals(other)?)?;
         Some(SystemTime::from_intervals(intervals))
     }
 
-    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
         let intervals = self.intervals().checked_sub(checked_dur2intervals(other)?)?;
         Some(SystemTime::from_intervals(intervals))
     }
@@ -150,15 +155,18 @@ impl Hash for SystemTime {
     }
 }
 
-fn checked_dur2intervals(dur: &Duration) -> Option<i64> {
-    dur.as_secs()
+#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+const fn checked_dur2intervals(dur: &Duration) -> Option<i64> {
+    // FIXME: const TryInto
+    let secs = dur
+        .as_secs()
         .checked_mul(INTERVALS_PER_SEC)?
-        .checked_add(dur.subsec_nanos() as u64 / 100)?
-        .try_into()
-        .ok()
+        .checked_add(dur.subsec_nanos() as u64 / 100)?;
+    if secs <= i64::MAX as u64 { Some(secs.cast_signed()) } else { None }
 }
 
-fn intervals2dur(intervals: u64) -> Duration {
+#[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+const fn intervals2dur(intervals: u64) -> Duration {
     Duration::new(intervals / INTERVALS_PER_SEC, ((intervals % INTERVALS_PER_SEC) * 100) as u32)
 }
 
diff --git a/library/std/src/sys/pal/xous/time.rs b/library/std/src/sys/pal/xous/time.rs
index ae8be81c0b7..d737416436e 100644
--- a/library/std/src/sys/pal/xous/time.rs
+++ b/library/std/src/sys/pal/xous/time.rs
@@ -43,15 +43,22 @@ impl SystemTime {
         SystemTime { 0: Duration::from_millis((upper as u64) << 32 | lower as u64) }
     }
 
-    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
-        self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+        // FIXME: ok_or_else with const closures
+        match self.0.checked_sub(other.0) {
+            Some(duration) => Ok(duration),
+            None => Err(other.0 - self.0),
+        }
     }
 
-    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_add(*other)?))
     }
 
-    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
         Some(SystemTime(self.0.checked_sub(*other)?))
     }
 }
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index cd0683f44c9..07bb41f1496 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -551,8 +551,13 @@ impl SystemTime {
     /// println!("{difference:?}");
     /// ```
     #[stable(feature = "time2", since = "1.8.0")]
-    pub fn duration_since(&self, earlier: SystemTime) -> Result<Duration, SystemTimeError> {
-        self.0.sub_time(&earlier.0).map_err(SystemTimeError)
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn duration_since(&self, earlier: SystemTime) -> Result<Duration, SystemTimeError> {
+        // FIXME: map_err in const
+        match self.0.sub_time(&earlier.0) {
+            Ok(time) => Ok(time),
+            Err(err) => Err(SystemTimeError(err)),
+        }
     }
 
     /// Returns the difference from this system time to the
@@ -589,7 +594,8 @@ impl SystemTime {
     /// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None`
     /// otherwise.
     #[stable(feature = "time_checked_add", since = "1.34.0")]
-    pub fn checked_add(&self, duration: Duration) -> Option<SystemTime> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn checked_add(&self, duration: Duration) -> Option<SystemTime> {
         self.0.checked_add_duration(&duration).map(SystemTime)
     }
 
@@ -597,13 +603,15 @@ impl SystemTime {
     /// `SystemTime` (which means it's inside the bounds of the underlying data structure), `None`
     /// otherwise.
     #[stable(feature = "time_checked_add", since = "1.34.0")]
-    pub fn checked_sub(&self, duration: Duration) -> Option<SystemTime> {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn checked_sub(&self, duration: Duration) -> Option<SystemTime> {
         self.0.checked_sub_duration(&duration).map(SystemTime)
     }
 }
 
 #[stable(feature = "time2", since = "1.8.0")]
-impl Add<Duration> for SystemTime {
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+impl const Add<Duration> for SystemTime {
     type Output = SystemTime;
 
     /// # Panics
@@ -616,14 +624,16 @@ impl Add<Duration> for SystemTime {
 }
 
 #[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-impl AddAssign<Duration> for SystemTime {
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+impl const AddAssign<Duration> for SystemTime {
     fn add_assign(&mut self, other: Duration) {
         *self = *self + other;
     }
 }
 
 #[stable(feature = "time2", since = "1.8.0")]
-impl Sub<Duration> for SystemTime {
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+impl const Sub<Duration> for SystemTime {
     type Output = SystemTime;
 
     fn sub(self, dur: Duration) -> SystemTime {
@@ -632,7 +642,8 @@ impl Sub<Duration> for SystemTime {
 }
 
 #[stable(feature = "time_augmented_assignment", since = "1.9.0")]
-impl SubAssign<Duration> for SystemTime {
+#[rustc_const_unstable(feature = "const_ops", issue = "143802")]
+impl const SubAssign<Duration> for SystemTime {
     fn sub_assign(&mut self, other: Duration) {
         *self = *self - other;
     }
@@ -699,7 +710,8 @@ impl SystemTimeError {
     /// ```
     #[must_use]
     #[stable(feature = "time2", since = "1.8.0")]
-    pub fn duration(&self) -> Duration {
+    #[rustc_const_unstable(feature = "const_system_time", issue = "144517")]
+    pub const fn duration(&self) -> Duration {
         self.0
     }
 }
diff --git a/library/std/tests/path.rs b/library/std/tests/path.rs
index 901d2770f20..e1576a0d423 100644
--- a/library/std/tests/path.rs
+++ b/library/std/tests/path.rs
@@ -1,10 +1,4 @@
-#![feature(
-    clone_to_uninit,
-    path_add_extension,
-    path_file_prefix,
-    maybe_uninit_slice,
-    normalize_lexically
-)]
+#![feature(clone_to_uninit, path_add_extension, maybe_uninit_slice, normalize_lexically)]
 
 use std::clone::CloneToUninit;
 use std::ffi::OsStr;
diff --git a/library/test/src/cli.rs b/library/test/src/cli.rs
index 8840714a662..1b3f9e2564c 100644
--- a/library/test/src/cli.rs
+++ b/library/test/src/cli.rs
@@ -162,18 +162,17 @@ tests whose names contain the filter are run. Multiple filter strings may
 be passed, which will run all tests matching any of the filters.
 
 By default, all tests are run in parallel. This can be altered with the
---test-threads flag or the RUST_TEST_THREADS environment variable when running
-tests (set it to 1).
+--test-threads flag when running tests (set it to 1).
 
-By default, the tests are run in alphabetical order. Use --shuffle or set
-RUST_TEST_SHUFFLE to run the tests in random order. Pass the generated
-"shuffle seed" to --shuffle-seed (or set RUST_TEST_SHUFFLE_SEED) to run the
-tests in the same order again. Note that --shuffle and --shuffle-seed do not
-affect whether the tests are run in parallel.
+By default, the tests are run in alphabetical order. Use --shuffle to run
+the tests in random order. Pass the generated "shuffle seed" to
+--shuffle-seed to run the tests in the same order again. Note that
+--shuffle and --shuffle-seed do not affect whether the tests are run in
+parallel.
 
 All tests have their standard output and standard error captured by default.
-This can be overridden with the --no-capture flag or setting RUST_TEST_NOCAPTURE
-environment variable to a value other than "0". Logging is not captured by default.
+This can be overridden with the --no-capture flag to a value other than "0".
+Logging is not captured by default.
 
 Test Attributes:
 
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index e091c94eb53..044d360ac37 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -730,9 +730,9 @@ dependencies = [
 
 [[package]]
 name = "sysinfo"
-version = "0.36.0"
+version = "0.37.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aab138f5c1bb35231de19049060a87977ad23e04f2303e953bc5c2947ac7dec4"
+checksum = "07cec4dc2d2e357ca1e610cfb07de2fa7a10fc3e9fe89f72545f3d244ea87753"
 dependencies = [
  "libc",
  "memchr",
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index 8dc41d1dec6..60d4976b934 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -58,7 +58,7 @@ walkdir = "2.4"
 xz2 = "0.1"
 
 # Dependencies needed by the build-metrics feature
-sysinfo = { version = "0.36.0", default-features = false, optional = true, features = ["system"] }
+sysinfo = { version = "0.37.0", default-features = false, optional = true, features = ["system"] }
 
 # Dependencies needed by the `tracing` feature
 tracing = { version = "0.1", optional = true, features = ["attributes"] }
diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs
index 0364c664ba5..5865df67b66 100644
--- a/src/bootstrap/src/bin/rustc.rs
+++ b/src/bootstrap/src/bin/rustc.rs
@@ -258,7 +258,7 @@ fn main() {
         eprintln!("{prefix} libdir: {libdir:?}");
     }
 
-    maybe_dump(format!("stage{stage}-rustc"), &cmd);
+    maybe_dump(format!("stage{}-rustc", stage + 1), &cmd);
 
     let start = Instant::now();
     let (child, status) = {
diff --git a/src/bootstrap/src/bin/rustdoc.rs b/src/bootstrap/src/bin/rustdoc.rs
index a338b9c8080..efb51bdce1e 100644
--- a/src/bootstrap/src/bin/rustdoc.rs
+++ b/src/bootstrap/src/bin/rustdoc.rs
@@ -56,11 +56,11 @@ fn main() {
     // Thus, if we are on stage 0, we explicitly set `--cfg=bootstrap`.
     // We also declare that the flag is expected, which we need to do to not
     // get warnings about it being unexpected.
-    if stage == "0" {
+    if stage == 0 {
         cmd.arg("--cfg=bootstrap");
     }
 
-    maybe_dump(format!("stage{stage}-rustdoc"), &cmd);
+    maybe_dump(format!("stage{}-rustdoc", stage + 1), &cmd);
 
     if verbose > 1 {
         eprintln!(
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index f931aae3c2e..0cbf8f55e99 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -72,7 +72,6 @@ impl Step for Std {
 
     fn run(self, builder: &Builder<'_>) {
         let build_compiler = self.build_compiler;
-        let stage = build_compiler.stage;
         let target = self.target;
 
         let mut cargo = builder::Cargo::new(
@@ -94,10 +93,12 @@ impl Step for Std {
             cargo.arg("-p").arg(krate);
         }
 
-        let _guard = builder.msg_check(
+        let _guard = builder.msg(
+            Kind::Check,
             format_args!("library artifacts{}", crate_description(&self.crates)),
+            Mode::Std,
+            self.build_compiler,
             target,
-            Some(stage),
         );
 
         let stamp = build_stamp::libstd_stamp(builder, build_compiler, target).with_prefix("check");
@@ -136,7 +137,13 @@ impl Step for Std {
 
         let stamp =
             build_stamp::libstd_stamp(builder, build_compiler, target).with_prefix("check-test");
-        let _guard = builder.msg_check("library test/bench/example targets", target, Some(stage));
+        let _guard = builder.msg(
+            Kind::Check,
+            "library test/bench/example targets",
+            Mode::Std,
+            self.build_compiler,
+            target,
+        );
         run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
     }
 
@@ -227,10 +234,12 @@ impl Step for Rustc {
             cargo.arg("-p").arg(krate);
         }
 
-        let _guard = builder.msg_check(
+        let _guard = builder.msg(
+            Kind::Check,
             format_args!("compiler artifacts{}", crate_description(&self.crates)),
+            Mode::Rustc,
+            self.build_compiler,
             target,
-            None,
         );
 
         let stamp =
@@ -357,7 +366,13 @@ impl Step for CodegenBackend {
             .arg(builder.src.join(format!("compiler/{}/Cargo.toml", backend.crate_name())));
         rustc_cargo_env(builder, &mut cargo, target);
 
-        let _guard = builder.msg_check(backend.crate_name(), target, None);
+        let _guard = builder.msg(
+            Kind::Check,
+            backend.crate_name(),
+            Mode::Codegen,
+            self.build_compiler,
+            target,
+        );
 
         let stamp = build_stamp::codegen_backend_stamp(builder, build_compiler, target, &backend)
             .with_prefix("check");
@@ -482,14 +497,7 @@ fn run_tool_check_step(
     let stamp = BuildStamp::new(&builder.cargo_out(build_compiler, mode, target))
         .with_prefix(&format!("{display_name}-check"));
 
-    let stage = match mode {
-        // Mode::ToolRustc is included here because of how msg_sysroot_tool prints stages
-        Mode::Std | Mode::ToolRustc => build_compiler.stage,
-        _ => build_compiler.stage + 1,
-    };
-
-    let _guard =
-        builder.msg_tool(builder.kind, mode, display_name, stage, &build_compiler.host, &target);
+    let _guard = builder.msg(builder.kind, display_name, mode, build_compiler, target);
     run_cargo(builder, cargo, builder.config.free_args.clone(), &stamp, vec![], true, false);
 }
 
diff --git a/src/bootstrap/src/core/build_steps/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs
index f67569d1486..8712aeb81eb 100644
--- a/src/bootstrap/src/core/build_steps/clean.rs
+++ b/src/bootstrap/src/core/build_steps/clean.rs
@@ -129,7 +129,7 @@ fn clean_specific_stage(build: &Build, stage: u32) {
 
         for entry in entries {
             let entry = t!(entry);
-            let stage_prefix = format!("stage{stage}");
+            let stage_prefix = format!("stage{}", stage + 1);
 
             // if current entry is not related with the target stage, continue
             if !entry.file_name().to_str().unwrap_or("").contains(&stage_prefix) {
diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs
index 93c767bdd25..4d734fe5c66 100644
--- a/src/bootstrap/src/core/build_steps/clippy.rs
+++ b/src/bootstrap/src/core/build_steps/clippy.rs
@@ -143,11 +143,11 @@ impl Step for Std {
 
     fn run(self, builder: &Builder<'_>) {
         let target = self.target;
-        let compiler = builder.compiler(builder.top_stage, builder.config.host_target);
+        let build_compiler = builder.compiler(builder.top_stage, builder.config.host_target);
 
         let mut cargo = builder::Cargo::new(
             builder,
-            compiler,
+            build_compiler,
             Mode::Std,
             SourceType::InTree,
             target,
@@ -160,14 +160,19 @@ impl Step for Std {
             cargo.arg("-p").arg(krate);
         }
 
-        let _guard =
-            builder.msg_clippy(format_args!("library{}", crate_description(&self.crates)), target);
+        let _guard = builder.msg(
+            Kind::Clippy,
+            format_args!("library{}", crate_description(&self.crates)),
+            Mode::Std,
+            build_compiler,
+            target,
+        );
 
         run_cargo(
             builder,
             cargo,
             lint_args(builder, &self.config, IGNORED_RULES_FOR_STD_AND_RUSTC),
-            &build_stamp::libstd_stamp(builder, compiler, target),
+            &build_stamp::libstd_stamp(builder, build_compiler, target),
             vec![],
             true,
             false,
@@ -203,33 +208,33 @@ 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.host_target);
+        let build_compiler = builder.compiler(builder.top_stage, builder.config.host_target);
         let target = self.target;
 
         if !builder.download_rustc() {
-            if compiler.stage != 0 {
+            if build_compiler.stage != 0 {
                 // If we're not in stage 0, then we won't have a std from the beta
                 // compiler around. That means we need to make sure there's one in
                 // the sysroot for the compiler to find. Otherwise, we're going to
                 // fail when building crates that need to generate code (e.g., build
                 // scripts and their dependencies).
-                builder.std(compiler, compiler.host);
-                builder.std(compiler, target);
+                builder.std(build_compiler, build_compiler.host);
+                builder.std(build_compiler, target);
             } else {
-                builder.ensure(check::Std::new(compiler, target));
+                builder.ensure(check::Std::new(build_compiler, target));
             }
         }
 
         let mut cargo = builder::Cargo::new(
             builder,
-            compiler,
+            build_compiler,
             Mode::Rustc,
             SourceType::InTree,
             target,
             Kind::Clippy,
         );
 
-        rustc_cargo(builder, &mut cargo, target, &compiler, &self.crates);
+        rustc_cargo(builder, &mut cargo, target, &build_compiler, &self.crates);
 
         // Explicitly pass -p for all compiler crates -- this will force cargo
         // to also lint the tests/benches/examples for these crates, rather
@@ -238,14 +243,19 @@ impl Step for Rustc {
             cargo.arg("-p").arg(krate);
         }
 
-        let _guard =
-            builder.msg_clippy(format_args!("compiler{}", crate_description(&self.crates)), target);
+        let _guard = builder.msg(
+            Kind::Clippy,
+            format_args!("compiler{}", crate_description(&self.crates)),
+            Mode::Rustc,
+            build_compiler,
+            target,
+        );
 
         run_cargo(
             builder,
             cargo,
             lint_args(builder, &self.config, IGNORED_RULES_FOR_STD_AND_RUSTC),
-            &build_stamp::librustc_stamp(builder, compiler, target),
+            &build_stamp::librustc_stamp(builder, build_compiler, target),
             vec![],
             true,
             false,
@@ -284,16 +294,16 @@ macro_rules! lint_any {
             }
 
             fn run(self, builder: &Builder<'_>) -> Self::Output {
-                let compiler = builder.compiler(builder.top_stage, builder.config.host_target);
+                let build_compiler = builder.compiler(builder.top_stage, builder.config.host_target);
                 let target = self.target;
 
                 if !builder.download_rustc() {
-                    builder.ensure(check::Rustc::new(builder, compiler, target));
+                    builder.ensure(check::Rustc::new(builder, build_compiler, target));
                 };
 
                 let cargo = prepare_tool_cargo(
                     builder,
-                    compiler,
+                    build_compiler,
                     Mode::ToolRustc,
                     target,
                     Kind::Clippy,
@@ -302,17 +312,16 @@ macro_rules! lint_any {
                     &[],
                 );
 
-                let _guard = builder.msg_tool(
+                let _guard = builder.msg(
                     Kind::Clippy,
-                    Mode::ToolRustc,
                     $readable_name,
-                    compiler.stage,
-                    &compiler.host,
-                    &target,
+                    Mode::ToolRustc,
+                    build_compiler,
+                    target,
                 );
 
                 let stringified_name = stringify!($name).to_lowercase();
-                let stamp = BuildStamp::new(&builder.cargo_out(compiler, Mode::ToolRustc, target))
+                let stamp = BuildStamp::new(&builder.cargo_out(build_compiler, Mode::ToolRustc, target))
                     .with_prefix(&format!("{}-check", stringified_name));
 
                 run_cargo(
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 79174eb281f..2a236de0192 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -18,7 +18,7 @@ use serde_derive::Deserialize;
 #[cfg(feature = "tracing")]
 use tracing::{instrument, span};
 
-use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags};
+use crate::core::build_steps::gcc::{Gcc, GccOutput, add_cg_gcc_cargo_flags};
 use crate::core::build_steps::tool::{RustcPrivateCompilers, SourceType, copy_lld_artifacts};
 use crate::core::build_steps::{dist, llvm};
 use crate::core::builder;
@@ -159,7 +159,7 @@ impl Step for Std {
             return;
         }
 
-        let compiler = if builder.download_rustc() && self.force_recompile {
+        let build_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.host_target)
@@ -173,7 +173,8 @@ impl Step for Std {
             && builder.config.is_host_target(target)
             && !self.force_recompile
         {
-            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,
@@ -182,53 +183,58 @@ impl Step for Std {
             return;
         }
 
-        if builder.config.keep_stage.contains(&compiler.stage)
-            || builder.config.keep_stage_std.contains(&compiler.stage)
+        if builder.config.keep_stage.contains(&build_compiler.stage)
+            || builder.config.keep_stage_std.contains(&build_compiler.stage)
         {
             trace!(keep_stage = ?builder.config.keep_stage);
             trace!(keep_stage_std = ?builder.config.keep_stage_std);
 
             builder.info("WARNING: Using a potentially old libstd. This may not behave well.");
 
-            builder.ensure(StartupObjects { compiler, target });
+            builder.ensure(StartupObjects { compiler: build_compiler, target });
 
-            self.copy_extra_objects(builder, &compiler, target);
+            self.copy_extra_objects(builder, &build_compiler, target);
 
-            builder.ensure(StdLink::from_std(self, compiler));
+            builder.ensure(StdLink::from_std(self, build_compiler));
             return;
         }
 
-        let mut target_deps = builder.ensure(StartupObjects { compiler, target });
+        let mut target_deps = builder.ensure(StartupObjects { compiler: build_compiler, target });
 
-        let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
+        let compiler_to_use =
+            builder.compiler_for(build_compiler.stage, build_compiler.host, target);
         trace!(?compiler_to_use);
 
-        if compiler_to_use != compiler
+        if compiler_to_use != build_compiler
             // Never uplift std unless we have compiled stage 1; if stage 1 is compiled,
             // uplift it from there.
             //
             // FIXME: improve `fn compiler_for` to avoid adding stage condition here.
-            && compiler.stage > 1
+            && build_compiler.stage > 1
         {
-            trace!(?compiler_to_use, ?compiler, "compiler != compiler_to_use, uplifting library");
+            trace!(
+                ?compiler_to_use,
+                ?build_compiler,
+                "build_compiler != compiler_to_use, uplifting library"
+            );
 
             builder.std(compiler_to_use, target);
             let msg = if compiler_to_use.host == target {
                 format!(
                     "Uplifting library (stage{} -> stage{})",
-                    compiler_to_use.stage, compiler.stage
+                    compiler_to_use.stage, build_compiler.stage
                 )
             } else {
                 format!(
                     "Uplifting library (stage{}:{} -> stage{}:{})",
-                    compiler_to_use.stage, compiler_to_use.host, compiler.stage, target
+                    compiler_to_use.stage, compiler_to_use.host, build_compiler.stage, target
                 )
             };
             builder.info(&msg);
 
             // Even if we're not building std this stage, the new sysroot must
             // still contain the third party objects needed by various targets.
-            self.copy_extra_objects(builder, &compiler, target);
+            self.copy_extra_objects(builder, &build_compiler, target);
 
             builder.ensure(StdLink::from_std(self, compiler_to_use));
             return;
@@ -236,11 +242,11 @@ impl Step for Std {
 
         trace!(
             ?compiler_to_use,
-            ?compiler,
+            ?build_compiler,
             "compiler == compiler_to_use, handling not-cross-compile scenario"
         );
 
-        target_deps.extend(self.copy_extra_objects(builder, &compiler, target));
+        target_deps.extend(self.copy_extra_objects(builder, &build_compiler, target));
 
         // We build a sysroot for mir-opt tests using the same trick that Miri does: A check build
         // with -Zalways-encode-mir. This frees us from the need to have a target linker, and the
@@ -249,7 +255,7 @@ impl Step for Std {
             trace!("building special sysroot for mir-opt tests");
             let mut cargo = builder::Cargo::new_for_mir_opt_tests(
                 builder,
-                compiler,
+                build_compiler,
                 Mode::Std,
                 SourceType::InTree,
                 target,
@@ -262,7 +268,7 @@ impl Step for Std {
             trace!("building regular sysroot");
             let mut cargo = builder::Cargo::new(
                 builder,
-                compiler,
+                build_compiler,
                 Mode::Std,
                 SourceType::InTree,
                 target,
@@ -285,16 +291,16 @@ impl Step for Std {
 
         let _guard = builder.msg(
             Kind::Build,
-            compiler.stage,
             format_args!("library artifacts{}", crate_description(&self.crates)),
-            compiler.host,
+            Mode::Std,
+            build_compiler,
             target,
         );
         run_cargo(
             builder,
             cargo,
             vec![],
-            &build_stamp::libstd_stamp(builder, compiler, target),
+            &build_stamp::libstd_stamp(builder, build_compiler, target),
             target_deps,
             self.is_for_mir_opt_tests, // is_check
             false,
@@ -302,7 +308,7 @@ impl Step for Std {
 
         builder.ensure(StdLink::from_std(
             self,
-            builder.compiler(compiler.stage, builder.config.host_target),
+            builder.compiler(build_compiler.stage, builder.config.host_target),
         ));
     }
 
@@ -1126,11 +1132,11 @@ impl Step for Rustc {
             cargo.env("RUSTC_BOLT_LINK_FLAGS", "1");
         }
 
-        let _guard = builder.msg_rustc_tool(
+        let _guard = builder.msg(
             Kind::Build,
-            build_compiler.stage,
             format_args!("compiler artifacts{}", crate_description(&self.crates)),
-            build_compiler.host,
+            Mode::Rustc,
+            build_compiler,
             target,
         );
         let stamp = build_stamp::librustc_stamp(builder, build_compiler, target);
@@ -1537,13 +1543,22 @@ impl Step for RustcLink {
     }
 }
 
+/// Output of the `compile::GccCodegenBackend` step.
+/// It includes the path to the libgccjit library on which this backend depends.
+#[derive(Clone)]
+pub struct GccCodegenBackendOutput {
+    stamp: BuildStamp,
+    gcc: GccOutput,
+}
+
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct GccCodegenBackend {
     compilers: RustcPrivateCompilers,
 }
 
 impl Step for GccCodegenBackend {
-    type Output = BuildStamp;
+    type Output = GccCodegenBackendOutput;
+
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
@@ -1578,6 +1593,8 @@ impl Step for GccCodegenBackend {
             &CodegenBackendKind::Gcc,
         );
 
+        let gcc = builder.ensure(Gcc { target });
+
         if builder.config.keep_stage.contains(&build_compiler.stage) {
             trace!("`keep-stage` requested");
             builder.info(
@@ -1586,7 +1603,7 @@ impl Step for GccCodegenBackend {
             );
             // Codegen backends are linked separately from this step today, so we don't do
             // anything here.
-            return stamp;
+            return GccCodegenBackendOutput { stamp, gcc };
         }
 
         let mut cargo = builder::Cargo::new(
@@ -1600,18 +1617,16 @@ impl Step for GccCodegenBackend {
         cargo.arg("--manifest-path").arg(builder.src.join("compiler/rustc_codegen_gcc/Cargo.toml"));
         rustc_cargo_env(builder, &mut cargo, target);
 
-        let gcc = builder.ensure(Gcc { target });
         add_cg_gcc_cargo_flags(&mut cargo, &gcc);
 
-        let _guard = builder.msg_rustc_tool(
-            Kind::Build,
-            build_compiler.stage,
-            "codegen backend gcc",
-            build_compiler.host,
-            target,
-        );
+        let _guard =
+            builder.msg(Kind::Build, "codegen backend gcc", Mode::Codegen, build_compiler, target);
         let files = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false);
-        write_codegen_backend_stamp(stamp, files, builder.config.dry_run())
+
+        GccCodegenBackendOutput {
+            stamp: write_codegen_backend_stamp(stamp, files, builder.config.dry_run()),
+            gcc,
+        }
     }
 
     fn metadata(&self) -> Option<StepMetadata> {
@@ -1687,11 +1702,11 @@ impl Step for CraneliftCodegenBackend {
             .arg(builder.src.join("compiler/rustc_codegen_cranelift/Cargo.toml"));
         rustc_cargo_env(builder, &mut cargo, target);
 
-        let _guard = builder.msg_rustc_tool(
+        let _guard = builder.msg(
             Kind::Build,
-            build_compiler.stage,
             "codegen backend cranelift",
-            build_compiler.host,
+            Mode::Codegen,
+            build_compiler,
             target,
         );
         let files = run_cargo(builder, cargo, vec![], &stamp, vec![], false, false);
@@ -1761,20 +1776,30 @@ fn copy_codegen_backends_to_sysroot(
     }
 
     if stamp.path().exists() {
-        let dylib = t!(fs::read_to_string(stamp.path()));
-        let file = Path::new(&dylib);
-        let filename = file.file_name().unwrap().to_str().unwrap();
-        // change `librustc_codegen_cranelift-xxxxxx.so` to
-        // `librustc_codegen_cranelift-release.so`
-        let target_filename = {
-            let dash = filename.find('-').unwrap();
-            let dot = filename.find('.').unwrap();
-            format!("{}-{}{}", &filename[..dash], builder.rust_release(), &filename[dot..])
-        };
-        builder.copy_link(file, &dst.join(target_filename), FileType::NativeLibrary);
+        let file = get_codegen_backend_file(&stamp);
+        builder.copy_link(
+            &file,
+            &dst.join(normalize_codegen_backend_name(builder, &file)),
+            FileType::NativeLibrary,
+        );
     }
 }
 
+/// Gets the path to a dynamic codegen backend library from its build stamp.
+pub fn get_codegen_backend_file(stamp: &BuildStamp) -> PathBuf {
+    PathBuf::from(t!(fs::read_to_string(stamp.path())))
+}
+
+/// Normalize the name of a dynamic codegen backend library.
+pub fn normalize_codegen_backend_name(builder: &Builder<'_>, path: &Path) -> String {
+    let filename = path.file_name().unwrap().to_str().unwrap();
+    // change e.g. `librustc_codegen_cranelift-xxxxxx.so` to
+    // `librustc_codegen_cranelift-release.so`
+    let dash = filename.find('-').unwrap();
+    let dot = filename.find('.').unwrap();
+    format!("{}-{}{}", &filename[..dash], builder.rust_release(), &filename[dot..])
+}
+
 pub fn compiler_file(
     builder: &Builder<'_>,
     compiler: &Path,
@@ -2180,53 +2205,6 @@ impl Step for Assemble {
         );
         build_compiler.stage = actual_stage;
 
-        let mut codegen_backend_stamps = vec![];
-        {
-            #[cfg(feature = "tracing")]
-            let _codegen_backend_span =
-                span!(tracing::Level::DEBUG, "building requested codegen backends").entered();
-
-            for backend in builder.config.enabled_codegen_backends(target_compiler.host) {
-                // FIXME: this is a horrible hack used to make `x check` work when other codegen
-                // backends are enabled.
-                // `x check` will check stage 1 rustc, which copies its rmetas to the stage0 sysroot.
-                // Then it checks codegen backends, which correctly use these rmetas.
-                // Then it needs to check std, but for that it needs to build stage 1 rustc.
-                // This copies the build rmetas into the stage0 sysroot, effectively poisoning it,
-                // because we then have both check and build rmetas in the same sysroot.
-                // That would be fine on its own. However, when another codegen backend is enabled,
-                // then building stage 1 rustc implies also building stage 1 codegen backend (even if
-                // it isn't used for anything). And since that tries to use the poisoned
-                // rmetas, it fails to build.
-                // We don't actually need to build rustc-private codegen backends for checking std,
-                // so instead we skip that.
-                // Note: this would be also an issue for other rustc-private tools, but that is "solved"
-                // by check::Std being last in the list of checked things (see
-                // `Builder::get_step_descriptions`).
-                if builder.kind == Kind::Check && builder.top_stage == 1 {
-                    continue;
-                }
-
-                let prepare_compilers = || {
-                    RustcPrivateCompilers::from_build_and_target_compiler(
-                        build_compiler,
-                        target_compiler,
-                    )
-                };
-
-                let stamp = match backend {
-                    CodegenBackendKind::Cranelift => {
-                        builder.ensure(CraneliftCodegenBackend { compilers: prepare_compilers() })
-                    }
-                    CodegenBackendKind::Gcc => {
-                        builder.ensure(GccCodegenBackend { compilers: prepare_compilers() })
-                    }
-                    CodegenBackendKind::Llvm | CodegenBackendKind::Custom(_) => continue,
-                };
-                codegen_backend_stamps.push(stamp);
-            }
-        }
-
         let stage = target_compiler.stage;
         let host = target_compiler.host;
         let (host_info, dir_name) = if build_compiler.host == host {
@@ -2285,9 +2263,56 @@ impl Step for Assemble {
             }
         }
 
-        debug!("copying codegen backends to sysroot");
-        for stamp in codegen_backend_stamps {
-            copy_codegen_backends_to_sysroot(builder, stamp, target_compiler);
+        {
+            #[cfg(feature = "tracing")]
+            let _codegen_backend_span =
+                span!(tracing::Level::DEBUG, "building requested codegen backends").entered();
+
+            for backend in builder.config.enabled_codegen_backends(target_compiler.host) {
+                // FIXME: this is a horrible hack used to make `x check` work when other codegen
+                // backends are enabled.
+                // `x check` will check stage 1 rustc, which copies its rmetas to the stage0 sysroot.
+                // Then it checks codegen backends, which correctly use these rmetas.
+                // Then it needs to check std, but for that it needs to build stage 1 rustc.
+                // This copies the build rmetas into the stage0 sysroot, effectively poisoning it,
+                // because we then have both check and build rmetas in the same sysroot.
+                // That would be fine on its own. However, when another codegen backend is enabled,
+                // then building stage 1 rustc implies also building stage 1 codegen backend (even if
+                // it isn't used for anything). And since that tries to use the poisoned
+                // rmetas, it fails to build.
+                // We don't actually need to build rustc-private codegen backends for checking std,
+                // so instead we skip that.
+                // Note: this would be also an issue for other rustc-private tools, but that is "solved"
+                // by check::Std being last in the list of checked things (see
+                // `Builder::get_step_descriptions`).
+                if builder.kind == Kind::Check && builder.top_stage == 1 {
+                    continue;
+                }
+
+                let prepare_compilers = || {
+                    RustcPrivateCompilers::from_build_and_target_compiler(
+                        build_compiler,
+                        target_compiler,
+                    )
+                };
+
+                match backend {
+                    CodegenBackendKind::Cranelift => {
+                        let stamp = builder
+                            .ensure(CraneliftCodegenBackend { compilers: prepare_compilers() });
+                        copy_codegen_backends_to_sysroot(builder, stamp, target_compiler);
+                    }
+                    CodegenBackendKind::Gcc => {
+                        let output =
+                            builder.ensure(GccCodegenBackend { compilers: prepare_compilers() });
+                        copy_codegen_backends_to_sysroot(builder, output.stamp, target_compiler);
+                        // Also copy libgccjit to the library sysroot, so that it is available for
+                        // the codegen backend.
+                        output.gcc.install_to(builder, &rustc_libdir);
+                    }
+                    CodegenBackendKind::Llvm | CodegenBackendKind::Custom(_) => continue,
+                }
+            }
         }
 
         if builder.config.lld_enabled {
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 727533dc5fd..7fdfeabe29d 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -19,6 +19,7 @@ use object::read::archive::ArchiveFile;
 #[cfg(feature = "tracing")]
 use tracing::instrument;
 
+use crate::core::build_steps::compile::{get_codegen_backend_file, normalize_codegen_backend_name};
 use crate::core::build_steps::doc::DocumentationFormat;
 use crate::core::build_steps::tool::{self, RustcPrivateCompilers, Tool};
 use crate::core::build_steps::vendor::{VENDOR_DIR, Vendor};
@@ -477,7 +478,19 @@ impl Step for Rustc {
             if libdir_relative.to_str() != Some("bin") {
                 let libdir = builder.rustc_libdir(compiler);
                 for entry in builder.read_dir(&libdir) {
-                    if is_dylib(&entry.path()) {
+                    // A safeguard that we will not ship libgccjit.so from the libdir, in case the
+                    // GCC codegen backend is enabled by default.
+                    // Long-term we should probably split the config options for:
+                    // - Include cg_gcc in the rustc sysroot by default
+                    // - Run dist of a specific codegen backend in `x dist` by default
+                    if is_dylib(&entry.path())
+                        && !entry
+                            .path()
+                            .file_name()
+                            .and_then(|n| n.to_str())
+                            .map(|n| n.contains("libgccjit"))
+                            .unwrap_or(false)
+                    {
                         // Don't use custom libdir here because ^lib/ will be resolved again
                         // with installer
                         builder.install(&entry.path(), &image.join("lib"), FileType::NativeLibrary);
@@ -1409,6 +1422,7 @@ impl Step for Miri {
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub struct CraneliftCodegenBackend {
     pub build_compiler: Compiler,
+    pub target: TargetSelection,
 }
 
 impl Step for CraneliftCodegenBackend {
@@ -1436,6 +1450,7 @@ impl Step for CraneliftCodegenBackend {
                 run.builder.config.host_target,
                 run.target,
             ),
+            target: run.target,
         });
     }
 
@@ -1447,7 +1462,7 @@ impl Step for CraneliftCodegenBackend {
             return None;
         }
 
-        let target = self.build_compiler.host;
+        let target = self.target;
         let compilers =
             RustcPrivateCompilers::from_build_compiler(builder, self.build_compiler, target);
         if !target_supports_cranelift_backend(target) {
@@ -1460,35 +1475,29 @@ impl Step for CraneliftCodegenBackend {
         tarball.is_preview(true);
         tarball.add_legal_and_readme_to("share/doc/rustc_codegen_cranelift");
 
-        builder.ensure(compile::CraneliftCodegenBackend { compilers });
+        let stamp = builder.ensure(compile::CraneliftCodegenBackend { compilers });
 
         if builder.config.dry_run() {
             return None;
         }
 
-        let src = builder.sysroot(self.build_compiler);
-        let backends_src = builder.sysroot_codegen_backends(self.build_compiler);
-        let backends_rel = backends_src
-            .strip_prefix(src)
+        // Get the relative path of where the codegen backend should be stored.
+        let backends_dst = builder.sysroot_codegen_backends(compilers.target_compiler());
+        let backends_rel = backends_dst
+            .strip_prefix(builder.sysroot(compilers.target_compiler()))
             .unwrap()
-            .strip_prefix(builder.sysroot_libdir_relative(self.build_compiler))
+            .strip_prefix(builder.sysroot_libdir_relative(compilers.target_compiler()))
             .unwrap();
         // Don't use custom libdir here because ^lib/ will be resolved again with installer
         let backends_dst = PathBuf::from("lib").join(backends_rel);
 
-        let mut found_backend = false;
-        for backend in fs::read_dir(&backends_src).unwrap() {
-            let file_name = backend.unwrap().file_name();
-            if file_name.to_str().unwrap().contains("rustc_codegen_cranelift") {
-                tarball.add_file(
-                    backends_src.join(file_name),
-                    &backends_dst,
-                    FileType::NativeLibrary,
-                );
-                found_backend = true;
-            }
-        }
-        assert!(found_backend);
+        let codegen_backend_dylib = get_codegen_backend_file(&stamp);
+        tarball.add_renamed_file(
+            &codegen_backend_dylib,
+            &backends_dst,
+            &normalize_codegen_backend_name(builder, &codegen_backend_dylib),
+            FileType::NativeLibrary,
+        );
 
         Some(tarball.generate())
     }
@@ -1613,6 +1622,7 @@ impl Step for Extended {
         add_component!("analysis" => Analysis { compiler, target });
         add_component!("rustc-codegen-cranelift" => CraneliftCodegenBackend {
             build_compiler: compiler,
+            target
         });
         add_component!("llvm-bitcode-linker" => LlvmBitcodeLinker {
             build_compiler: compiler,
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index ca7a6dc8e07..6f0d5203d11 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -239,7 +239,7 @@ impl Step for TheBook {
     fn run(self, builder: &Builder<'_>) {
         builder.require_submodule("src/doc/book", None);
 
-        let compiler = self.build_compiler;
+        let build_compiler = self.build_compiler;
         let target = self.target;
 
         let absolute_path = builder.src.join("src/doc/book");
@@ -273,20 +273,20 @@ impl Step for TheBook {
         let shared_assets = builder.ensure(SharedAssets { target });
 
         // build the redirect pages
-        let _guard = builder.msg_doc(compiler, "book redirect pages", target);
+        let _guard = builder.msg(Kind::Doc, "book redirect pages", None, build_compiler, target);
         for file in t!(fs::read_dir(redirect_path)) {
             let file = t!(file);
             let path = file.path();
             let path = path.to_str().unwrap();
 
-            invoke_rustdoc(builder, compiler, &shared_assets, target, path);
+            invoke_rustdoc(builder, build_compiler, &shared_assets, target, path);
         }
     }
 }
 
 fn invoke_rustdoc(
     builder: &Builder<'_>,
-    compiler: Compiler,
+    build_compiler: Compiler,
     shared_assets: &SharedAssetsPaths,
     target: TargetSelection,
     markdown: &str,
@@ -298,7 +298,7 @@ fn invoke_rustdoc(
     let header = builder.src.join("src/doc/redirect.inc");
     let footer = builder.src.join("src/doc/footer.inc");
 
-    let mut cmd = builder.rustdoc_cmd(compiler);
+    let mut cmd = builder.rustdoc_cmd(build_compiler);
 
     let out = out.join("book");
 
@@ -362,7 +362,7 @@ impl Step for Standalone {
     fn run(self, builder: &Builder<'_>) {
         let target = self.target;
         let build_compiler = self.build_compiler;
-        let _guard = builder.msg_doc(build_compiler, "standalone", target);
+        let _guard = builder.msg(Kind::Doc, "standalone", None, build_compiler, target);
         let out = builder.doc_out(target);
         t!(fs::create_dir_all(&out));
 
@@ -469,7 +469,7 @@ impl Step for Releases {
     fn run(self, builder: &Builder<'_>) {
         let target = self.target;
         let build_compiler = self.build_compiler;
-        let _guard = builder.msg_doc(build_compiler, "releases", target);
+        let _guard = builder.msg(Kind::Doc, "releases", None, build_compiler, target);
         let out = builder.doc_out(target);
         t!(fs::create_dir_all(&out));
 
@@ -784,7 +784,7 @@ fn doc_std(
 
     let description =
         format!("library{} in {} format", crate_description(requested_crates), format.as_str());
-    let _guard = builder.msg_doc(build_compiler, description, target);
+    let _guard = builder.msg(Kind::Doc, description, None, build_compiler, target);
 
     cargo.into_cmd().run(builder);
     builder.cp_link_r(&out_dir, out);
@@ -861,11 +861,11 @@ impl Step for Rustc {
         let build_compiler = self.build_compiler;
         builder.std(build_compiler, builder.config.host_target);
 
-        let _guard = builder.msg_rustc_tool(
+        let _guard = builder.msg(
             Kind::Doc,
-            build_compiler.stage,
             format!("compiler{}", crate_description(&self.crates)),
-            build_compiler.host,
+            Mode::Rustc,
+            build_compiler,
             target,
         );
 
@@ -1059,7 +1059,7 @@ macro_rules! tool_doc {
                 let proc_macro_out_dir = builder.stage_out(build_compiler, mode).join("doc");
                 symlink_dir_force(&builder.config, &out, &proc_macro_out_dir);
 
-                let _guard = builder.msg_doc(build_compiler, stringify!($tool).to_lowercase(), target);
+                let _guard = builder.msg(Kind::Doc, stringify!($tool).to_lowercase(), None, build_compiler, target);
                 cargo.into_cmd().run(builder);
 
                 if !builder.config.dry_run() {
@@ -1314,13 +1314,8 @@ impl Step for RustcBook {
         // bootstrap.toml), then this needs to explicitly update the dylib search
         // path.
         builder.add_rustc_lib_path(self.build_compiler, &mut cmd);
-        let doc_generator_guard = builder.msg(
-            Kind::Run,
-            self.build_compiler.stage,
-            "lint-docs",
-            self.build_compiler.host,
-            self.target,
-        );
+        let doc_generator_guard =
+            builder.msg(Kind::Run, "lint-docs", None, self.build_compiler, self.target);
         cmd.run(builder);
         drop(doc_generator_guard);
 
diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs
index d4cbbe60921..389afaecea3 100644
--- a/src/bootstrap/src/core/build_steps/gcc.rs
+++ b/src/bootstrap/src/core/build_steps/gcc.rs
@@ -12,6 +12,7 @@ use std::fs;
 use std::path::{Path, PathBuf};
 use std::sync::OnceLock;
 
+use crate::FileType;
 use crate::core::builder::{Builder, Cargo, Kind, RunConfig, ShouldRun, Step};
 use crate::core::config::TargetSelection;
 use crate::utils::build_stamp::{BuildStamp, generate_smart_stamp_hash};
@@ -28,6 +29,21 @@ pub struct GccOutput {
     pub libgccjit: PathBuf,
 }
 
+impl GccOutput {
+    /// Install the required libgccjit library file(s) to the specified `path`.
+    pub fn install_to(&self, builder: &Builder<'_>, directory: &Path) {
+        // At build time, cg_gcc has to link to libgccjit.so (the unversioned symbol).
+        // However, at runtime, it will by default look for libgccjit.so.0.
+        // So when we install the built libgccjit.so file to the target `directory`, we add it there
+        // with the `.0` suffix.
+        let mut target_filename = self.libgccjit.file_name().unwrap().to_str().unwrap().to_string();
+        target_filename.push_str(".0");
+
+        let dst = directory.join(target_filename);
+        builder.copy_link(&self.libgccjit, &dst, FileType::NativeLibrary);
+    }
+}
+
 impl Step for Gcc {
     type Output = GccOutput;
 
@@ -61,7 +77,6 @@ impl Step for Gcc {
         }
 
         build_gcc(&metadata, builder, target);
-        create_lib_alias(builder, &libgccjit_path);
 
         t!(metadata.stamp.write());
 
@@ -69,15 +84,6 @@ impl Step for Gcc {
     }
 }
 
-/// Creates a libgccjit.so.0 alias next to libgccjit.so if it does not
-/// already exist
-fn create_lib_alias(builder: &Builder<'_>, libgccjit: &PathBuf) {
-    let lib_alias = libgccjit.parent().unwrap().join("libgccjit.so.0");
-    if !lib_alias.exists() {
-        t!(builder.symlink_file(libgccjit, lib_alias));
-    }
-}
-
 pub struct Meta {
     stamp: BuildStamp,
     out_dir: PathBuf,
@@ -124,7 +130,6 @@ fn try_download_gcc(builder: &Builder<'_>, target: TargetSelection) -> Option<Pa
             }
 
             let libgccjit = root.join("lib").join("libgccjit.so");
-            create_lib_alias(builder, &libgccjit);
             Some(libgccjit)
         }
         PathFreshness::HasLocalModifications { .. } => {
diff --git a/src/bootstrap/src/core/build_steps/install.rs b/src/bootstrap/src/core/build_steps/install.rs
index acee78dcf59..666f2715224 100644
--- a/src/bootstrap/src/core/build_steps/install.rs
+++ b/src/bootstrap/src/core/build_steps/install.rs
@@ -68,7 +68,13 @@ fn install_sh(
     host: Option<TargetSelection>,
     tarball: &GeneratedTarball,
 ) {
-    let _guard = builder.msg(Kind::Install, stage, package, host, host);
+    let _guard = builder.msg(
+        Kind::Install,
+        package,
+        None,
+        (host.unwrap_or(builder.host_target), stage),
+        host,
+    );
 
     let prefix = default_path(&builder.config.prefix, "/usr/local");
     let sysconfdir = prefix.join(default_path(&builder.config.sysconfdir, "/etc"));
@@ -276,6 +282,7 @@ install!((self, builder, _config),
     RustcCodegenCranelift, alias = "rustc-codegen-cranelift", Self::should_build(_config), only_hosts: true, {
         if let Some(tarball) = builder.ensure(dist::CraneliftCodegenBackend {
             build_compiler: self.compiler,
+            target: self.target
         }) {
             install_sh(builder, "rustc-codegen-cranelift", self.compiler.stage, Some(self.target), &tarball);
         } else {
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 2f933baa4a4..f1be0af3183 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -161,8 +161,7 @@ You can skip linkcheck with --skip src/tools/linkchecker"
         let linkchecker = builder.tool_cmd(Tool::Linkchecker);
 
         // Run the linkchecker.
-        let _guard =
-            builder.msg(Kind::Test, compiler.stage, "Linkcheck", bootstrap_host, bootstrap_host);
+        let _guard = builder.msg(Kind::Test, "Linkcheck", None, compiler, bootstrap_host);
         let _time = helpers::timeit(builder);
         linkchecker.delay_failure().arg(builder.out.join(host).join("doc")).run(builder);
     }
@@ -541,8 +540,7 @@ impl Miri {
         cargo.env("MIRI_SYSROOT", &miri_sysroot);
 
         let mut cargo = BootstrapCommand::from(cargo);
-        let _guard =
-            builder.msg(Kind::Build, compiler.stage, "miri sysroot", compiler.host, target);
+        let _guard = builder.msg(Kind::Build, "miri sysroot", Mode::ToolRustc, compiler, target);
         cargo.run(builder);
 
         // # Determine where Miri put its sysroot.
@@ -643,7 +641,8 @@ impl Step for Miri {
         cargo.env("MIRI_TEST_TARGET", target.rustc_target_arg());
 
         {
-            let _guard = builder.msg_rustc_tool(Kind::Test, stage, "miri", host, target);
+            let _guard =
+                builder.msg(Kind::Test, "miri", Mode::ToolRustc, miri.build_compiler, target);
             let _time = helpers::timeit(builder);
             cargo.run(builder);
         }
@@ -659,11 +658,11 @@ impl Step for Miri {
             cargo.args(["tests/pass", "tests/panic"]);
 
             {
-                let _guard = builder.msg_rustc_tool(
+                let _guard = builder.msg(
                     Kind::Test,
-                    stage,
                     "miri (mir-opt-level 4)",
-                    host,
+                    Mode::ToolRustc,
+                    miri.build_compiler,
                     target,
                 );
                 let _time = helpers::timeit(builder);
@@ -703,7 +702,7 @@ impl Step for CargoMiri {
         }
 
         // This compiler runs on the host, we'll just use it for the target.
-        let compiler = builder.compiler(stage, host);
+        let build_compiler = builder.compiler(stage, host);
 
         // Run `cargo miri test`.
         // This is just a smoke test (Miri's own CI invokes this in a bunch of different ways and ensures
@@ -711,7 +710,7 @@ impl Step for CargoMiri {
         // itself executes properly under Miri, and that all the logic in `cargo-miri` does not explode.
         let mut cargo = tool::prepare_tool_cargo(
             builder,
-            compiler,
+            build_compiler,
             Mode::ToolStd, // it's unclear what to use here, we're not building anything just doing a smoke test!
             target,
             Kind::MiriTest,
@@ -736,7 +735,8 @@ impl Step for CargoMiri {
         // Finally, run everything.
         let mut cargo = BootstrapCommand::from(cargo);
         {
-            let _guard = builder.msg_rustc_tool(Kind::Test, stage, "cargo-miri", host, target);
+            let _guard =
+                builder.msg(Kind::Test, "cargo-miri", Mode::ToolRustc, (host, stage), target);
             let _time = helpers::timeit(builder);
             cargo.run(builder);
         }
@@ -830,7 +830,7 @@ impl Step for Clippy {
 
     /// Runs `cargo test` for clippy.
     fn run(self, builder: &Builder<'_>) {
-        let host = self.compilers.target();
+        let target = self.compilers.target();
 
         // We need to carefully distinguish the compiler that builds clippy, and the compiler
         // that is linked into the clippy being tested. `target_compiler` is the latter,
@@ -844,7 +844,7 @@ impl Step for Clippy {
             builder,
             build_compiler,
             Mode::ToolRustc,
-            host,
+            target,
             Kind::Test,
             "src/tools/clippy",
             SourceType::InTree,
@@ -858,7 +858,7 @@ impl Step for Clippy {
         cargo.env("HOST_LIBS", host_libs);
 
         // Build the standard library that the tests can use.
-        builder.std(target_compiler, host);
+        builder.std(target_compiler, target);
         cargo.env("TEST_SYSROOT", builder.sysroot(target_compiler));
         cargo.env("TEST_RUSTC", builder.rustc(target_compiler));
         cargo.env("TEST_RUSTC_LIB", builder.rustc_libdir(target_compiler));
@@ -881,9 +881,9 @@ impl Step for Clippy {
         }
 
         cargo.add_rustc_lib_path(builder);
-        let cargo = prepare_cargo_test(cargo, &[], &[], host, builder);
+        let cargo = prepare_cargo_test(cargo, &[], &[], target, builder);
 
-        let _guard = builder.msg_rustc_tool(Kind::Test, build_compiler.stage, "clippy", host, host);
+        let _guard = builder.msg(Kind::Test, "clippy", Mode::ToolRustc, build_compiler, target);
 
         // Clippy reports errors if it blessed the outputs
         if cargo.allow_failure().run(builder) {
@@ -990,9 +990,9 @@ impl Step for RustdocJSStd {
         ));
         let _guard = builder.msg(
             Kind::Test,
-            builder.top_stage,
             "rustdoc-js-std",
-            builder.config.host_target,
+            None,
+            (builder.config.host_target, builder.top_stage),
             self.target,
         );
         command.run(builder);
@@ -1141,13 +1141,7 @@ impl Step for RustdocGUI {
         }
 
         let _time = helpers::timeit(builder);
-        let _guard = builder.msg_rustc_tool(
-            Kind::Test,
-            self.compiler.stage,
-            "rustdoc-gui",
-            self.compiler.host,
-            self.target,
-        );
+        let _guard = builder.msg(Kind::Test, "rustdoc-gui", None, self.compiler, self.target);
         try_run_tests(builder, &mut cmd, true);
     }
 }
@@ -2237,9 +2231,10 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
 
         let _group = builder.msg(
             Kind::Test,
-            compiler.stage,
             format!("compiletest suite={suite} mode={mode}"),
-            compiler.host,
+            // FIXME: compiletest sometimes behaves as ToolStd, we could expose that difference here
+            Mode::ToolBootstrap,
+            compiler,
             target,
         );
         try_run_tests(builder, &mut cmd, false);
@@ -2381,9 +2376,9 @@ impl BookTest {
         builder.add_rust_test_threads(&mut rustbook_cmd);
         let _guard = builder.msg(
             Kind::Test,
-            compiler.stage,
             format_args!("mdbook {}", self.path.display()),
-            compiler.host,
+            None,
+            compiler,
             compiler.host,
         );
         let _time = helpers::timeit(builder);
@@ -2402,8 +2397,7 @@ impl BookTest {
 
         builder.std(compiler, host);
 
-        let _guard =
-            builder.msg(Kind::Test, compiler.stage, format!("book {}", self.name), host, host);
+        let _guard = builder.msg(Kind::Test, format!("book {}", self.name), None, compiler, host);
 
         // Do a breadth-first traversal of the `src/doc` directory and just run
         // tests for all files that end in `*.md`
@@ -2547,9 +2541,9 @@ impl Step for ErrorIndex {
 
         let guard = builder.msg(
             Kind::Test,
-            target_compiler.stage,
             "error-index",
-            target_compiler.host,
+            None,
+            self.compilers.build_compiler(),
             target_compiler.host,
         );
         let _time = helpers::timeit(builder);
@@ -2650,9 +2644,8 @@ fn run_cargo_test<'a>(
     let compiler = cargo.compiler();
     let mut cargo = prepare_cargo_test(cargo, libtest_args, crates, target, builder);
     let _time = helpers::timeit(builder);
-    let _group = description.into().and_then(|what| {
-        builder.msg_rustc_tool(Kind::Test, compiler.stage, what, compiler.host, target)
-    });
+    let _group =
+        description.into().and_then(|what| builder.msg(Kind::Test, what, None, compiler, target));
 
     #[cfg(feature = "build-metrics")]
     builder.metrics.begin_test_suite(
@@ -3176,8 +3169,9 @@ impl Step for Bootstrap {
     /// Tests the build system itself.
     fn run(self, builder: &Builder<'_>) {
         let host = builder.config.host_target;
-        let compiler = builder.compiler(0, host);
-        let _guard = builder.msg(Kind::Test, 0, "bootstrap", host, host);
+        let build_compiler = builder.compiler(0, host);
+        let _guard =
+            builder.msg(Kind::Test, "bootstrap", Mode::ToolBootstrap, build_compiler, host);
 
         // Some tests require cargo submodule to be present.
         builder.build.require_submodule("src/tools/cargo", None);
@@ -3196,7 +3190,7 @@ impl Step for Bootstrap {
 
         let mut cargo = tool::prepare_tool_cargo(
             builder,
-            compiler,
+            build_compiler,
             Mode::ToolBootstrap,
             host,
             Kind::Test,
@@ -3276,9 +3270,9 @@ impl Step for TierCheck {
 
         let _guard = builder.msg(
             Kind::Test,
-            self.compiler.stage,
             "platform support check",
-            self.compiler.host,
+            None,
+            self.compiler,
             self.compiler.host,
         );
         BootstrapCommand::from(cargo).delay_failure().run(builder);
@@ -3326,10 +3320,10 @@ impl Step for RustInstaller {
     /// Ensure the version placeholder replacement tool builds
     fn run(self, builder: &Builder<'_>) {
         let bootstrap_host = builder.config.host_target;
-        let compiler = builder.compiler(0, bootstrap_host);
+        let build_compiler = builder.compiler(0, bootstrap_host);
         let cargo = tool::prepare_tool_cargo(
             builder,
-            compiler,
+            build_compiler,
             Mode::ToolBootstrap,
             bootstrap_host,
             Kind::Test,
@@ -3338,13 +3332,8 @@ impl Step for RustInstaller {
             &[],
         );
 
-        let _guard = builder.msg(
-            Kind::Test,
-            compiler.stage,
-            "rust-installer",
-            bootstrap_host,
-            bootstrap_host,
-        );
+        let _guard =
+            builder.msg(Kind::Test, "rust-installer", None, build_compiler, bootstrap_host);
         run_cargo_test(cargo, &[], &[], None, bootstrap_host, builder);
 
         // We currently don't support running the test.sh script outside linux(?) environments.
@@ -3355,7 +3344,7 @@ impl Step for RustInstaller {
         }
 
         let mut cmd = command(builder.src.join("src/tools/rust-installer/test.sh"));
-        let tmpdir = testdir(builder, compiler.host).join("rust-installer");
+        let tmpdir = testdir(builder, build_compiler.host).join("rust-installer");
         let _ = std::fs::remove_dir_all(&tmpdir);
         let _ = std::fs::create_dir_all(&tmpdir);
         cmd.current_dir(&tmpdir);
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index aa00cd03c5b..793e6b629c9 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -26,7 +26,7 @@ use crate::core::builder::{
 use crate::core::config::{DebuginfoLevel, RustcLto, TargetSelection};
 use crate::utils::exec::{BootstrapCommand, command};
 use crate::utils::helpers::{add_dylib_path, exe, t};
-use crate::{Compiler, FileType, Kind, Mode, gha};
+use crate::{Compiler, FileType, Kind, Mode};
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub enum SourceType {
@@ -58,28 +58,6 @@ struct ToolBuild {
     artifact_kind: ToolArtifactKind,
 }
 
-impl Builder<'_> {
-    #[track_caller]
-    pub(crate) fn msg_tool(
-        &self,
-        kind: Kind,
-        mode: Mode,
-        tool: &str,
-        build_stage: u32,
-        host: &TargetSelection,
-        target: &TargetSelection,
-    ) -> Option<gha::Group> {
-        match mode {
-            // depends on compiler stage, different to host compiler
-            Mode::ToolRustc => {
-                self.msg_rustc_tool(kind, build_stage, format_args!("tool {tool}"), *host, *target)
-            }
-            // doesn't depend on compiler, same as host compiler
-            _ => self.msg(kind, build_stage, format_args!("tool {tool}"), *host, *target),
-        }
-    }
-}
-
 /// Result of the tool build process. Each `Step` in this module is responsible
 /// for using this type as `type Output = ToolBuildResult;`
 #[derive(Clone)]
@@ -166,14 +144,8 @@ impl Step for ToolBuild {
 
         cargo.args(self.cargo_args);
 
-        let _guard = builder.msg_tool(
-            Kind::Build,
-            self.mode,
-            self.tool,
-            self.build_compiler.stage,
-            &self.build_compiler.host,
-            &self.target,
-        );
+        let _guard =
+            builder.msg(Kind::Build, self.tool, self.mode, self.build_compiler, self.target);
 
         // we check this below
         let build_success = compile::stream_cargo(builder, cargo, vec![], &mut |_| {});
@@ -380,13 +352,13 @@ pub(crate) fn get_tool_target_compiler(
 /// tools directory.
 fn copy_link_tool_bin(
     builder: &Builder<'_>,
-    compiler: Compiler,
+    build_compiler: Compiler,
     target: TargetSelection,
     mode: Mode,
     name: &str,
 ) -> PathBuf {
-    let cargo_out = builder.cargo_out(compiler, mode, target).join(exe(name, target));
-    let bin = builder.tools_dir(compiler).join(exe(name, target));
+    let cargo_out = builder.cargo_out(build_compiler, mode, target).join(exe(name, target));
+    let bin = builder.tools_dir(build_compiler).join(exe(name, target));
     builder.copy_link(&cargo_out, &bin, FileType::Executable);
     bin
 }
@@ -857,7 +829,9 @@ impl Step for Cargo {
     fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
         builder.build.require_submodule("src/tools/cargo", None);
 
+        builder.std(self.build_compiler, builder.host_target);
         builder.std(self.build_compiler, self.target);
+
         builder.ensure(ToolBuild {
             build_compiler: self.build_compiler,
             target: self.target,
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index 163a498d4b4..de4b941ac90 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -1597,7 +1597,7 @@ You have to build a stage1 compiler for `{}` first, and then use it to build a s
         cmd.env("CARGO", &self.initial_cargo);
         // Need to add the `run_compiler` libs. Those are the libs produces *by* `build_compiler`
         // in `tool::ToolBuild` step, so they match the Miri we just built. However this means they
-        // are actually living one stage up, i.e. we are running `stage0-tools-bin/miri` with the
+        // are actually living one stage up, i.e. we are running `stage1-tools-bin/miri` with the
         // libraries in `stage1/lib`. This is an unfortunate off-by-1 caused (possibly) by the fact
         // that Miri doesn't have an "assemble" step like rustc does that would cross the stage boundary.
         // We can't use `add_rustc_lib_path` as that's a NOP on Windows but we do need these libraries
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index c505cacadb5..a656927b1f6 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -955,7 +955,7 @@ impl Config {
         config.download_rustc_commit =
             download_ci_rustc_commit(dwn_ctx, rust_download_rustc, config.llvm_assertions);
 
-        if debug_assertions_requested {
+        if debug_assertions_requested && config.download_rustc_commit.is_some() {
             eprintln!(
                 "WARN: `rust.debug-assertions = true` will prevent downloading CI rustc as alt CI \
                 rustc is not currently built with debug assertions."
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index 3080e641b5b..bd02131b7fe 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -35,6 +35,7 @@ pub struct Finder {
 const STAGE0_MISSING_TARGETS: &[&str] = &[
     "armv7a-vex-v5",
     // just a dummy comment so the list doesn't get onelined
+    "aarch64_be-unknown-none-softfloat",
 ];
 
 /// Minimum version threshold for libstdc++ required when using prebuilt LLVM
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 4abf386e5de..0b65ebc0671 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -410,6 +410,25 @@ forward! {
     download_rustc() -> bool,
 }
 
+/// A mostly temporary helper struct before we can migrate everything in bootstrap to use
+/// the concept of a build compiler.
+struct HostAndStage {
+    host: TargetSelection,
+    stage: u32,
+}
+
+impl From<(TargetSelection, u32)> for HostAndStage {
+    fn from((host, stage): (TargetSelection, u32)) -> Self {
+        Self { host, stage }
+    }
+}
+
+impl From<Compiler> for HostAndStage {
+    fn from(compiler: Compiler) -> Self {
+        Self { host: compiler.host, stage: compiler.stage }
+    }
+}
+
 impl Build {
     /// Creates a new set of build configuration from the `flags` on the command
     /// line and the filesystem `config`.
@@ -859,14 +878,17 @@ impl Build {
         if self.config.rust_optimize.is_release() { "release" } else { "debug" }
     }
 
-    fn tools_dir(&self, compiler: Compiler) -> PathBuf {
-        let out = self.out.join(compiler.host).join(format!("stage{}-tools-bin", compiler.stage));
+    fn tools_dir(&self, build_compiler: Compiler) -> PathBuf {
+        let out = self
+            .out
+            .join(build_compiler.host)
+            .join(format!("stage{}-tools-bin", build_compiler.stage + 1));
         t!(fs::create_dir_all(&out));
         out
     }
 
     /// Returns the root directory for all output generated in a particular
-    /// stage when running with a particular host compiler.
+    /// stage when being built with a particular build compiler.
     ///
     /// The mode indicates what the root directory is for.
     fn stage_out(&self, build_compiler: Compiler, mode: Mode) -> PathBuf {
@@ -876,15 +898,17 @@ impl Build {
             (None, "bootstrap-tools")
         }
         fn staged_tool(build_compiler: Compiler) -> (Option<u32>, &'static str) {
-            (Some(build_compiler.stage), "tools")
+            (Some(build_compiler.stage + 1), "tools")
         }
 
         let (stage, suffix) = match mode {
+            // Std is special, stage N std is built with stage N rustc
             Mode::Std => (Some(build_compiler.stage), "std"),
-            Mode::Rustc => (Some(build_compiler.stage), "rustc"),
-            Mode::Codegen => (Some(build_compiler.stage), "codegen"),
+            // The rest of things are built with stage N-1 rustc
+            Mode::Rustc => (Some(build_compiler.stage + 1), "rustc"),
+            Mode::Codegen => (Some(build_compiler.stage + 1), "codegen"),
             Mode::ToolBootstrap => bootstrap_tool(),
-            Mode::ToolStd | Mode::ToolRustc => (Some(build_compiler.stage), "tools"),
+            Mode::ToolStd | Mode::ToolRustc => (Some(build_compiler.stage + 1), "tools"),
             Mode::ToolTarget => {
                 // If we're not cross-compiling (the common case), share the target directory with
                 // bootstrap tools to reuse the build cache.
@@ -907,8 +931,8 @@ impl Build {
     /// Returns the root output directory for all Cargo output in a given stage,
     /// running a particular compiler, whether or not we're building the
     /// standard library, and targeting the specified architecture.
-    fn cargo_out(&self, compiler: Compiler, mode: Mode, target: TargetSelection) -> PathBuf {
-        self.stage_out(compiler, mode).join(target).join(self.cargo_dir())
+    fn cargo_out(&self, build_compiler: Compiler, mode: Mode, target: TargetSelection) -> PathBuf {
+        self.stage_out(build_compiler, mode).join(target).join(self.cargo_dir())
     }
 
     /// Root output directory of LLVM for `target`
@@ -1067,45 +1091,14 @@ impl Build {
         }
     }
 
-    #[must_use = "Groups should not be dropped until the Step finishes running"]
-    #[track_caller]
-    fn msg_clippy(
-        &self,
-        what: impl Display,
-        target: impl Into<Option<TargetSelection>>,
-    ) -> Option<gha::Group> {
-        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"]
-    #[track_caller]
-    fn msg_check(
-        &self,
-        what: impl Display,
-        target: impl Into<Option<TargetSelection>>,
-        custom_stage: Option<u32>,
-    ) -> Option<gha::Group> {
-        self.msg(
-            Kind::Check,
-            custom_stage.unwrap_or(self.config.stage),
-            what,
-            self.config.host_target,
-            target,
-        )
-    }
-
-    #[must_use = "Groups should not be dropped until the Step finishes running"]
-    #[track_caller]
-    fn msg_doc(
-        &self,
-        compiler: Compiler,
-        what: impl Display,
-        target: impl Into<Option<TargetSelection>> + Copy,
-    ) -> Option<gha::Group> {
-        self.msg(Kind::Doc, compiler.stage, what, compiler.host, target.into())
-    }
-
-    /// Return a `Group` guard for a [`Step`] that is built for each `--stage`.
+    /// Return a `Group` guard for a [`Step`] that:
+    /// - Performs `action`
+    /// - On `what`
+    ///   - Where `what` possibly corresponds to a `mode`
+    /// - `action` is performed using the given build compiler (`host_and_stage`).
+    ///   - Since some steps do not use the concept of a build compiler yet, it is also possible
+    ///     to pass the host and stage explicitly.
+    /// - With a given `target`.
     ///
     /// [`Step`]: crate::core::builder::Step
     #[must_use = "Groups should not be dropped until the Step finishes running"]
@@ -1113,19 +1106,36 @@ impl Build {
     fn msg(
         &self,
         action: impl Into<Kind>,
-        stage: u32,
         what: impl Display,
-        host: impl Into<Option<TargetSelection>>,
+        mode: impl Into<Option<Mode>>,
+        host_and_stage: impl Into<HostAndStage>,
         target: impl Into<Option<TargetSelection>>,
     ) -> Option<gha::Group> {
+        let host_and_stage = host_and_stage.into();
+        let actual_stage = match mode.into() {
+            // Std has the same stage as the compiler that builds it
+            Some(Mode::Std) => host_and_stage.stage,
+            // Other things have stage corresponding to their build compiler + 1
+            Some(
+                Mode::Rustc
+                | Mode::Codegen
+                | Mode::ToolBootstrap
+                | Mode::ToolTarget
+                | Mode::ToolStd
+                | Mode::ToolRustc,
+            )
+            | None => host_and_stage.stage + 1,
+        };
+
         let action = action.into().description();
-        let msg = |fmt| format!("{action} stage{stage} {what}{fmt}");
+        let msg = |fmt| format!("{action} stage{actual_stage} {what}{fmt}");
         let msg = if let Some(target) = target.into() {
-            let host = host.into().unwrap();
+            let build_stage = host_and_stage.stage;
+            let host = host_and_stage.host;
             if host == target {
-                msg(format_args!(" ({target})"))
+                msg(format_args!(" (stage{build_stage} -> stage{actual_stage}, {target})"))
             } else {
-                msg(format_args!(" ({host} -> {target})"))
+                msg(format_args!(" (stage{build_stage}:{host} -> stage{actual_stage}:{target})"))
             }
         } else {
             msg(format_args!(""))
@@ -1149,27 +1159,6 @@ impl Build {
         self.group(&msg)
     }
 
-    #[must_use = "Groups should not be dropped until the Step finishes running"]
-    #[track_caller]
-    fn msg_rustc_tool(
-        &self,
-        action: impl Into<Kind>,
-        build_stage: u32,
-        what: impl Display,
-        host: TargetSelection,
-        target: TargetSelection,
-    ) -> Option<gha::Group> {
-        let action = action.into().description();
-        let msg = |fmt| format!("{action} {what} {fmt}");
-
-        let msg = if host == target {
-            msg(format_args!("(stage{build_stage} -> stage{}, {target})", build_stage + 1))
-        } else {
-            msg(format_args!("(stage{build_stage}:{host} -> stage{}:{target})", build_stage + 1))
-        };
-        self.group(&msg)
-    }
-
     #[track_caller]
     fn group(&self, msg: &str) -> Option<gha::Group> {
         match self.config.get_dry_run() {
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 091956e7e5f..cd7fba39a84 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -496,4 +496,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         severity: ChangeSeverity::Warning,
         summary: "It is no longer possible to `x doc` with stage 0. All doc commands have to be on stage 1+.",
     },
+    ChangeInfo {
+        change_id: 145295,
+        severity: ChangeSeverity::Warning,
+        summary: "The names of stageN directories in the build directory have been consolidated with the new (post-stage-0-redesign) staging scheme. Some tools and binaries might be located in a different build directory than before.",
+    },
 ];
diff --git a/src/bootstrap/src/utils/shared_helpers.rs b/src/bootstrap/src/utils/shared_helpers.rs
index 9428e221f41..d620cc4bbb6 100644
--- a/src/bootstrap/src/utils/shared_helpers.rs
+++ b/src/bootstrap/src/utils/shared_helpers.rs
@@ -81,10 +81,11 @@ pub fn parse_rustc_verbose() -> usize {
 }
 
 /// Parses the value of the "RUSTC_STAGE" environment variable and returns it as a `String`.
+/// This is the stage of the *build compiler*, which we are wrapping using a rustc/rustdoc wrapper.
 ///
 /// If "RUSTC_STAGE" was not set, the program will be terminated with 101.
-pub fn parse_rustc_stage() -> String {
-    env::var("RUSTC_STAGE").unwrap_or_else(|_| {
+pub fn parse_rustc_stage() -> u32 {
+    env::var("RUSTC_STAGE").ok().and_then(|v| v.parse().ok()).unwrap_or_else(|| {
         // Don't panic here; it's reasonable to try and run these shims directly. Give a helpful error instead.
         eprintln!("rustc shim: FATAL: RUSTC_STAGE was not set");
         eprintln!("rustc shim: NOTE: use `x.py build -vvv` to see all environment variables set by bootstrap");
diff --git a/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile b/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile
index 2b8a3f829c6..e726329753f 100644
--- a/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile
+++ b/src/ci/docker/host-aarch64/dist-aarch64-linux/Dockerfile
@@ -96,7 +96,7 @@ ENV RUST_CONFIGURE_ARGS \
       --set rust.codegen-units=1
 
 ENV SCRIPT python3 ../x.py build --set rust.debug=true opt-dist && \
-      ./build/$HOSTS/stage0-tools-bin/opt-dist linux-ci --  python3 ../x.py dist \
+      ./build/$HOSTS/stage1-tools-bin/opt-dist linux-ci --  python3 ../x.py dist \
       --host $HOSTS --target $HOSTS --include-default-paths build-manifest bootstrap
 
 ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=clang
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh
index 924bdbc7615..4c95d4a401e 100755
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/dist.sh
@@ -4,7 +4,7 @@ set -eux
 
 python3 ../x.py build --set rust.debug=true opt-dist
 
-./build/$HOSTS/stage0-tools-bin/opt-dist linux-ci -- python3 ../x.py dist \
+./build/$HOSTS/stage1-tools-bin/opt-dist linux-ci -- python3 ../x.py dist \
     --host $HOSTS --target $HOSTS \
     --include-default-paths \
     build-manifest bootstrap
diff --git a/src/ci/docker/host-x86_64/pr-check-2/Dockerfile b/src/ci/docker/host-x86_64/pr-check-2/Dockerfile
index 1a219125593..6fea2437276 100644
--- a/src/ci/docker/host-x86_64/pr-check-2/Dockerfile
+++ b/src/ci/docker/host-x86_64/pr-check-2/Dockerfile
@@ -33,11 +33,11 @@ ENV SCRIPT \
         python3 ../x.py test --stage 1 src/tools/compiletest && \
         python3 ../x.py doc bootstrap && \
         # Build both public and internal documentation.
-        RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc compiler --stage 2 && \
-        RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc library --stage 2 && \
+        RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc compiler --stage 1 && \
+        RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc library --stage 1 && \
         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 library/test --stage 2 && \
+        RUSTDOCFLAGS=\"--document-private-items --document-hidden-items\" python3 ../x.py doc library/test --stage 1 && \
         # 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/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 48c570bfa11..ae13d14c380 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -656,7 +656,7 @@ auto:
         --enable-full-tools
         --enable-profiler
         --set rust.codegen-units=1
-      SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist windows-ci -- python x.py dist bootstrap --include-default-paths
+      SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage1-tools-bin/opt-dist windows-ci -- python x.py dist bootstrap --include-default-paths
       DIST_REQUIRE_ALL_TOOLS: 1
       CODEGEN_BACKENDS: llvm,cranelift
     <<: *job-windows-8c
diff --git a/src/ci/run.sh b/src/ci/run.sh
index f58a067041d..c9d81f1ff51 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -205,6 +205,9 @@ if [ "$ENABLE_GCC_CODEGEN" = "1" ]; then
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-new-symbol-mangling"
 fi
 
+# If bootstrap fails, we want to see its backtrace
+export RUST_BACKTRACE=1
+
 # Print the date from the local machine and the date from an external source to
 # check for clock drifts. An HTTP URL is used instead of HTTPS since on Azure
 # Pipelines it happened that the certificates were marked as expired.
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 1be151c051a082b542548c62cafbcb055fa8944
+Subproject 59b8af811886313577615c2cf0e045f01faed88
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject bd1279cdc9865bfff605e741fb76a0b2f07314a
+Subproject adc1f3b9012ad3255eea2054ca30596a953d053
diff --git a/src/doc/rustc-dev-guide/src/building/optimized-build.md b/src/doc/rustc-dev-guide/src/building/optimized-build.md
index 863ed9749fb..46def66d178 100644
--- a/src/doc/rustc-dev-guide/src/building/optimized-build.md
+++ b/src/doc/rustc-dev-guide/src/building/optimized-build.md
@@ -118,7 +118,7 @@ Here is an example of how can `opt-dist` be used locally (outside of CI):
     ```
 3. Run the tool with the `local` mode and provide necessary parameters:
     ```bash
-    ./build/host/stage0-tools-bin/opt-dist local \
+    ./build/host/stage1-tools-bin/opt-dist local \
       --target-triple <target> \ # select target, e.g. "x86_64-unknown-linux-gnu"
       --checkout-dir <path>    \ # path to rust checkout, e.g. "."
       --llvm-dir <path>        \ # path to built LLVM toolchain, e.g. "/foo/bar/llvm/install"
diff --git a/src/doc/rustc-dev-guide/src/stability.md b/src/doc/rustc-dev-guide/src/stability.md
index c26d34273d7..3c4c65fdd5a 100644
--- a/src/doc/rustc-dev-guide/src/stability.md
+++ b/src/doc/rustc-dev-guide/src/stability.md
@@ -182,6 +182,11 @@ of the standard library raises it to a warning with
 `#![warn(deprecated_in_future)]`.
 
 ## unstable_feature_bound
-The `#[unstable_feature_bound(foo)]` attribute can be used together with `#[unstable]` attribute to mark an `impl` of stable type and stable trait as unstable. In std/core, an item annotated with `#[unstable_feature_bound(foo)]` can only be used by another item that is also annotated with `#[unstable_feature_bound(foo)]`. Outside of std/core, using an item with `#[unstable_feature_bound(foo)]` requires the feature to be enabled with `#![feature(foo)]` attribute on the crate. Currently, only `impl`s and free functions can be annotated with `#[unstable_feature_bound]`.
+The `#[unstable_feature_bound(foo)]` attribute can be used together with `#[unstable]` attribute to mark an `impl` of stable type and stable trait as unstable. In std/core, an item annotated with `#[unstable_feature_bound(foo)]` can only be used by another item that is also annotated with `#[unstable_feature_bound(foo)]`. Outside of std/core, using an item with `#[unstable_feature_bound(foo)]` requires the feature to be enabled with `#![feature(foo)]` attribute on the crate.
+
+Currently, the items that can be annotated with `#[unstable_feature_bound]` are:
+- `impl`
+- free function
+- trait
 
 [blog]: https://www.ralfj.de/blog/2018/07/19/const.html
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 25f154f1180..b942e4bfa61 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -47,6 +47,7 @@
     - [\*-apple-visionos](platform-support/apple-visionos.md)
     - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md)
     - [aarch64-unknown-linux-musl](platform-support/aarch64-unknown-linux-musl.md)
+    - [aarch64_be-unknown-none-softfloat](platform-support/aarch64_be-unknown-none-softfloat.md)
     - [amdgcn-amd-amdhsa](platform-support/amdgcn-amd-amdhsa.md)
     - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md)
     - [arm-none-eabi](platform-support/arm-none-eabi.md)
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 8ebaa8dd874..89b43cda9b9 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -273,6 +273,7 @@ target | std | host | notes
 `aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian)
 `aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI)
 [`aarch64_be-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD (big-endian)
+[`aarch64_be-unknown-none-softfloat`](platform-support/aarch64_be-unknown-none-softfloat.md) | * |  | Bare big-endian ARM64, softfloat
 [`amdgcn-amd-amdhsa`](platform-support/amdgcn-amd-amdhsa.md) | * |  | `-Ctarget-cpu=gfx...` to specify [the AMD GPU] to compile for
 [`arm64_32-apple-watchos`](platform-support/apple-watchos.md) | ✓ |  | Arm Apple WatchOS 64-bit with 32-bit pointers
 [`arm64e-apple-darwin`](platform-support/arm64e-apple-darwin.md)  | ✓ | ✓ | ARM64e Apple Darwin
diff --git a/src/doc/rustc/src/platform-support/aarch64_be-unknown-none-softfloat.md b/src/doc/rustc/src/platform-support/aarch64_be-unknown-none-softfloat.md
new file mode 100644
index 00000000000..a28ddcdf7f2
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/aarch64_be-unknown-none-softfloat.md
@@ -0,0 +1,74 @@
+# aarch64_be-unknown-none-softfloat
+
+**Tier: 3**
+
+Target for freestanding/bare-metal big-endian ARM64 binaries in ELF format:
+firmware, kernels, etc.
+
+## Target maintainers
+
+[@Gelbpunkt](https://github.com/Gelbpunkt)
+
+## Requirements
+
+This target is cross-compiled. There is no support for `std`. There is no
+default allocator, but it's possible to use `alloc` by supplying an allocator.
+
+The target does not assume existence of a FPU and does not make use of any
+non-GPR register. This allows the generated code to run in environments, such
+as kernels, which may need to avoid the use of such registers or which may have
+special considerations about the use of such registers (e.g. saving and
+restoring them to avoid breaking userspace code using the same registers). You
+can change code generation to use additional CPU features via the
+`-C target-feature=` codegen options to rustc, or via the `#[target_feature]`
+mechanism within Rust code.
+
+By default, code generated with the soft-float target should run on any
+big-endian ARM64 hardware, enabling additional target features may raise this
+baseline.
+
+`extern "C"` uses the [architecture's standard calling convention][aapcs64].
+
+[aapcs64]: https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst
+
+The targets generate binaries in the ELF format. Any alternate formats or
+special considerations for binary layout will require linker options or linker
+scripts.
+
+## Building the target
+
+You can build Rust with support for the target by adding it to the `target`
+list in `bootstrap.toml`:
+
+```toml
+[build]
+target = ["aarch64_be-unknown-none-softfloat"]
+```
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for this target. To compile for
+this target, you will first need to build Rust with the target enabled (see
+"Building the target" above).
+
+## Cross-compilation
+
+For cross builds, you will need an appropriate ARM64 C/C++ toolchain for
+linking, or if you want to compile C code along with Rust (such as for Rust
+crates with C dependencies).
+
+Rust *may* be able to use an `aarch64_be-unknown-linux-{gnu,musl}-` toolchain
+with appropriate standalone flags to build for this target (depending on the
+assumptions of that toolchain, see below), or you may wish to use a separate
+`aarch64_be-unknown-none-softfloat` toolchain.
+
+On some ARM64 hosts that use ELF binaries, you *may* be able to use the host C
+toolchain, if it does not introduce assumptions about the host environment that
+don't match the expectations of a standalone environment. Otherwise, you may
+need a separate toolchain for standalone/freestanding development, just as when
+cross-compiling from a non-ARM64 platform.
+
+## Testing
+
+As the target supports a variety of different environments and does not support
+`std`, it does not support running the Rust test suite.
diff --git a/src/doc/rustc/src/tests/index.md b/src/doc/rustc/src/tests/index.md
index 12de69a4c9e..7609ed23351 100644
--- a/src/doc/rustc/src/tests/index.md
+++ b/src/doc/rustc/src/tests/index.md
@@ -164,7 +164,7 @@ Sets the number of threads to use for running tests in parallel. By default,
 uses the amount of concurrency available on the hardware as indicated by
 [`available_parallelism`].
 
-This can also be specified with the `RUST_TEST_THREADS` environment variable.
+Deprecated: this can also be specified with the `RUST_TEST_THREADS` environment variable.
 
 #### `--force-run-in-process`
 
@@ -186,7 +186,7 @@ docs](../../unstable-book/compiler-flags/report-time.html) for more information.
 
 Runs the tests in random order, as opposed to the default alphabetical order.
 
-This may also be specified by setting the `RUST_TEST_SHUFFLE` environment
+Deprecated: this may also be specified by setting the `RUST_TEST_SHUFFLE` environment
 variable to anything but `0`.
 
 The random number generator seed that is output can be passed to
@@ -209,7 +209,7 @@ the tests in the same order both times.
 _SEED_ is any 64-bit unsigned integer, for example, one produced by
 [`--shuffle`](#--shuffle).
 
-This can also be specified with the `RUST_TEST_SHUFFLE_SEED` environment
+Deprecated: this can also be specified with the `RUST_TEST_SHUFFLE_SEED` environment
 variable.
 
 ⚠️ 🚧 This option is [unstable](#unstable-options), and requires the `-Z
@@ -231,7 +231,7 @@ Does not capture the stdout and stderr of the test, and allows tests to print
 to the console. Usually the output is captured, and only displayed if the test
 fails.
 
-This may also be specified by setting the `RUST_TEST_NOCAPTURE` environment
+Deprecated: this may also be specified by setting the `RUST_TEST_NOCAPTURE` environment
 variable to anything but `0`.
 
 `--nocapture` is a deprecated alias for `--no-capture`.
diff --git a/src/doc/unstable-book/src/compiler-environment-variables/SDKROOT.md b/src/doc/unstable-book/src/compiler-environment-variables/SDKROOT.md
index be9ed02f54d..6d371ae289f 100644
--- a/src/doc/unstable-book/src/compiler-environment-variables/SDKROOT.md
+++ b/src/doc/unstable-book/src/compiler-environment-variables/SDKROOT.md
@@ -1,6 +1,6 @@
 # `SDKROOT`
 
 This environment variable is used on Apple targets.
-It is passed through to the linker (currently either as `-isysroot` or `-syslibroot`).
+It is passed through to the linker (currently either directly or via the `-syslibroot` flag).
 
 Note that this variable is not always respected. When the SDKROOT is clearly wrong (e.g. when the platform of the SDK does not match the `--target` used by rustc), this is ignored and rustc does its own detection.
diff --git a/src/doc/unstable-book/src/compiler-flags/codegen-source-order.md b/src/doc/unstable-book/src/compiler-flags/codegen-source-order.md
new file mode 100644
index 00000000000..cb019fe0176
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/codegen-source-order.md
@@ -0,0 +1,12 @@
+# `codegen-source-order`
+
+---
+
+This feature allows you to have a predictive and
+deterministic order for items after codegen, which
+is the same as in source code.
+
+For every `CodegenUnit`, local `MonoItem`s would
+be sorted by `(Span, SymbolName)`, which
+makes codegen tests rely on the order of items in
+source files work.
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 8c0f897c992..0d98c64bbde 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -6,7 +6,7 @@ use std::sync::Arc;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
 use rustc_hir::Mutability;
-use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def::{DefKind, MacroKinds, Res};
 use rustc_hir::def_id::{DefId, DefIdSet, LocalDefId, LocalModDefId};
 use rustc_metadata::creader::{CStore, LoadedMacro};
 use rustc_middle::ty::fast_reject::SimplifiedType;
@@ -137,13 +137,16 @@ pub(crate) fn try_inline(
                 clean::ConstantItem(Box::new(ct))
             })
         }
-        Res::Def(DefKind::Macro(kind), did) => {
-            let mac = build_macro(cx, did, name, kind);
-
-            let type_kind = match kind {
-                MacroKind::Bang => ItemType::Macro,
-                MacroKind::Attr => ItemType::ProcAttribute,
-                MacroKind::Derive => ItemType::ProcDerive,
+        Res::Def(DefKind::Macro(kinds), did) => {
+            let mac = build_macro(cx, did, name, kinds);
+
+            // FIXME: handle attributes and derives that aren't proc macros, and macros with
+            // multiple kinds
+            let type_kind = match kinds {
+                MacroKinds::BANG => ItemType::Macro,
+                MacroKinds::ATTR => ItemType::ProcAttribute,
+                MacroKinds::DERIVE => ItemType::ProcDerive,
+                _ => todo!("Handle macros with multiple kinds"),
             };
             record_extern_fqn(cx, did, type_kind);
             mac
@@ -749,22 +752,36 @@ fn build_macro(
     cx: &mut DocContext<'_>,
     def_id: DefId,
     name: Symbol,
-    macro_kind: MacroKind,
+    macro_kinds: MacroKinds,
 ) -> clean::ItemKind {
     match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.tcx) {
-        LoadedMacro::MacroDef { def, .. } => match macro_kind {
-            MacroKind::Bang => clean::MacroItem(clean::Macro {
+        // FIXME: handle attributes and derives that aren't proc macros, and macros with multiple
+        // kinds
+        LoadedMacro::MacroDef { def, .. } => match macro_kinds {
+            MacroKinds::BANG => clean::MacroItem(clean::Macro {
                 source: utils::display_macro_source(cx, name, &def),
                 macro_rules: def.macro_rules,
             }),
-            MacroKind::Derive | MacroKind::Attr => {
-                clean::ProcMacroItem(clean::ProcMacro { kind: macro_kind, helpers: Vec::new() })
-            }
+            MacroKinds::DERIVE => clean::ProcMacroItem(clean::ProcMacro {
+                kind: MacroKind::Derive,
+                helpers: Vec::new(),
+            }),
+            MacroKinds::ATTR => clean::ProcMacroItem(clean::ProcMacro {
+                kind: MacroKind::Attr,
+                helpers: Vec::new(),
+            }),
+            _ => todo!("Handle macros with multiple kinds"),
         },
-        LoadedMacro::ProcMacro(ext) => clean::ProcMacroItem(clean::ProcMacro {
-            kind: ext.macro_kind(),
-            helpers: ext.helper_attrs,
-        }),
+        LoadedMacro::ProcMacro(ext) => {
+            // Proc macros can only have a single kind
+            let kind = match ext.macro_kinds() {
+                MacroKinds::BANG => MacroKind::Bang,
+                MacroKinds::ATTR => MacroKind::Attr,
+                MacroKinds::DERIVE => MacroKind::Derive,
+                _ => unreachable!(),
+            };
+            clean::ProcMacroItem(clean::ProcMacro { kind, helpers: ext.helper_attrs })
+        }
     }
 }
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 7194c2fcede..4ff94cc6f3b 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -40,7 +40,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, In
 use rustc_errors::codes::*;
 use rustc_errors::{FatalError, struct_span_code_err};
 use rustc_hir::attrs::AttributeKind;
-use rustc_hir::def::{CtorKind, DefKind, Res};
+use rustc_hir::def::{CtorKind, DefKind, MacroKinds, Res};
 use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE, LocalDefId};
 use rustc_hir::{LangItem, PredicateOrigin, find_attr};
 use rustc_hir_analysis::hir_ty_lowering::FeedConstTy;
@@ -2768,7 +2768,7 @@ fn clean_maybe_renamed_item<'tcx>(
         // These kinds of item either don't need a `name` or accept a `None` one so we handle them
         // before.
         match item.kind {
-            ItemKind::Impl(impl_) => return clean_impl(impl_, item.owner_id.def_id, cx),
+            ItemKind::Impl(ref impl_) => return clean_impl(impl_, item.owner_id.def_id, cx),
             ItemKind::Use(path, kind) => {
                 return clean_use_statement(
                     item,
@@ -2845,11 +2845,19 @@ fn clean_maybe_renamed_item<'tcx>(
                 generics: clean_generics(generics, cx),
                 fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
             }),
-            ItemKind::Macro(_, macro_def, MacroKind::Bang) => MacroItem(Macro {
+            // FIXME: handle attributes and derives that aren't proc macros, and macros with
+            // multiple kinds
+            ItemKind::Macro(_, macro_def, MacroKinds::BANG) => MacroItem(Macro {
                 source: display_macro_source(cx, name, macro_def),
                 macro_rules: macro_def.macro_rules,
             }),
-            ItemKind::Macro(_, _, macro_kind) => clean_proc_macro(item, &mut name, macro_kind, cx),
+            ItemKind::Macro(_, _, MacroKinds::ATTR) => {
+                clean_proc_macro(item, &mut name, MacroKind::Attr, cx)
+            }
+            ItemKind::Macro(_, _, MacroKinds::DERIVE) => {
+                clean_proc_macro(item, &mut name, MacroKind::Derive, cx)
+            }
+            ItemKind::Macro(_, _, _) => todo!("Handle macros with multiple kinds"),
             // proc macros can have a name set by attributes
             ItemKind::Fn { ref sig, generics, body: body_id, .. } => {
                 clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
@@ -2896,7 +2904,7 @@ fn clean_impl<'tcx>(
 ) -> Vec<Item> {
     let tcx = cx.tcx;
     let mut ret = Vec::new();
-    let trait_ = impl_.of_trait.as_ref().map(|t| clean_trait_ref(t, cx));
+    let trait_ = impl_.of_trait.map(|t| clean_trait_ref(&t.trait_ref, cx));
     let items = impl_
         .items
         .iter()
@@ -2922,7 +2930,10 @@ fn clean_impl<'tcx>(
         });
     let mut make_item = |trait_: Option<Path>, for_: Type, items: Vec<Item>| {
         let kind = ImplItem(Box::new(Impl {
-            safety: impl_.safety,
+            safety: match impl_.of_trait {
+                Some(of_trait) => of_trait.safety,
+                None => hir::Safety::Safe,
+            },
             generics: clean_generics(impl_.generics, cx),
             trait_,
             for_,
diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs
index 3aba7a370ad..1dba84aa44c 100644
--- a/src/librustdoc/formats/item_type.rs
+++ b/src/librustdoc/formats/item_type.rs
@@ -2,7 +2,7 @@
 
 use std::fmt;
 
-use rustc_hir::def::{CtorOf, DefKind};
+use rustc_hir::def::{CtorOf, DefKind, MacroKinds};
 use rustc_span::hygiene::MacroKind;
 use serde::{Serialize, Serializer};
 
@@ -134,9 +134,10 @@ impl ItemType {
             DefKind::Trait => Self::Trait,
             DefKind::TyAlias => Self::TypeAlias,
             DefKind::TraitAlias => Self::TraitAlias,
-            DefKind::Macro(MacroKind::Bang) => ItemType::Macro,
-            DefKind::Macro(MacroKind::Attr) => ItemType::ProcAttribute,
-            DefKind::Macro(MacroKind::Derive) => ItemType::ProcDerive,
+            DefKind::Macro(MacroKinds::BANG) => ItemType::Macro,
+            DefKind::Macro(MacroKinds::ATTR) => ItemType::ProcAttribute,
+            DefKind::Macro(MacroKinds::DERIVE) => ItemType::ProcDerive,
+            DefKind::Macro(_) => todo!("Handle macros with multiple kinds"),
             DefKind::ForeignTy => Self::ForeignType,
             DefKind::Variant => Self::Variant,
             DefKind::Field => Self::StructField,
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 02ee34aaac6..759f53974f5 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -1656,11 +1656,9 @@ fn display_c_like_variant(
         } else if should_show_enum_discriminant {
             let adt_def = cx.tcx().adt_def(enum_def_id);
             let discr = adt_def.discriminant_for_variant(cx.tcx(), index);
-            if discr.ty.is_signed() {
-                write!(w, "{} = {}", name.as_str(), discr.val as i128)?;
-            } else {
-                write!(w, "{} = {}", name.as_str(), discr.val)?;
-            }
+            // Use `discr`'s `Display` impl to render the value with the correct
+            // signedness, including proper sign-extension for signed types.
+            write!(w, "{} = {}", name.as_str(), discr)?;
         } else {
             write!(w, "{name}")?;
         }
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index bcb676cd1f1..bad51d7f5b2 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -13,7 +13,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::intern::Interned;
 use rustc_errors::{Applicability, Diag, DiagMessage};
 use rustc_hir::def::Namespace::*;
-use rustc_hir::def::{DefKind, Namespace, PerNS};
+use rustc_hir::def::{DefKind, MacroKinds, Namespace, PerNS};
 use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE};
 use rustc_hir::{Mutability, Safety};
 use rustc_middle::ty::{Ty, TyCtxt};
@@ -25,7 +25,6 @@ use rustc_resolve::rustdoc::{
 use rustc_session::config::CrateType;
 use rustc_session::lint::Lint;
 use rustc_span::BytePos;
-use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{Ident, Symbol, sym};
 use smallvec::{SmallVec, smallvec};
 use tracing::{debug, info, instrument, trace};
@@ -115,9 +114,11 @@ impl Res {
 
         let prefix = match kind {
             DefKind::Fn | DefKind::AssocFn => return Suggestion::Function,
-            DefKind::Macro(MacroKind::Bang) => return Suggestion::Macro,
+            // FIXME: handle macros with multiple kinds, and attribute/derive macros that aren't
+            // proc macros
+            DefKind::Macro(MacroKinds::BANG) => return Suggestion::Macro,
 
-            DefKind::Macro(MacroKind::Derive) => "derive",
+            DefKind::Macro(MacroKinds::DERIVE) => "derive",
             DefKind::Struct => "struct",
             DefKind::Enum => "enum",
             DefKind::Trait => "trait",
@@ -881,9 +882,12 @@ fn trait_impls_for<'a>(
 fn is_derive_trait_collision<T>(ns: &PerNS<Result<Vec<(Res, T)>, ResolutionFailure<'_>>>) -> bool {
     if let (Ok(type_ns), Ok(macro_ns)) = (&ns.type_ns, &ns.macro_ns) {
         type_ns.iter().any(|(res, _)| matches!(res, Res::Def(DefKind::Trait, _)))
-            && macro_ns
-                .iter()
-                .any(|(res, _)| matches!(res, Res::Def(DefKind::Macro(MacroKind::Derive), _)))
+            && macro_ns.iter().any(|(res, _)| {
+                matches!(
+                    res,
+                    Res::Def(DefKind::Macro(kinds), _) if kinds.contains(MacroKinds::DERIVE)
+                )
+            })
     } else {
         false
     }
@@ -997,6 +1001,7 @@ fn preprocess_link(
         }
     };
 
+    let is_shortcut_style = ori_link.kind == LinkType::ShortcutUnknown;
     // If there's no backticks, be lenient and revert to the old behavior.
     // This is to prevent churn by linting on stuff that isn't meant to be a link.
     // only shortcut links have simple enough syntax that they
@@ -1013,11 +1018,22 @@ fn preprocess_link(
     // | has backtick |    never ignore    |    never ignore   |
     // | no backtick  | ignore if url-like |    never ignore   |
     // |-------------------------------------------------------|
-    let ignore_urllike =
-        can_be_url || (ori_link.kind == LinkType::ShortcutUnknown && !ori_link.link.contains('`'));
+    let ignore_urllike = can_be_url || (is_shortcut_style && !ori_link.link.contains('`'));
     if ignore_urllike && should_ignore_link(path_str) {
         return None;
     }
+    // If we have an intra-doc link starting with `!` (which isn't `[!]` because this is the never type), we ignore it
+    // as it is never valid.
+    //
+    // The case is common enough because of cases like `#[doc = include_str!("../README.md")]` which often
+    // uses GitHub-flavored Markdown (GFM) admonitions, such as `[!NOTE]`.
+    if is_shortcut_style
+        && let Some(suffix) = ori_link.link.strip_prefix('!')
+        && !suffix.is_empty()
+        && suffix.chars().all(|c| c.is_ascii_alphabetic())
+    {
+        return None;
+    }
 
     // Strip generics from the path.
     let path_str = match strip_generics_from_path(path_str) {
@@ -1662,11 +1678,11 @@ impl Disambiguator {
 
         let suffixes = [
             // If you update this list, please also update the relevant rustdoc book section!
-            ("!()", DefKind::Macro(MacroKind::Bang)),
-            ("!{}", DefKind::Macro(MacroKind::Bang)),
-            ("![]", DefKind::Macro(MacroKind::Bang)),
+            ("!()", DefKind::Macro(MacroKinds::BANG)),
+            ("!{}", DefKind::Macro(MacroKinds::BANG)),
+            ("![]", DefKind::Macro(MacroKinds::BANG)),
             ("()", DefKind::Fn),
-            ("!", DefKind::Macro(MacroKind::Bang)),
+            ("!", DefKind::Macro(MacroKinds::BANG)),
         ];
 
         if let Some(idx) = link.find('@') {
@@ -1685,7 +1701,7 @@ impl Disambiguator {
                     safety: Safety::Safe,
                 }),
                 "function" | "fn" | "method" => Kind(DefKind::Fn),
-                "derive" => Kind(DefKind::Macro(MacroKind::Derive)),
+                "derive" => Kind(DefKind::Macro(MacroKinds::DERIVE)),
                 "field" => Kind(DefKind::Field),
                 "variant" => Kind(DefKind::Variant),
                 "type" => NS(Namespace::TypeNS),
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 9058277d72e..b2e4b594375 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -5,7 +5,7 @@ use std::mem;
 
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def::{DefKind, MacroKinds, Res};
 use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LocalDefIdSet};
 use rustc_hir::intravisit::{Visitor, walk_body, walk_item};
 use rustc_hir::{CRATE_HIR_ID, Node};
@@ -13,7 +13,6 @@ use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::Span;
 use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
-use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{Symbol, kw, sym};
 use tracing::debug;
 
@@ -325,7 +324,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
 
         let is_bang_macro = matches!(
             item,
-            Node::Item(&hir::Item { kind: hir::ItemKind::Macro(_, _, MacroKind::Bang), .. })
+            Node::Item(&hir::Item { kind: hir::ItemKind::Macro(_, _, kinds), .. }) if kinds.contains(MacroKinds::BANG)
         );
 
         if !self.view_item_stack.insert(res_did) && !is_bang_macro {
@@ -406,7 +405,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
             // attribute can still be visible.
             || match item.kind {
                 hir::ItemKind::Impl(..) => true,
-                hir::ItemKind::Macro(_, _, MacroKind::Bang) => {
+                hir::ItemKind::Macro(_, _, _) => {
                     self.cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export)
                 }
                 _ => false,
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 d6469d32931..36498adff50 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
@@ -534,6 +534,7 @@ fn get_item_name(item: &Item<'_>) -> Option<String> {
 
                         if let Some(of_trait) = im.of_trait {
                             let mut trait_segs: Vec<String> = of_trait
+                                .trait_ref
                                 .path
                                 .segments
                                 .iter()
diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
index 581fe33ea0b..f31b67f470f 100644
--- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
@@ -130,18 +130,22 @@ impl<'tcx> LateLintPass<'tcx> for BoolAssertComparison {
 
                 let mut suggestions = vec![(name_span, non_eq_mac.to_string()), (lit_span, String::new())];
 
-                if bool_value ^ eq_macro {
-                    let Some(sugg) = Sugg::hir_opt(cx, non_lit_expr) else {
-                        return;
+                if let Some(sugg) = Sugg::hir_opt(cx, non_lit_expr) {
+                    let sugg = if bool_value ^ eq_macro {
+                        !sugg.maybe_paren()
+                    } else if ty::Bool == *non_lit_ty.kind() {
+                        sugg
+                    } else {
+                        !!sugg.maybe_paren()
                     };
-                    suggestions.push((non_lit_expr.span, (!sugg).to_string()));
-                }
+                    suggestions.push((non_lit_expr.span, sugg.to_string()));
 
-                diag.multipart_suggestion(
-                    format!("replace it with `{non_eq_mac}!(..)`"),
-                    suggestions,
-                    Applicability::MachineApplicable,
-                );
+                    diag.multipart_suggestion(
+                        format!("replace it with `{non_eq_mac}!(..)`"),
+                        suggestions,
+                        Applicability::MachineApplicable,
+                    );
+                }
             },
         );
     }
diff --git a/src/tools/clippy/clippy_lints/src/copy_iterator.rs b/src/tools/clippy/clippy_lints/src/copy_iterator.rs
index 4ecf3e41611..51aebd8b0cf 100644
--- a/src/tools/clippy/clippy_lints/src/copy_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/copy_iterator.rs
@@ -37,12 +37,12 @@ declare_lint_pass!(CopyIterator => [COPY_ITERATOR]);
 impl<'tcx> LateLintPass<'tcx> for CopyIterator {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         if let ItemKind::Impl(Impl {
-            of_trait: Some(trait_ref),
+            of_trait: Some(of_trait),
             ..
         }) = item.kind
             && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
             && is_copy(cx, ty)
-            && let Some(trait_id) = trait_ref.trait_def_id()
+            && let Some(trait_id) = of_trait.trait_ref.trait_def_id()
             && cx.tcx.is_diagnostic_item(sym::Iterator, trait_id)
         {
             span_lint_and_note(
diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
index 0a481ddcd12..7580d6cab66 100644
--- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
@@ -183,14 +183,14 @@ fn check_enum<'tcx>(cx: &LateContext<'tcx>, item: &'tcx Item<'_>, func_expr: &Ex
 impl<'tcx> LateLintPass<'tcx> for DerivableImpls {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         if let ItemKind::Impl(Impl {
-            of_trait: Some(trait_ref),
+            of_trait: Some(of_trait),
             items: [child],
             self_ty,
             ..
         }) = item.kind
             && !cx.tcx.is_automatically_derived(item.owner_id.to_def_id())
             && !item.span.from_expansion()
-            && let Some(def_id) = trait_ref.trait_def_id()
+            && let Some(def_id) = of_trait.trait_ref.trait_def_id()
             && cx.tcx.is_diagnostic_item(sym::Default, def_id)
             && let impl_item_hir = child.hir_id()
             && let Node::ImplItem(impl_item) = cx.tcx.hir_node(impl_item_hir)
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 49dd1bb09c6..c53a957f6a8 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -201,10 +201,11 @@ declare_lint_pass!(Derive => [
 impl<'tcx> LateLintPass<'tcx> for Derive {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         if let ItemKind::Impl(Impl {
-            of_trait: Some(trait_ref),
+            of_trait: Some(of_trait),
             ..
         }) = item.kind
         {
+            let trait_ref = &of_trait.trait_ref;
             let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
             let is_automatically_derived = cx.tcx.is_automatically_derived(item.owner_id.to_def_id());
 
diff --git a/src/tools/clippy/clippy_lints/src/empty_drop.rs b/src/tools/clippy/clippy_lints/src/empty_drop.rs
index 4e948701da4..2b822188434 100644
--- a/src/tools/clippy/clippy_lints/src/empty_drop.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_drop.rs
@@ -36,11 +36,11 @@ declare_lint_pass!(EmptyDrop => [EMPTY_DROP]);
 impl LateLintPass<'_> for EmptyDrop {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
         if let ItemKind::Impl(Impl {
-            of_trait: Some(trait_ref),
+            of_trait: Some(of_trait),
             items: [child],
             ..
         }) = item.kind
-            && trait_ref.trait_def_id() == cx.tcx.lang_items().drop_trait()
+            && of_trait.trait_ref.trait_def_id() == cx.tcx.lang_items().drop_trait()
             && let impl_item_hir = child.hir_id()
             && let Node::ImplItem(impl_item) = cx.tcx.hir_node(impl_item_hir)
             && let ImplItemKind::Fn(_, b) = &impl_item.kind
diff --git a/src/tools/clippy/clippy_lints/src/error_impl_error.rs b/src/tools/clippy/clippy_lints/src/error_impl_error.rs
index 6525648efb1..3018e1f1273 100644
--- a/src/tools/clippy/clippy_lints/src/error_impl_error.rs
+++ b/src/tools/clippy/clippy_lints/src/error_impl_error.rs
@@ -52,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError {
                 );
             },
             ItemKind::Impl(imp)
-                if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id())
+                if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_ref.trait_def_id())
                     && let Some(error_def_id) = cx.tcx.get_diagnostic_item(sym::Error)
                     && error_def_id == trait_def_id
                     && let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local)
diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs
index 0535ecf5240..416aea51ea1 100644
--- a/src/tools/clippy/clippy_lints/src/format_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/format_impl.rs
@@ -254,10 +254,10 @@ fn is_format_trait_impl(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) -> Optio
     if impl_item.ident.name == sym::fmt
         && let ImplItemKind::Fn(_, body_id) = impl_item.kind
         && let Some(Impl {
-            of_trait: Some(trait_ref),
+            of_trait: Some(of_trait),
             ..
         }) = get_parent_as_impl(cx.tcx, impl_item.hir_id())
-        && let Some(did) = trait_ref.trait_def_id()
+        && let Some(did) = of_trait.trait_ref.trait_def_id()
         && let Some(name) = cx.tcx.get_diagnostic_name(did)
         && matches!(name, sym::Debug | sym::Display)
     {
diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs
index 1da6952eb64..e3bb5ee10db 100644
--- a/src/tools/clippy/clippy_lints/src/from_over_into.rs
+++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs
@@ -67,12 +67,12 @@ impl_lint_pass!(FromOverInto => [FROM_OVER_INTO]);
 impl<'tcx> LateLintPass<'tcx> for FromOverInto {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         if let ItemKind::Impl(Impl {
-            of_trait: Some(hir_trait_ref),
+            of_trait: Some(of_trait),
             self_ty,
             items: [impl_item_ref],
             ..
         }) = item.kind
-            && let Some(into_trait_seg) = hir_trait_ref.path.segments.last()
+            && let Some(into_trait_seg) = of_trait.trait_ref.path.segments.last()
             // `impl Into<target_ty> for self_ty`
             && let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args
             && span_is_local(item.span)
diff --git a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
index cb83b1395d2..3105e303ae3 100644
--- a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
@@ -54,8 +54,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
     if let ImplItemKind::Fn(_, body_id) = impl_item.kind
         && let hir::Node::Item(item) = cx.tcx.parent_hir_node(impl_item.hir_id())
         && let hir::ItemKind::Impl(impl_) = item.kind
-        && let hir::Impl { of_trait, .. } = *impl_
-        && of_trait.is_none()
+        && let hir::Impl { of_trait: None, .. } = impl_
         && let body = cx.tcx.hir_body(body_id)
         && cx.tcx.visibility(cx.tcx.hir_body_owner_def_id(body.id())).is_public()
         && !is_in_test(cx.tcx, impl_item.hir_id())
diff --git a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs
index 0d6191f2c97..0a7c6e9d5f8 100644
--- a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs
@@ -15,11 +15,11 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &ImplItem<'_>, ignored
         && let parent_node = cx.tcx.parent_hir_node(item.hir_id())
         && let Node::Item(parent_item) = parent_node
         && let ItemKind::Impl(Impl {
-            of_trait: Some(trait_ref),
+            of_trait: Some(of_trait),
             ..
         }) = &parent_item.kind
         && let Some(did) = trait_item_def_id_of_impl(cx, item.owner_id)
-        && !is_from_ignored_trait(trait_ref, ignored_traits)
+        && !is_from_ignored_trait(&of_trait.trait_ref, ignored_traits)
     {
         let mut param_idents_iter = cx.tcx.hir_body_param_idents(body_id);
         let mut default_param_idents_iter = cx.tcx.fn_arg_idents(did).iter().copied();
diff --git a/src/tools/clippy/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs b/src/tools/clippy/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs
index 940adbae428..f73182d3af0 100644
--- a/src/tools/clippy/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs
+++ b/src/tools/clippy/clippy_lints/src/impl_hash_with_borrow_str_and_bytes.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::ty::implements_trait;
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{Item, ItemKind, Path, TraitRef};
+use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::Ty;
 use rustc_session::declare_lint_pass;
@@ -76,10 +76,10 @@ impl LateLintPass<'_> for ImplHashWithBorrowStrBytes {
     /// three of `Hash`, `Borrow<str>` and `Borrow<[u8]>`.
     fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
         if let ItemKind::Impl(imp) = item.kind
-            && let Some(TraitRef {path: Path {span, res, ..}, ..}) = imp.of_trait
+            && let Some(of_trait) = imp.of_trait
             && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
             && let Some(hash_id) = cx.tcx.get_diagnostic_item(sym::Hash)
-            && Res::Def(DefKind::Trait, hash_id) == *res
+            && Res::Def(DefKind::Trait, hash_id) == of_trait.trait_ref.path.res
             && let Some(borrow_id) = cx.tcx.get_diagnostic_item(sym::Borrow)
             // since we are in the `Hash` impl, we don't need to check for that.
             // we need only to check for `Borrow<str>` and `Borrow<[u8]>`
@@ -89,7 +89,7 @@ impl LateLintPass<'_> for ImplHashWithBorrowStrBytes {
             span_lint_and_then(
                 cx,
                 IMPL_HASH_BORROW_WITH_STR_AND_BYTES,
-                *span,
+                of_trait.trait_ref.path.span,
                 "the semantics of `Borrow<T>` around `Hash` can't be satisfied when both `Borrow<str>` and `Borrow<[u8]>` are implemented",
                 |diag| {
                     diag.note("the `Borrow` semantics require that `Hash` must behave the same for all implementations of Borrow<T>");
diff --git a/src/tools/clippy/clippy_lints/src/infallible_try_from.rs b/src/tools/clippy/clippy_lints/src/infallible_try_from.rs
index 589c294a678..36df07a4370 100644
--- a/src/tools/clippy/clippy_lints/src/infallible_try_from.rs
+++ b/src/tools/clippy/clippy_lints/src/infallible_try_from.rs
@@ -45,8 +45,8 @@ 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 {
+        let Some(of_trait) = imp.of_trait else { return };
+        let Some(trait_def_id) = of_trait.trait_ref.trait_def_id() else {
             return;
         };
         if !cx.tcx.is_diagnostic_item(sym::TryFrom, trait_def_id) {
diff --git a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
index 95e16aae40f..945bb84708f 100644
--- a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
+++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
@@ -8,7 +8,6 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, QPath, TyKind, Variant, VariantData};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
-use rustc_span::MacroKind;
 use rustc_span::symbol::Symbol;
 
 declare_clippy_lint! {
@@ -503,8 +502,8 @@ impl LateLintPass<'_> for ItemNameRepetitions {
                 );
             }
 
-            let is_macro_rule = matches!(item.kind, ItemKind::Macro(_, _, MacroKind::Bang));
-            if both_are_public && item_camel.len() > mod_camel.len() && !is_macro_rule {
+            let is_macro = matches!(item.kind, ItemKind::Macro(_, _, _));
+            if both_are_public && item_camel.len() > mod_camel.len() && !is_macro {
                 let matching = count_match_start(mod_camel, &item_camel);
                 let rmatching = count_match_end(mod_camel, &item_camel);
                 let nchars = mod_camel.chars().count();
diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
index b89f91f7255..645e0f981f2 100644
--- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
@@ -125,8 +125,9 @@ impl LateLintPass<'_> for IterWithoutIntoIter {
     fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) {
         if let ItemKind::Impl(imp) = item.kind
             && let TyKind::Ref(_, self_ty_without_ref) = &imp.self_ty.kind
-            && let Some(trait_ref) = imp.of_trait
-            && trait_ref
+            && let Some(of_trait) = imp.of_trait
+            && of_trait
+                .trait_ref
                 .trait_def_id()
                 .is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did))
             && !item.span.in_external_macro(cx.sess().source_map())
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 35c9d2fd4eb..149ae5e710c 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -150,7 +150,7 @@ impl<'tcx> LateLintPass<'tcx> for Lifetimes {
         } = item.kind
         {
             check_fn_inner(cx, sig, Some(id), None, generics, item.span, true, self.msrv);
-        } else if let ItemKind::Impl(impl_) = item.kind
+        } else if let ItemKind::Impl(impl_) = &item.kind
             && !item.span.from_expansion()
         {
             report_extra_impl_lifetimes(cx, impl_);
@@ -712,8 +712,8 @@ fn report_extra_impl_lifetimes<'tcx>(cx: &LateContext<'tcx>, impl_: &'tcx Impl<'
     let mut checker = LifetimeChecker::<middle_nested_filter::All>::new(cx, impl_.generics);
 
     walk_generics(&mut checker, impl_.generics);
-    if let Some(ref trait_ref) = impl_.of_trait {
-        walk_trait_ref(&mut checker, trait_ref);
+    if let Some(of_trait) = impl_.of_trait {
+        walk_trait_ref(&mut checker, &of_trait.trait_ref);
     }
     walk_unambig_ty(&mut checker, impl_.self_ty);
     for &item in impl_.items {
diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
index 18e2b384a46..8822b32b1c3 100644
--- a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
@@ -198,8 +198,8 @@ fn check_struct<'tcx>(
 impl<'tcx> LateLintPass<'tcx> for MissingFieldsInDebug {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
         // is this an `impl Debug for X` block?
-        if let ItemKind::Impl(Impl { of_trait: Some(trait_ref), self_ty, .. }) = item.kind
-            && let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res
+        if let ItemKind::Impl(Impl { of_trait: Some(of_trait), self_ty, .. }) = item.kind
+            && let Res::Def(DefKind::Trait, trait_def_id) = of_trait.trait_ref.path.res
             && let TyKind::Path(QPath::Resolved(_, self_path)) = &self_ty.kind
             // make sure that the self type is either a struct, an enum or a union
             // this prevents ICEs such as when self is a type parameter or a primitive type
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index d02952eb487..b16924babd1 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -190,5 +190,5 @@ impl<'tcx> LateLintPass<'tcx> for MissingInline {
 /// and a rustc warning would be triggered, see #15301
 fn fn_is_externally_exported(cx: &LateContext<'_>, def_id: DefId) -> bool {
     let attrs = cx.tcx.codegen_fn_attrs(def_id);
-    attrs.contains_extern_indicator()
+    attrs.contains_extern_indicator(cx.tcx, def_id)
 }
diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
index 399bf4e1806..9cc93bf0653 100644
--- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
@@ -61,10 +61,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingTraitMethods {
         if !is_lint_allowed(cx, MISSING_TRAIT_METHODS, item.hir_id())
             && span_is_local(item.span)
             && let ItemKind::Impl(Impl {
-                of_trait: Some(trait_ref),
+                of_trait: Some(of_trait),
                 ..
             }) = item.kind
-            && let Some(trait_id) = trait_ref.trait_def_id()
+            && let Some(trait_id) = of_trait.trait_ref.trait_def_id()
         {
             let trait_item_ids: DefIdSet = cx
                 .tcx
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 388c029c9ef..8a5a6f4a4dc 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -778,7 +778,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst<'tcx> {
                     if let Node::Item(parent_item) = cx.tcx.parent_hir_node(item.hir_id())
                         && let ItemKind::Impl(impl_block) = parent_item.kind
                         && let Some(of_trait) = impl_block.of_trait
-                        && let Some(trait_id) = of_trait.trait_def_id()
+                        && let Some(trait_id) = of_trait.trait_ref.trait_def_id()
                     {
                         // Replace all instances of `<Self as Trait>::AssocType` with the
                         // unit type and check again. If the result is the same then the
diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
index 8ff78ec7c58..b810bc01fbd 100644
--- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
+++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
@@ -83,10 +83,10 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy {
         if !item.span.in_external_macro(cx.tcx.sess.source_map())
             && let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send)
             && let ItemKind::Impl(hir_impl) = &item.kind
-            && let Some(trait_ref) = &hir_impl.of_trait
-            && let Some(trait_id) = trait_ref.trait_def_id()
+            && let Some(of_trait) = &hir_impl.of_trait
+            && let Some(trait_id) = of_trait.trait_ref.trait_def_id()
             && send_trait == trait_id
-            && hir_impl.polarity == ImplPolarity::Positive
+            && of_trait.polarity == ImplPolarity::Positive
             && let Some(ty_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
             && let self_ty = ty_trait_ref.instantiate_identity().self_ty()
             && let ty::Adt(adt_def, impl_trait_args) = self_ty.kind()
diff --git a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
index 0a1f2625f4c..9c160ff680e 100644
--- a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
@@ -183,7 +183,7 @@ fn in_impl<'tcx>(
         && let item = cx.tcx.hir_expect_item(impl_def_id.expect_local())
         && let ItemKind::Impl(item) = &item.kind
         && let Some(of_trait) = &item.of_trait
-        && let Some(seg) = of_trait.path.segments.last()
+        && let Some(seg) = of_trait.trait_ref.path.segments.last()
         && let Res::Def(_, trait_id) = seg.res
         && trait_id == bin_op
         && let Some(generic_args) = seg.args
diff --git a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
index 301b2cd4bf2..77751e75a8e 100644
--- a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
@@ -34,15 +34,15 @@ declare_lint_pass!(PartialEqNeImpl => [PARTIALEQ_NE_IMPL]);
 impl<'tcx> LateLintPass<'tcx> for PartialEqNeImpl {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         if let ItemKind::Impl(Impl {
-            of_trait: Some(trait_ref),
+            of_trait: Some(of_trait),
             items: impl_items,
             ..
         }) = item.kind
             && !cx.tcx.is_automatically_derived(item.owner_id.to_def_id())
             && let Some(eq_trait) = cx.tcx.lang_items().eq_trait()
-            && trait_ref.path.res.def_id() == eq_trait
+            && of_trait.trait_ref.path.res.def_id() == eq_trait
         {
-            for impl_item in *impl_items {
+            for impl_item in impl_items {
                 if cx.tcx.item_name(impl_item.owner_id) == sym::ne {
                     span_lint_hir(
                         cx,
diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
index 3828aff4164..902e8af7ec4 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
@@ -7,7 +7,6 @@ use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
 use rustc_session::impl_lint_pass;
 use rustc_span::def_id::CRATE_DEF_ID;
-use rustc_span::hygiene::MacroKind;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -89,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
 // We ignore macro exports. And `ListStem` uses, which aren't interesting.
 fn is_ignorable_export<'tcx>(item: &'tcx Item<'tcx>) -> bool {
     if let ItemKind::Use(path, kind) = item.kind {
-        let ignore = matches!(path.res.macro_ns, Some(Res::Def(DefKind::Macro(MacroKind::Bang), _)))
+        let ignore = matches!(path.res.macro_ns, Some(Res::Def(DefKind::Macro(_), _)))
             || kind == UseKind::ListStem;
         if ignore {
             return true;
diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs
index 67eb71f7d07..b87751f4986 100644
--- a/src/tools/clippy/clippy_lints/src/same_name_method.rs
+++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs
@@ -68,9 +68,9 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
                 let existing_name = map.get_mut(res).unwrap();
 
                 match of_trait {
-                    Some(trait_ref) => {
+                    Some(of_trait) => {
                         let mut methods_in_trait: BTreeSet<Symbol> = if let Node::TraitRef(TraitRef { path, .. }) =
-                            cx.tcx.hir_node(trait_ref.hir_ref_id)
+                            cx.tcx.hir_node(of_trait.trait_ref.hir_ref_id)
                             && let Res::Def(DefKind::Trait, did) = path.res
                         {
                             // FIXME: if
diff --git a/src/tools/clippy/clippy_lints/src/serde_api.rs b/src/tools/clippy/clippy_lints/src/serde_api.rs
index 2de22e4b6a3..01c7f394b9a 100644
--- a/src/tools/clippy/clippy_lints/src/serde_api.rs
+++ b/src/tools/clippy/clippy_lints/src/serde_api.rs
@@ -26,16 +26,16 @@ declare_lint_pass!(SerdeApi => [SERDE_API_MISUSE]);
 impl<'tcx> LateLintPass<'tcx> for SerdeApi {
     fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
         if let ItemKind::Impl(Impl {
-            of_trait: Some(trait_ref),
+            of_trait: Some(of_trait),
             items,
             ..
         }) = item.kind
         {
-            let did = trait_ref.path.res.def_id();
+            let did = of_trait.trait_ref.path.res.def_id();
             if paths::SERDE_DE_VISITOR.matches(cx, did) {
                 let mut seen_str = None;
                 let mut seen_string = None;
-                for item in *items {
+                for item in items {
                     match cx.tcx.item_name(item.owner_id) {
                         sym::visit_str => seen_str = Some(cx.tcx.def_span(item.owner_id)),
                         sym::visit_string => seen_string = Some(cx.tcx.def_span(item.owner_id)),
diff --git a/src/tools/clippy/clippy_lints/src/to_string_trait_impl.rs b/src/tools/clippy/clippy_lints/src/to_string_trait_impl.rs
index 9596b85664b..303f6028bd5 100644
--- a/src/tools/clippy/clippy_lints/src/to_string_trait_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/to_string_trait_impl.rs
@@ -48,10 +48,10 @@ declare_lint_pass!(ToStringTraitImpl => [TO_STRING_TRAIT_IMPL]);
 impl<'tcx> LateLintPass<'tcx> for ToStringTraitImpl {
     fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'tcx>) {
         if let ItemKind::Impl(Impl {
-            of_trait: Some(trait_ref),
+            of_trait: Some(of_trait),
             ..
         }) = it.kind
-            && let Some(trait_did) = trait_ref.trait_def_id()
+            && let Some(trait_did) = of_trait.trait_ref.trait_def_id()
             && cx.tcx.is_diagnostic_item(sym::ToString, trait_did)
         {
             span_lint_and_help(
diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
index dcddff557d1..e843e169113 100644
--- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
@@ -137,9 +137,9 @@ fn get_impl_trait_def_id(cx: &LateContext<'_>, method_def_id: LocalDefId) -> Opt
         // We exclude `impl` blocks generated from rustc's proc macros.
         && !cx.tcx.is_automatically_derived(owner_id.to_def_id())
         // It is a implementation of a trait.
-        && let Some(trait_) = impl_.of_trait
+        && let Some(of_trait) = impl_.of_trait
     {
-        trait_.trait_def_id()
+        of_trait.trait_ref.trait_def_id()
     } else {
         None
     }
@@ -242,8 +242,8 @@ fn check_to_string(cx: &LateContext<'_>, method_span: Span, method_def_id: Local
         // We exclude `impl` blocks generated from rustc's proc macros.
         && !cx.tcx.is_automatically_derived(owner_id.to_def_id())
         // It is a implementation of a trait.
-        && let Some(trait_) = impl_.of_trait
-        && let Some(trait_def_id) = trait_.trait_def_id()
+        && let Some(of_trait) = impl_.of_trait
+        && let Some(trait_def_id) = of_trait.trait_ref.trait_def_id()
         // The trait is `ToString`.
         && cx.tcx.is_diagnostic_item(sym::ToString, trait_def_id)
     {
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index cf603c6190b..1c52de52619 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -8,7 +8,7 @@ use clippy_utils::source::walk_span_to_context;
 use clippy_utils::visitors::{Descend, for_each_expr};
 use hir::HirId;
 use rustc_hir as hir;
-use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource};
+use rustc_hir::{Block, BlockCheckMode, Impl, ItemKind, Node, UnsafeSource};
 use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::impl_lint_pass;
@@ -204,7 +204,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
         let item_has_safety_comment = item_has_safety_comment(cx, item);
         match (&item.kind, item_has_safety_comment) {
             // lint unsafe impl without safety comment
-            (ItemKind::Impl(impl_), HasSafetyComment::No) if impl_.safety.is_unsafe() => {
+            (ItemKind::Impl(Impl { of_trait: Some(of_trait), .. }), HasSafetyComment::No) if of_trait.safety.is_unsafe() => {
                 if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id())
                     && !is_unsafe_from_proc_macro(cx, item.span)
                 {
@@ -228,7 +228,7 @@ impl<'tcx> LateLintPass<'tcx> for UndocumentedUnsafeBlocks {
                 }
             },
             // lint safe impl with unnecessary safety comment
-            (ItemKind::Impl(impl_), HasSafetyComment::Yes(pos)) if impl_.safety.is_safe() => {
+            (ItemKind::Impl(Impl { of_trait: Some(of_trait), .. }), HasSafetyComment::Yes(pos)) if of_trait.safety.is_safe() => {
                 if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) {
                     let (span, help_span) = mk_spans(pos);
 
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index d9a007635ca..a15e4e42e71 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -347,10 +347,10 @@ impl<'tcx> LateLintPass<'tcx> for Write {
 
 fn is_debug_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
     if let ItemKind::Impl(Impl {
-        of_trait: Some(trait_ref),
+        of_trait: Some(of_trait),
         ..
     }) = &item.kind
-        && let Some(trait_id) = trait_ref.trait_def_id()
+        && let Some(trait_id) = of_trait.trait_ref.trait_def_id()
     {
         cx.tcx.is_diagnostic_item(sym::Debug, trait_id)
     } else {
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
index 0312bf56e59..24e017f7cf7 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
@@ -473,33 +473,27 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
             eq_id(*li, *ri) && eq_generics(lg, rg) && over(lb, rb, eq_generic_bound)
         },
         (
-            Impl(box ast::Impl {
-                safety: lu,
-                polarity: lp,
-                defaultness: ld,
-                constness: lc,
+            Impl(ast::Impl {
                 generics: lg,
                 of_trait: lot,
                 self_ty: lst,
                 items: li,
             }),
-            Impl(box ast::Impl {
-                safety: ru,
-                polarity: rp,
-                defaultness: rd,
-                constness: rc,
+            Impl(ast::Impl {
                 generics: rg,
                 of_trait: rot,
                 self_ty: rst,
                 items: ri,
             }),
         ) => {
-            matches!(lu, Safety::Default) == matches!(ru, Safety::Default)
-                && matches!(lp, ImplPolarity::Positive) == matches!(rp, ImplPolarity::Positive)
-                && eq_defaultness(*ld, *rd)
-                && matches!(lc, ast::Const::No) == matches!(rc, ast::Const::No)
-                && eq_generics(lg, rg)
-                && both(lot.as_ref(), rot.as_ref(), |l, r| eq_path(&l.path, &r.path))
+            eq_generics(lg, rg)
+                && both(lot.as_deref(), rot.as_deref(), |l, r| {
+                    matches!(l.safety, Safety::Default) == matches!(r.safety, Safety::Default)
+                        && matches!(l.polarity, ImplPolarity::Positive) == matches!(r.polarity, ImplPolarity::Positive)
+                        && eq_defaultness(l.defaultness, r.defaultness)
+                        && matches!(l.constness, ast::Const::No) == matches!(r.constness, ast::Const::No)
+                        && eq_path(&l.trait_ref.path, &r.trait_ref.path)
+                })
                 && eq_ty(lst, rst)
                 && over(li, ri, |l, r| eq_item(l, r, eq_assoc_item_kind))
         },
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index dc31ed08fb7..e0c1b9d445a 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -19,8 +19,8 @@ use rustc_ast::token::CommentKind;
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
     Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl,
-    ImplItem, ImplItemKind, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path, QPath, Safety,
-    TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource,
+    ImplItem, ImplItemKind, TraitImplHeader, IsAuto, Item, ItemKind, Lit, LoopSource, MatchSource, MutTy, Node, Path,
+    QPath, Safety, TraitItem, TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource,
 };
 use rustc_lint::{EarlyContext, LateContext, LintContext};
 use rustc_middle::ty::TyCtxt;
@@ -254,7 +254,7 @@ fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) {
         ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")),
         ItemKind::Trait(_, _, Safety::Unsafe, ..)
         | ItemKind::Impl(Impl {
-            safety: Safety::Unsafe, ..
+            of_trait: Some(TraitImplHeader { safety: Safety::Unsafe, .. }), ..
         }) => (Pat::Str("unsafe"), Pat::Str("}")),
         ItemKind::Trait(_, IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")),
         ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")),
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index fc716d86fc6..fcc120656e3 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -528,8 +528,9 @@ pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>
 pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, owner: OwnerId) -> Option<&'tcx TraitRef<'tcx>> {
     if let Node::Item(item) = cx.tcx.hir_node(cx.tcx.hir_owner_parent(owner))
         && let ItemKind::Impl(impl_) = &item.kind
+        && let Some(of_trait) = impl_.of_trait
     {
-        return impl_.of_trait.as_ref();
+        return Some(&of_trait.trait_ref);
     }
     None
 }
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index ba5cbc73836..c9f5401ebe7 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -460,7 +460,8 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
         }
         fn visit_nested_item(&mut self, id: ItemId) -> Self::Result {
             if let ItemKind::Impl(i) = &self.cx.tcx.hir_item(id).kind
-                && i.safety.is_unsafe()
+                && let Some(of_trait) = i.of_trait
+                && of_trait.safety.is_unsafe()
             {
                 ControlFlow::Break(())
             } else {
diff --git a/src/tools/clippy/tests/missing-test-files.rs b/src/tools/clippy/tests/missing-test-files.rs
index 565dcd73f58..63f960c92fa 100644
--- a/src/tools/clippy/tests/missing-test-files.rs
+++ b/src/tools/clippy/tests/missing-test-files.rs
@@ -1,6 +1,6 @@
 #![warn(rust_2018_idioms, unused_lifetimes)]
 #![allow(clippy::assertions_on_constants)]
-#![feature(path_file_prefix)]
+#![cfg_attr(bootstrap, feature(path_file_prefix))]
 
 use std::cmp::Ordering;
 use std::ffi::OsStr;
diff --git a/src/tools/clippy/tests/ui/bool_assert_comparison.fixed b/src/tools/clippy/tests/ui/bool_assert_comparison.fixed
index 721d8b2c2dc..ec76abbef05 100644
--- a/src/tools/clippy/tests/ui/bool_assert_comparison.fixed
+++ b/src/tools/clippy/tests/ui/bool_assert_comparison.fixed
@@ -1,7 +1,7 @@
 #![allow(unused, clippy::assertions_on_constants, clippy::const_is_empty)]
 #![warn(clippy::bool_assert_comparison)]
 
-use std::ops::Not;
+use std::ops::{Add, Not};
 
 macro_rules! a {
     () => {
@@ -62,6 +62,14 @@ impl Not for ImplNotTraitWithBool {
     }
 }
 
+impl Add for ImplNotTraitWithBool {
+    type Output = Self;
+
+    fn add(self, other: Self) -> Self::Output {
+        self
+    }
+}
+
 #[derive(Debug)]
 struct NonCopy;
 
@@ -94,7 +102,7 @@ fn main() {
     assert_eq!(a!(), "".is_empty());
     assert_eq!("".is_empty(), b!());
     assert_eq!(a, true);
-    assert!(b);
+    assert!(!!b);
     //~^ bool_assert_comparison
 
     assert_ne!("a".len(), 1);
@@ -122,7 +130,7 @@ fn main() {
     debug_assert_eq!(a!(), "".is_empty());
     debug_assert_eq!("".is_empty(), b!());
     debug_assert_eq!(a, true);
-    debug_assert!(b);
+    debug_assert!(!!b);
     //~^ bool_assert_comparison
 
     debug_assert_ne!("a".len(), 1);
@@ -167,7 +175,7 @@ fn main() {
 
     use debug_assert_eq as renamed;
     renamed!(a, true);
-    debug_assert!(b);
+    debug_assert!(!!b);
     //~^ bool_assert_comparison
 
     let non_copy = NonCopy;
@@ -199,4 +207,12 @@ fn main() {
     //~^ bool_assert_comparison
     debug_assert!(!"requires negation".is_empty());
     //~^ bool_assert_comparison
+    assert!(!b);
+    //~^ bool_assert_comparison
+    assert!(!(!b));
+    //~^ bool_assert_comparison
+    assert!(!!(b + b));
+    //~^ bool_assert_comparison
+    assert!(!(b + b));
+    //~^ bool_assert_comparison
 }
diff --git a/src/tools/clippy/tests/ui/bool_assert_comparison.rs b/src/tools/clippy/tests/ui/bool_assert_comparison.rs
index 5ab4f475b06..40824a23c82 100644
--- a/src/tools/clippy/tests/ui/bool_assert_comparison.rs
+++ b/src/tools/clippy/tests/ui/bool_assert_comparison.rs
@@ -1,7 +1,7 @@
 #![allow(unused, clippy::assertions_on_constants, clippy::const_is_empty)]
 #![warn(clippy::bool_assert_comparison)]
 
-use std::ops::Not;
+use std::ops::{Add, Not};
 
 macro_rules! a {
     () => {
@@ -62,6 +62,14 @@ impl Not for ImplNotTraitWithBool {
     }
 }
 
+impl Add for ImplNotTraitWithBool {
+    type Output = Self;
+
+    fn add(self, other: Self) -> Self::Output {
+        self
+    }
+}
+
 #[derive(Debug)]
 struct NonCopy;
 
@@ -199,4 +207,12 @@ fn main() {
     //~^ bool_assert_comparison
     debug_assert_eq!("requires negation".is_empty(), false);
     //~^ bool_assert_comparison
+    assert_eq!(!b, true);
+    //~^ bool_assert_comparison
+    assert_eq!(!b, false);
+    //~^ bool_assert_comparison
+    assert_eq!(b + b, true);
+    //~^ bool_assert_comparison
+    assert_eq!(b + b, false);
+    //~^ bool_assert_comparison
 }
diff --git a/src/tools/clippy/tests/ui/bool_assert_comparison.stderr b/src/tools/clippy/tests/ui/bool_assert_comparison.stderr
index a1d0af54361..f823f08f31d 100644
--- a/src/tools/clippy/tests/ui/bool_assert_comparison.stderr
+++ b/src/tools/clippy/tests/ui/bool_assert_comparison.stderr
@@ -1,5 +1,5 @@
 error: used `assert_eq!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:87:5
+  --> tests/ui/bool_assert_comparison.rs:95:5
    |
 LL |     assert_eq!("a".is_empty(), false);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL +     assert!(!"a".is_empty());
    |
 
 error: used `assert_eq!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:89:5
+  --> tests/ui/bool_assert_comparison.rs:97:5
    |
 LL |     assert_eq!("".is_empty(), true);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL +     assert!("".is_empty());
    |
 
 error: used `assert_eq!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:91:5
+  --> tests/ui/bool_assert_comparison.rs:99:5
    |
 LL |     assert_eq!(true, "".is_empty());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -37,7 +37,7 @@ LL +     assert!("".is_empty());
    |
 
 error: used `assert_eq!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:97:5
+  --> tests/ui/bool_assert_comparison.rs:105:5
    |
 LL |     assert_eq!(b, true);
    |     ^^^^^^^^^^^^^^^^^^^
@@ -45,11 +45,11 @@ LL |     assert_eq!(b, true);
 help: replace it with `assert!(..)`
    |
 LL -     assert_eq!(b, true);
-LL +     assert!(b);
+LL +     assert!(!!b);
    |
 
 error: used `assert_ne!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:101:5
+  --> tests/ui/bool_assert_comparison.rs:109:5
    |
 LL |     assert_ne!("a".is_empty(), false);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -61,7 +61,7 @@ LL +     assert!("a".is_empty());
    |
 
 error: used `assert_ne!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:103:5
+  --> tests/ui/bool_assert_comparison.rs:111:5
    |
 LL |     assert_ne!("".is_empty(), true);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -73,7 +73,7 @@ LL +     assert!(!"".is_empty());
    |
 
 error: used `assert_ne!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:105:5
+  --> tests/ui/bool_assert_comparison.rs:113:5
    |
 LL |     assert_ne!(true, "".is_empty());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -85,7 +85,7 @@ LL +     assert!(!"".is_empty());
    |
 
 error: used `assert_ne!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:111:5
+  --> tests/ui/bool_assert_comparison.rs:119:5
    |
 LL |     assert_ne!(b, true);
    |     ^^^^^^^^^^^^^^^^^^^
@@ -97,7 +97,7 @@ LL +     assert!(!b);
    |
 
 error: used `debug_assert_eq!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:115:5
+  --> tests/ui/bool_assert_comparison.rs:123:5
    |
 LL |     debug_assert_eq!("a".is_empty(), false);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -109,7 +109,7 @@ LL +     debug_assert!(!"a".is_empty());
    |
 
 error: used `debug_assert_eq!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:117:5
+  --> tests/ui/bool_assert_comparison.rs:125:5
    |
 LL |     debug_assert_eq!("".is_empty(), true);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -121,7 +121,7 @@ LL +     debug_assert!("".is_empty());
    |
 
 error: used `debug_assert_eq!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:119:5
+  --> tests/ui/bool_assert_comparison.rs:127:5
    |
 LL |     debug_assert_eq!(true, "".is_empty());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -133,7 +133,7 @@ LL +     debug_assert!("".is_empty());
    |
 
 error: used `debug_assert_eq!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:125:5
+  --> tests/ui/bool_assert_comparison.rs:133:5
    |
 LL |     debug_assert_eq!(b, true);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -141,11 +141,11 @@ LL |     debug_assert_eq!(b, true);
 help: replace it with `debug_assert!(..)`
    |
 LL -     debug_assert_eq!(b, true);
-LL +     debug_assert!(b);
+LL +     debug_assert!(!!b);
    |
 
 error: used `debug_assert_ne!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:129:5
+  --> tests/ui/bool_assert_comparison.rs:137:5
    |
 LL |     debug_assert_ne!("a".is_empty(), false);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -157,7 +157,7 @@ LL +     debug_assert!("a".is_empty());
    |
 
 error: used `debug_assert_ne!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:131:5
+  --> tests/ui/bool_assert_comparison.rs:139:5
    |
 LL |     debug_assert_ne!("".is_empty(), true);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -169,7 +169,7 @@ LL +     debug_assert!(!"".is_empty());
    |
 
 error: used `debug_assert_ne!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:133:5
+  --> tests/ui/bool_assert_comparison.rs:141:5
    |
 LL |     debug_assert_ne!(true, "".is_empty());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -181,7 +181,7 @@ LL +     debug_assert!(!"".is_empty());
    |
 
 error: used `debug_assert_ne!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:139:5
+  --> tests/ui/bool_assert_comparison.rs:147:5
    |
 LL |     debug_assert_ne!(b, true);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -193,7 +193,7 @@ LL +     debug_assert!(!b);
    |
 
 error: used `assert_eq!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:145:5
+  --> tests/ui/bool_assert_comparison.rs:153:5
    |
 LL |     assert_eq!("a".is_empty(), false, "tadam {}", 1);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -205,7 +205,7 @@ LL +     assert!(!"a".is_empty(), "tadam {}", 1);
    |
 
 error: used `assert_eq!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:147:5
+  --> tests/ui/bool_assert_comparison.rs:155:5
    |
 LL |     assert_eq!("a".is_empty(), false, "tadam {}", true);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -217,7 +217,7 @@ LL +     assert!(!"a".is_empty(), "tadam {}", true);
    |
 
 error: used `assert_eq!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:149:5
+  --> tests/ui/bool_assert_comparison.rs:157:5
    |
 LL |     assert_eq!(false, "a".is_empty(), "tadam {}", true);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -229,7 +229,7 @@ LL +     assert!(!"a".is_empty(), "tadam {}", true);
    |
 
 error: used `debug_assert_eq!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:155:5
+  --> tests/ui/bool_assert_comparison.rs:163:5
    |
 LL |     debug_assert_eq!("a".is_empty(), false, "tadam {}", 1);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -241,7 +241,7 @@ LL +     debug_assert!(!"a".is_empty(), "tadam {}", 1);
    |
 
 error: used `debug_assert_eq!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:157:5
+  --> tests/ui/bool_assert_comparison.rs:165:5
    |
 LL |     debug_assert_eq!("a".is_empty(), false, "tadam {}", true);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -253,7 +253,7 @@ LL +     debug_assert!(!"a".is_empty(), "tadam {}", true);
    |
 
 error: used `debug_assert_eq!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:159:5
+  --> tests/ui/bool_assert_comparison.rs:167:5
    |
 LL |     debug_assert_eq!(false, "a".is_empty(), "tadam {}", true);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -265,31 +265,35 @@ LL +     debug_assert!(!"a".is_empty(), "tadam {}", true);
    |
 
 error: used `assert_eq!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:163:5
+  --> tests/ui/bool_assert_comparison.rs:171:5
    |
 LL |     assert_eq!(a!(), true);
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
 help: replace it with `assert!(..)`
    |
-LL -     assert_eq!(a!(), true);
-LL +     assert!(a!());
+LL |         true
+...
+LL |
+LL ~     assert!(a!());
    |
 
 error: used `assert_eq!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:165:5
+  --> tests/ui/bool_assert_comparison.rs:173:5
    |
 LL |     assert_eq!(true, b!());
    |     ^^^^^^^^^^^^^^^^^^^^^^
    |
 help: replace it with `assert!(..)`
    |
-LL -     assert_eq!(true, b!());
-LL +     assert!(b!());
+LL |         true
+...
+LL |
+LL ~     assert!(b!());
    |
 
 error: used `debug_assert_eq!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:170:5
+  --> tests/ui/bool_assert_comparison.rs:178:5
    |
 LL |     renamed!(b, true);
    |     ^^^^^^^^^^^^^^^^^
@@ -297,11 +301,11 @@ LL |     renamed!(b, true);
 help: replace it with `debug_assert!(..)`
    |
 LL -     renamed!(b, true);
-LL +     debug_assert!(b);
+LL +     debug_assert!(!!b);
    |
 
 error: used `assert_eq!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:185:5
+  --> tests/ui/bool_assert_comparison.rs:193:5
    |
 LL |     assert_eq!("".is_empty(), true);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -313,7 +317,7 @@ LL +     assert!("".is_empty());
    |
 
 error: used `assert_ne!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:187:5
+  --> tests/ui/bool_assert_comparison.rs:195:5
    |
 LL |     assert_ne!("".is_empty(), false);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -325,7 +329,7 @@ LL +     assert!("".is_empty());
    |
 
 error: used `assert_ne!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:189:5
+  --> tests/ui/bool_assert_comparison.rs:197:5
    |
 LL |     assert_ne!("requires negation".is_empty(), true);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -337,7 +341,7 @@ LL +     assert!(!"requires negation".is_empty());
    |
 
 error: used `assert_eq!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:191:5
+  --> tests/ui/bool_assert_comparison.rs:199:5
    |
 LL |     assert_eq!("requires negation".is_empty(), false);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -349,7 +353,7 @@ LL +     assert!(!"requires negation".is_empty());
    |
 
 error: used `debug_assert_eq!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:194:5
+  --> tests/ui/bool_assert_comparison.rs:202:5
    |
 LL |     debug_assert_eq!("".is_empty(), true);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -361,7 +365,7 @@ LL +     debug_assert!("".is_empty());
    |
 
 error: used `debug_assert_ne!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:196:5
+  --> tests/ui/bool_assert_comparison.rs:204:5
    |
 LL |     debug_assert_ne!("".is_empty(), false);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -373,7 +377,7 @@ LL +     debug_assert!("".is_empty());
    |
 
 error: used `debug_assert_ne!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:198:5
+  --> tests/ui/bool_assert_comparison.rs:206:5
    |
 LL |     debug_assert_ne!("requires negation".is_empty(), true);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -385,7 +389,7 @@ LL +     debug_assert!(!"requires negation".is_empty());
    |
 
 error: used `debug_assert_eq!` with a literal bool
-  --> tests/ui/bool_assert_comparison.rs:200:5
+  --> tests/ui/bool_assert_comparison.rs:208:5
    |
 LL |     debug_assert_eq!("requires negation".is_empty(), false);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -396,5 +400,53 @@ LL -     debug_assert_eq!("requires negation".is_empty(), false);
 LL +     debug_assert!(!"requires negation".is_empty());
    |
 
-error: aborting due to 33 previous errors
+error: used `assert_eq!` with a literal bool
+  --> tests/ui/bool_assert_comparison.rs:210:5
+   |
+LL |     assert_eq!(!b, true);
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `assert!(..)`
+   |
+LL -     assert_eq!(!b, true);
+LL +     assert!(!b);
+   |
+
+error: used `assert_eq!` with a literal bool
+  --> tests/ui/bool_assert_comparison.rs:212:5
+   |
+LL |     assert_eq!(!b, false);
+   |     ^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `assert!(..)`
+   |
+LL -     assert_eq!(!b, false);
+LL +     assert!(!(!b));
+   |
+
+error: used `assert_eq!` with a literal bool
+  --> tests/ui/bool_assert_comparison.rs:214:5
+   |
+LL |     assert_eq!(b + b, true);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `assert!(..)`
+   |
+LL -     assert_eq!(b + b, true);
+LL +     assert!(!!(b + b));
+   |
+
+error: used `assert_eq!` with a literal bool
+  --> tests/ui/bool_assert_comparison.rs:216:5
+   |
+LL |     assert_eq!(b + b, false);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: replace it with `assert!(..)`
+   |
+LL -     assert_eq!(b + b, false);
+LL +     assert!(!(b + b));
+   |
+
+error: aborting due to 37 previous errors
 
diff --git a/src/tools/clippy/tests/ui/crashes/ice-96721.stderr b/src/tools/clippy/tests/ui/crashes/ice-96721.stderr
index f0778a4b32b..23f7300178e 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-96721.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-96721.stderr
@@ -3,6 +3,8 @@ error: malformed `path` attribute input
    |
 LL | #[path = foo!()]
    | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[path = "file"]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute>
 
 error: aborting due to 1 previous error
 
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index debf67e2741..be4663fffbe 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1695,6 +1695,10 @@ impl<'test> TestCx<'test> {
             }
             TestMode::Assembly | TestMode::Codegen => {
                 rustc.arg("-Cdebug-assertions=no");
+                // For assembly and codegen tests, we want to use the same order
+                // of the items of a codegen unit as the source order, so that
+                // we can compare the output with the source code through filecheck.
+                rustc.arg("-Zcodegen-source-order");
             }
             TestMode::Crashes => {
                 set_mir_dump_dir(&mut rustc);
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index ae1b25f8857..d9e374c414c 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -279,7 +279,7 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls {
                                 return None;
                             }
                             let codegen_fn_attrs = tcx.codegen_fn_attrs(local_def_id);
-                            if codegen_fn_attrs.contains_extern_indicator()
+                            if codegen_fn_attrs.contains_extern_indicator(tcx, local_def_id.into())
                                 || codegen_fn_attrs
                                     .flags
                                     .contains(CodegenFnAttrFlags::USED_COMPILER)
diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs
index ec6c2c60ca9..89bd93edae1 100644
--- a/src/tools/miri/src/borrow_tracker/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/mod.rs
@@ -260,7 +260,7 @@ impl GlobalStateInner {
         kind: MemoryKind,
         machine: &MiriMachine<'_>,
     ) -> AllocState {
-        let _span = enter_trace_span!(borrow_tracker::new_allocation, ?id, ?alloc_size, ?kind);
+        let _trace = enter_trace_span!(borrow_tracker::new_allocation, ?id, ?alloc_size, ?kind);
         match self.borrow_tracker_method {
             BorrowTrackerMethod::StackedBorrows =>
                 AllocState::StackedBorrows(Box::new(RefCell::new(Stacks::new_allocation(
@@ -281,7 +281,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         kind: RetagKind,
         val: &ImmTy<'tcx>,
     ) -> InterpResult<'tcx, ImmTy<'tcx>> {
-        let _span = enter_trace_span!(borrow_tracker::retag_ptr_value, ?kind, ?val.layout);
+        let _trace = enter_trace_span!(borrow_tracker::retag_ptr_value, ?kind, ?val.layout);
         let this = self.eval_context_mut();
         let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method;
         match method {
@@ -295,7 +295,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         kind: RetagKind,
         place: &PlaceTy<'tcx>,
     ) -> InterpResult<'tcx> {
-        let _span = enter_trace_span!(borrow_tracker::retag_place_contents, ?kind, ?place);
+        let _trace = enter_trace_span!(borrow_tracker::retag_place_contents, ?kind, ?place);
         let this = self.eval_context_mut();
         let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method;
         match method {
@@ -305,7 +305,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     }
 
     fn protect_place(&mut self, place: &MPlaceTy<'tcx>) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
-        let _span = enter_trace_span!(borrow_tracker::protect_place, ?place);
+        let _trace = enter_trace_span!(borrow_tracker::protect_place, ?place);
         let this = self.eval_context_mut();
         let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method;
         match method {
@@ -315,7 +315,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
     }
 
     fn expose_tag(&self, alloc_id: AllocId, tag: BorTag) -> InterpResult<'tcx> {
-        let _span =
+        let _trace =
             enter_trace_span!(borrow_tracker::expose_tag, alloc_id = alloc_id.0, tag = tag.0);
         let this = self.eval_context_ref();
         let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method;
@@ -360,7 +360,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         &self,
         frame: &Frame<'tcx, Provenance, FrameExtra<'tcx>>,
     ) -> InterpResult<'tcx> {
-        let _span = enter_trace_span!(borrow_tracker::on_stack_pop);
+        let _trace = enter_trace_span!(borrow_tracker::on_stack_pop);
         let this = self.eval_context_ref();
         let borrow_tracker = this.machine.borrow_tracker.as_ref().unwrap();
         // The body of this loop needs `borrow_tracker` immutably
@@ -438,7 +438,7 @@ impl AllocState {
         range: AllocRange,
         machine: &MiriMachine<'tcx>,
     ) -> InterpResult<'tcx> {
-        let _span = enter_trace_span!(borrow_tracker::before_memory_read, alloc_id = alloc_id.0);
+        let _trace = enter_trace_span!(borrow_tracker::before_memory_read, alloc_id = alloc_id.0);
         match self {
             AllocState::StackedBorrows(sb) =>
                 sb.borrow_mut().before_memory_read(alloc_id, prov_extra, range, machine),
@@ -460,7 +460,7 @@ impl AllocState {
         range: AllocRange,
         machine: &MiriMachine<'tcx>,
     ) -> InterpResult<'tcx> {
-        let _span = enter_trace_span!(borrow_tracker::before_memory_write, alloc_id = alloc_id.0);
+        let _trace = enter_trace_span!(borrow_tracker::before_memory_write, alloc_id = alloc_id.0);
         match self {
             AllocState::StackedBorrows(sb) =>
                 sb.get_mut().before_memory_write(alloc_id, prov_extra, range, machine),
@@ -482,7 +482,7 @@ impl AllocState {
         size: Size,
         machine: &MiriMachine<'tcx>,
     ) -> InterpResult<'tcx> {
-        let _span =
+        let _trace =
             enter_trace_span!(borrow_tracker::before_memory_deallocation, alloc_id = alloc_id.0);
         match self {
             AllocState::StackedBorrows(sb) =>
@@ -493,7 +493,7 @@ impl AllocState {
     }
 
     pub fn remove_unreachable_tags(&self, tags: &FxHashSet<BorTag>) {
-        let _span = enter_trace_span!(borrow_tracker::remove_unreachable_tags);
+        let _trace = enter_trace_span!(borrow_tracker::remove_unreachable_tags);
         match self {
             AllocState::StackedBorrows(sb) => sb.borrow_mut().remove_unreachable_tags(tags),
             AllocState::TreeBorrows(tb) => tb.borrow_mut().remove_unreachable_tags(tags),
@@ -508,7 +508,7 @@ impl AllocState {
         tag: BorTag,
         alloc_id: AllocId, // diagnostics
     ) -> InterpResult<'tcx> {
-        let _span = enter_trace_span!(
+        let _trace = enter_trace_span!(
             borrow_tracker::release_protector,
             alloc_id = alloc_id.0,
             tag = tag.0
@@ -523,7 +523,7 @@ impl AllocState {
 
 impl VisitProvenance for AllocState {
     fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
-        let _span = enter_trace_span!(borrow_tracker::visit_provenance);
+        let _trace = enter_trace_span!(borrow_tracker::visit_provenance);
         match self {
             AllocState::StackedBorrows(sb) => sb.visit_provenance(visit),
             AllocState::TreeBorrows(tb) => tb.visit_provenance(visit),
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 43cb1c9ae05..a8e2151afe6 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -132,7 +132,7 @@ pub fn iter_exported_symbols<'tcx>(
     for def_id in crate_items.definitions() {
         let exported = tcx.def_kind(def_id).has_codegen_attrs() && {
             let codegen_attrs = tcx.codegen_fn_attrs(def_id);
-            codegen_attrs.contains_extern_indicator()
+            codegen_attrs.contains_extern_indicator(tcx, def_id.into())
                 || codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL)
                 || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_COMPILER)
                 || codegen_attrs.flags.contains(CodegenFnAttrFlags::USED_LINKER)
diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml
index 2ed3fbac709..f4051ae67d7 100644
--- a/src/tools/opt-dist/Cargo.toml
+++ b/src/tools/opt-dist/Cargo.toml
@@ -10,7 +10,7 @@ log = "0.4"
 anyhow = "1"
 humantime = "2"
 humansize = "2"
-sysinfo = { version = "0.36.0", default-features = false, features = ["disk"] }
+sysinfo = { version = "0.37.0", default-features = false, features = ["disk"] }
 fs_extra = "1"
 camino = "1"
 tar = "0.4"
diff --git a/src/tools/opt-dist/src/tests.rs b/src/tools/opt-dist/src/tests.rs
index d5121b8c786..fa55805bbf2 100644
--- a/src/tools/opt-dist/src/tests.rs
+++ b/src/tools/opt-dist/src/tests.rs
@@ -36,6 +36,16 @@ pub fn run_tests(env: &Environment) -> anyhow::Result<()> {
     let cargo_dir = extract_dist_dir(&format!("cargo-{version}-{host_triple}"))?.join("cargo");
     let extracted_src_dir = extract_dist_dir(&format!("rust-src-{version}"))?.join("rust-src");
 
+    // If we have a Cranelift archive, copy it to the rustc sysroot
+    if let Ok(_) = find_file_in_dir(&dist_dir, "rustc-codegen-cranelift-", ".tar.xz") {
+        let extracted_codegen_dir =
+            extract_dist_dir(&format!("rustc-codegen-cranelift-{version}-{host_triple}"))?
+                .join("rustc-codegen-cranelift-preview");
+        let rel_path =
+            Utf8Path::new("lib").join("rustlib").join(host_triple).join("codegen-backends");
+        copy_directory(&extracted_codegen_dir.join(&rel_path), &rustc_dir.join(&rel_path))?;
+    }
+
     // We need to manually copy libstd to the extracted rustc sysroot
     copy_directory(
         &libstd_dir.join("lib").join("rustlib").join(host_triple).join("lib"),
diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs
index 60d3366ee98..b74b1d5e166 100644
--- a/src/tools/run-make-support/src/external_deps/rustc.rs
+++ b/src/tools/run-make-support/src/external_deps/rustc.rs
@@ -405,6 +405,12 @@ impl Rustc {
         };
         self
     }
+
+    /// Make that the generated LLVM IR is in source order.
+    pub fn codegen_source_order(&mut self) -> &mut Self {
+        self.cmd.arg("-Zcodegen-source-order");
+        self
+    }
 }
 
 /// Query the sysroot path corresponding `rustc --print=sysroot`.
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index 57d4142ebe4..10df6f96702 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -958,20 +958,19 @@ fn format_impl_ref_and_type(
     offset: Indent,
 ) -> Option<String> {
     let ast::Impl {
-        safety,
-        polarity,
-        defaultness,
-        constness,
-        ref generics,
-        of_trait: ref trait_ref,
-        ref self_ty,
-        ..
-    } = *iimpl;
+        generics,
+        of_trait,
+        self_ty,
+        items: _,
+    } = iimpl;
     let mut result = String::with_capacity(128);
 
     result.push_str(&format_visibility(context, &item.vis));
-    result.push_str(format_defaultness(defaultness));
-    result.push_str(format_safety(safety));
+
+    if let Some(of_trait) = of_trait.as_deref() {
+        result.push_str(format_defaultness(of_trait.defaultness));
+        result.push_str(format_safety(of_trait.safety));
+    }
 
     let shape = if context.config.style_edition() >= StyleEdition::Edition2024 {
         Shape::indented(offset + last_line_width(&result), context.config)
@@ -984,28 +983,24 @@ fn format_impl_ref_and_type(
     };
     let generics_str = rewrite_generics(context, "impl", generics, shape).ok()?;
     result.push_str(&generics_str);
-    result.push_str(format_constness_right(constness));
 
-    let polarity_str = match polarity {
-        ast::ImplPolarity::Negative(_) => "!",
-        ast::ImplPolarity::Positive => "",
-    };
-
-    let polarity_overhead;
     let trait_ref_overhead;
-    if let Some(ref trait_ref) = *trait_ref {
+    if let Some(of_trait) = of_trait.as_deref() {
+        result.push_str(format_constness_right(of_trait.constness));
+        let polarity_str = match of_trait.polarity {
+            ast::ImplPolarity::Negative(_) => "!",
+            ast::ImplPolarity::Positive => "",
+        };
         let result_len = last_line_width(&result);
         result.push_str(&rewrite_trait_ref(
             context,
-            trait_ref,
+            &of_trait.trait_ref,
             offset,
             polarity_str,
             result_len,
         )?);
-        polarity_overhead = 0; // already written
         trait_ref_overhead = " for".len();
     } else {
-        polarity_overhead = polarity_str.len();
         trait_ref_overhead = 0;
     }
 
@@ -1020,17 +1015,15 @@ fn format_impl_ref_and_type(
     } else {
         0
     };
-    let used_space =
-        last_line_width(&result) + polarity_overhead + trait_ref_overhead + curly_brace_overhead;
+    let used_space = last_line_width(&result) + trait_ref_overhead + curly_brace_overhead;
     // 1 = space before the type.
     let budget = context.budget(used_space + 1);
     if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) {
         if !self_ty_str.contains('\n') {
-            if trait_ref.is_some() {
+            if of_trait.is_some() {
                 result.push_str(" for ");
             } else {
                 result.push(' ');
-                result.push_str(polarity_str);
             }
             result.push_str(&self_ty_str);
             return Some(result);
@@ -1042,12 +1035,10 @@ fn format_impl_ref_and_type(
     // Add indentation of one additional tab.
     let new_line_offset = offset.block_indent(context.config);
     result.push_str(&new_line_offset.to_string(context.config));
-    if trait_ref.is_some() {
+    if of_trait.is_some() {
         result.push_str("for ");
-    } else {
-        result.push_str(polarity_str);
     }
-    let budget = context.budget(last_line_width(&result) + polarity_overhead);
+    let budget = context.budget(last_line_width(&result));
     let type_offset = match context.config.indent_style() {
         IndentStyle::Visual => new_line_offset + trait_ref_overhead,
         IndentStyle::Block => new_line_offset,
diff --git a/src/tools/rustfmt/tests/source/negative-impl.rs b/src/tools/rustfmt/tests/source/negative-impl.rs
index da242d4f3dc..e8f9508e656 100644
--- a/src/tools/rustfmt/tests/source/negative-impl.rs
+++ b/src/tools/rustfmt/tests/source/negative-impl.rs
@@ -1,7 +1,3 @@
 impl ! Display for JoinHandle { }
 
-impl ! Box < JoinHandle > { }
-
 impl ! std :: fmt :: Display for JoinHandle < T : std :: future :: Future + std :: marker :: Send + std :: marker :: Sync > { }
-
-impl ! JoinHandle < T : std :: future :: Future < Output > + std :: marker :: Send + std :: marker :: Sync + 'static > + 'static { }
diff --git a/src/tools/rustfmt/tests/target/negative-impl.rs b/src/tools/rustfmt/tests/target/negative-impl.rs
index 16ce7e26a99..bb53048dbc6 100644
--- a/src/tools/rustfmt/tests/target/negative-impl.rs
+++ b/src/tools/rustfmt/tests/target/negative-impl.rs
@@ -1,14 +1,6 @@
 impl !Display for JoinHandle {}
 
-impl !Box<JoinHandle> {}
-
 impl !std::fmt::Display
     for JoinHandle<T: std::future::Future + std::marker::Send + std::marker::Sync>
 {
 }
-
-impl
-    !JoinHandle<T: std::future::Future<Output> + std::marker::Send + std::marker::Sync + 'static>
-        + 'static
-{
-}
diff --git a/tests/assembly-llvm/asm/aarch64-outline-atomics.rs b/tests/assembly-llvm/asm/aarch64-outline-atomics.rs
index 22599c18dcf..1177c1e68ed 100644
--- a/tests/assembly-llvm/asm/aarch64-outline-atomics.rs
+++ b/tests/assembly-llvm/asm/aarch64-outline-atomics.rs
@@ -8,6 +8,10 @@
 use std::sync::atomic::AtomicI32;
 use std::sync::atomic::Ordering::*;
 
+// Verify config on outline-atomics works (it is always enabled on aarch64-linux).
+#[cfg(not(target_feature = "outline-atomics"))]
+compile_error!("outline-atomics is not enabled");
+
 pub fn compare_exchange(a: &AtomicI32) {
     // On AArch64 LLVM should outline atomic operations.
     // CHECK: __aarch64_cas4_relax
diff --git a/tests/assembly-llvm/targets/targets-elf.rs b/tests/assembly-llvm/targets/targets-elf.rs
index ee63dffe9ea..a1d759ede2b 100644
--- a/tests/assembly-llvm/targets/targets-elf.rs
+++ b/tests/assembly-llvm/targets/targets-elf.rs
@@ -10,6 +10,9 @@
 //@ revisions: aarch64_be_unknown_netbsd
 //@ [aarch64_be_unknown_netbsd] compile-flags: --target aarch64_be-unknown-netbsd
 //@ [aarch64_be_unknown_netbsd] needs-llvm-components: aarch64
+//@ revisions: aarch64_be_unknown_none_softfloat
+//@ [aarch64_be_unknown_none_softfloat] compile-flags: --target aarch64_be-unknown-none-softfloat
+//@ [aarch64_be_unknown_none_softfloat] needs-llvm-components: aarch64
 //@ revisions: aarch64_kmc_solid_asp3
 //@ [aarch64_kmc_solid_asp3] compile-flags: --target aarch64-kmc-solid_asp3
 //@ [aarch64_kmc_solid_asp3] needs-llvm-components: aarch64
diff --git a/tests/codegen-llvm/addr-of-mutate.rs b/tests/codegen-llvm/addr-of-mutate.rs
index 14bc4b8ab28..71669065289 100644
--- a/tests/codegen-llvm/addr-of-mutate.rs
+++ b/tests/codegen-llvm/addr-of-mutate.rs
@@ -5,7 +5,7 @@
 // Test for the absence of `readonly` on the argument when it is mutated via `&raw const`.
 // See <https://github.com/rust-lang/rust/issues/111502>.
 
-// CHECK: i8 @foo(ptr noalias{{( nocapture)?}} noundef align 1{{( captures\(none\))?}} dereferenceable(128) %x)
+// CHECK: i8 @foo(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef align 1{{( captures\(none\))?}} dereferenceable(128) %x)
 #[no_mangle]
 pub fn foo(x: [u8; 128]) -> u8 {
     let ptr = core::ptr::addr_of!(x).cast_mut();
@@ -15,7 +15,7 @@ pub fn foo(x: [u8; 128]) -> u8 {
     x[0]
 }
 
-// CHECK: i1 @second(ptr noalias{{( nocapture)?}} noundef align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b)
+// CHECK: i1 @second(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b)
 #[no_mangle]
 pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool {
     let b_bool_ptr = core::ptr::addr_of!(a_ptr_and_b.1.1).cast_mut();
@@ -24,7 +24,7 @@ pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool {
 }
 
 // If going through a deref (and there are no other mutating accesses), then `readonly` is fine.
-// CHECK: i1 @third(ptr noalias{{( nocapture)?}} noundef readonly align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b)
+// CHECK: i1 @third(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef readonly align {{[0-9]+}}{{( captures\(none\))?}} dereferenceable({{[0-9]+}}) %a_ptr_and_b)
 #[no_mangle]
 pub unsafe fn third(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool {
     let b_bool_ptr = core::ptr::addr_of!((*a_ptr_and_b.0).1).cast_mut();
diff --git a/tests/codegen-llvm/dead_on_return.rs b/tests/codegen-llvm/dead_on_return.rs
new file mode 100644
index 00000000000..3c1940d6ba7
--- /dev/null
+++ b/tests/codegen-llvm/dead_on_return.rs
@@ -0,0 +1,31 @@
+//@ compile-flags: -C opt-level=3
+//@ min-llvm-version: 21
+
+#![crate_type = "lib"]
+#![allow(unused_assignments, unused_variables)]
+
+// Check that the old string is deallocated, but a new one is not initialized.
+#[unsafe(no_mangle)]
+pub fn test_str_new(mut s: String) {
+    // CHECK-LABEL: @test_str_new
+    // CHECK: __rust_dealloc
+    // CHECK-NOT: store
+    s = String::new();
+}
+
+#[unsafe(no_mangle)]
+pub fn test_str_take(mut x: String) -> String {
+    // CHECK-LABEL: @test_str_take
+    // CHECK-NEXT: {{.*}}:
+    // CHECK-NEXT: call void @llvm.memcpy
+    // CHECK-NEXT: ret
+    core::mem::take(&mut x)
+}
+
+#[unsafe(no_mangle)]
+pub fn test_array_store(mut x: [u32; 100]) {
+    // CHECK-LABEL: @test_array_store
+    // CHECK-NEXT: {{.*}}:
+    // CHECK-NEXT: ret
+    x[0] = 1;
+}
diff --git a/tests/codegen-llvm/function-arguments.rs b/tests/codegen-llvm/function-arguments.rs
index c8cd8526ae5..a3fafbe6f82 100644
--- a/tests/codegen-llvm/function-arguments.rs
+++ b/tests/codegen-llvm/function-arguments.rs
@@ -134,7 +134,7 @@ pub fn mutable_notunpin_borrow(_: &mut NotUnpin) {}
 #[no_mangle]
 pub fn notunpin_borrow(_: &NotUnpin) {}
 
-// CHECK: @indirect_struct(ptr noalias{{( nocapture)?}} noundef readonly align 4{{( captures\(none\))?}} dereferenceable(32) %_1)
+// CHECK: @indirect_struct(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef readonly align 4{{( captures\(none\))?}} dereferenceable(32) %_1)
 #[no_mangle]
 pub fn indirect_struct(_: S) {}
 
diff --git a/tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs b/tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs
index 93c8d60930b..4666342a16a 100644
--- a/tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs
+++ b/tests/codegen-llvm/loongarch-abi/loongarch64-lp64d-abi.rs
@@ -256,7 +256,7 @@ pub struct IntDoubleInt {
     c: i32,
 }
 
-// CHECK: define void @f_int_double_int_s_arg(ptr noalias{{( nocapture)?}} noundef align 8{{( captures\(none\))?}} dereferenceable(24) %a)
+// CHECK: define void @f_int_double_int_s_arg(ptr{{( dead_on_return)?}} noalias{{( nocapture)?}} noundef align 8{{( captures\(none\))?}} dereferenceable(24) %a)
 #[no_mangle]
 pub extern "C" fn f_int_double_int_s_arg(a: IntDoubleInt) {}
 
diff --git a/tests/run-make/link-under-xcode/foo.rs b/tests/run-make/link-under-xcode/foo.rs
new file mode 100644
index 00000000000..f328e4d9d04
--- /dev/null
+++ b/tests/run-make/link-under-xcode/foo.rs
@@ -0,0 +1 @@
+fn main() {}
diff --git a/tests/run-make/link-under-xcode/rmake.rs b/tests/run-make/link-under-xcode/rmake.rs
new file mode 100644
index 00000000000..c9394feb000
--- /dev/null
+++ b/tests/run-make/link-under-xcode/rmake.rs
@@ -0,0 +1,32 @@
+//! Test that linking works under an environment similar to what Xcode sets up.
+//!
+//! Regression test for https://github.com/rust-lang/rust/issues/80817.
+
+//@ only-apple
+
+use run_make_support::{cmd, rustc, target};
+
+fn main() {
+    // Fetch toolchain `/usr/bin` directory. Usually:
+    // /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
+    let clang_bin = cmd("xcrun").arg("--find").arg("clang").run().stdout_utf8();
+    let toolchain_bin = clang_bin.trim().strip_suffix("/clang").unwrap();
+
+    // Put toolchain directory at the front of PATH.
+    let path = format!("{}:{}", toolchain_bin, std::env::var("PATH").unwrap());
+
+    // Check that compiling and linking still works.
+    //
+    // Removing `SDKROOT` is necessary for the test to excercise what we want, since bootstrap runs
+    // under `/usr/bin/python3`, which will set SDKROOT for us.
+    rustc().target(target()).env_remove("SDKROOT").env("PATH", &path).input("foo.rs").run();
+
+    // Also check linking directly with the system linker.
+    rustc()
+        .target(target())
+        .env_remove("SDKROOT")
+        .env("PATH", &path)
+        .input("foo.rs")
+        .arg("-Clinker-flavor=ld")
+        .run();
+}
diff --git a/tests/run-make/pgo-branch-weights/rmake.rs b/tests/run-make/pgo-branch-weights/rmake.rs
index 1893248e307..e74eabc1875 100644
--- a/tests/run-make/pgo-branch-weights/rmake.rs
+++ b/tests/run-make/pgo-branch-weights/rmake.rs
@@ -17,15 +17,21 @@ use run_make_support::{llvm_filecheck, llvm_profdata, rfs, run_with_args, rustc}
 fn main() {
     let path_prof_data_dir = Path::new("prof_data_dir");
     let path_merged_profdata = path_prof_data_dir.join("merged.profdata");
-    rustc().input("opaque.rs").run();
+    rustc().input("opaque.rs").codegen_source_order().run();
     rfs::create_dir_all(&path_prof_data_dir);
     rustc()
         .input("interesting.rs")
         .profile_generate(&path_prof_data_dir)
         .opt()
         .codegen_units(1)
+        .codegen_source_order()
+        .run();
+    rustc()
+        .input("main.rs")
+        .profile_generate(&path_prof_data_dir)
+        .opt()
+        .codegen_source_order()
         .run();
-    rustc().input("main.rs").profile_generate(&path_prof_data_dir).opt().run();
     run_with_args("main", &["aaaaaaaaaaaa2bbbbbbbbbbbb2bbbbbbbbbbbbbbbbcc"]);
     llvm_profdata().merge().output(&path_merged_profdata).input(path_prof_data_dir).run();
     rustc()
@@ -34,6 +40,7 @@ fn main() {
         .opt()
         .codegen_units(1)
         .emit("llvm-ir")
+        .codegen_source_order()
         .run();
     llvm_filecheck()
         .patterns("filecheck-patterns.txt")
diff --git a/tests/run-make/pgo-indirect-call-promotion/rmake.rs b/tests/run-make/pgo-indirect-call-promotion/rmake.rs
index ce9754f13b9..ee09141912b 100644
--- a/tests/run-make/pgo-indirect-call-promotion/rmake.rs
+++ b/tests/run-make/pgo-indirect-call-promotion/rmake.rs
@@ -14,11 +14,17 @@ use run_make_support::{llvm_filecheck, llvm_profdata, rfs, run, rustc};
 
 fn main() {
     // We don't compile `opaque` with either optimizations or instrumentation.
-    rustc().input("opaque.rs").run();
+    rustc().input("opaque.rs").codegen_source_order().run();
     // Compile the test program with instrumentation
     rfs::create_dir("prof_data_dir");
-    rustc().input("interesting.rs").profile_generate("prof_data_dir").opt().codegen_units(1).run();
-    rustc().input("main.rs").profile_generate("prof_data_dir").opt().run();
+    rustc()
+        .input("interesting.rs")
+        .profile_generate("prof_data_dir")
+        .opt()
+        .codegen_units(1)
+        .codegen_source_order()
+        .run();
+    rustc().input("main.rs").profile_generate("prof_data_dir").opt().codegen_source_order().run();
     // The argument below generates to the expected branch weights
     run("main");
     llvm_profdata().merge().output("prof_data_dir/merged.profdata").input("prof_data_dir").run();
@@ -28,6 +34,7 @@ fn main() {
         .opt()
         .codegen_units(1)
         .emit("llvm-ir")
+        .codegen_source_order()
         .run();
     llvm_filecheck()
         .patterns("filecheck-patterns.txt")
diff --git a/tests/run-make/pgo-use/rmake.rs b/tests/run-make/pgo-use/rmake.rs
index c09a82353b9..137b0b859a0 100644
--- a/tests/run-make/pgo-use/rmake.rs
+++ b/tests/run-make/pgo-use/rmake.rs
@@ -22,6 +22,7 @@ fn main() {
         .opt_level("2")
         .codegen_units(1)
         .arg("-Cllvm-args=-disable-preinline")
+        .codegen_source_order()
         .profile_generate(cwd())
         .input("main.rs")
         .run();
@@ -40,6 +41,7 @@ fn main() {
         .arg("-Cllvm-args=-disable-preinline")
         .profile_use("merged.profdata")
         .emit("llvm-ir")
+        .codegen_source_order()
         .input("main.rs")
         .run();
     // Check that the generate IR contains some things that we expect.
diff --git a/tests/run-make/wasm-panic-small/rmake.rs b/tests/run-make/wasm-panic-small/rmake.rs
index e69fbac9635..ea0b6faf037 100644
--- a/tests/run-make/wasm-panic-small/rmake.rs
+++ b/tests/run-make/wasm-panic-small/rmake.rs
@@ -24,5 +24,5 @@ fn test(cfg: &str) {
 
     let bytes = rfs::read("foo.wasm");
     println!("{}", bytes.len());
-    assert!(bytes.len() < 40_000);
+    assert!(bytes.len() < 40_000, "bytes len was: {}", bytes.len());
 }
diff --git a/tests/rustdoc-ui/intra-doc/github-flavored-admonitions.rs b/tests/rustdoc-ui/intra-doc/github-flavored-admonitions.rs
new file mode 100644
index 00000000000..d5fa72eb993
--- /dev/null
+++ b/tests/rustdoc-ui/intra-doc/github-flavored-admonitions.rs
@@ -0,0 +1,6 @@
+// regression test for https://github.com/rust-lang/rust/issues/141866
+//@ check-pass
+#![deny(rustdoc::broken_intra_doc_links)]
+
+//! > [!NOTE]
+//! > This should not cause any warnings
diff --git a/tests/rustdoc/enum/enum-variant-value.rs b/tests/rustdoc/enum/enum-variant-value.rs
index 1670de8a24f..9cc85dfe10d 100644
--- a/tests/rustdoc/enum/enum-variant-value.rs
+++ b/tests/rustdoc/enum/enum-variant-value.rs
@@ -189,3 +189,25 @@ pub use bar::P;
 //@ has - '//*[@id="variant.A"]/h3' 'A(u32)'
 //@ matches - '//*[@id="variant.B"]/h3' '^B$'
 pub use bar::Q;
+
+// Ensure signed implicit discriminants are rendered correctly after a negative explicit value.
+//@ has 'foo/enum.R.html'
+//@ has - '//*[@class="rust item-decl"]/code' 'A = -2,'
+//@ has - '//*[@class="rust item-decl"]/code' 'B = -1,'
+//@ matches - '//*[@id="variant.A"]/h3' '^A = -2$'
+//@ matches - '//*[@id="variant.B"]/h3' '^B = -1$'
+pub enum R {
+    A = -2,
+    B,
+}
+
+// Also check that incrementing -1 yields 0 for the next implicit variant.
+//@ has 'foo/enum.S.html'
+//@ has - '//*[@class="rust item-decl"]/code' 'A = -1,'
+//@ has - '//*[@class="rust item-decl"]/code' 'B = 0,'
+//@ matches - '//*[@id="variant.A"]/h3' '^A = -1$'
+//@ matches - '//*[@id="variant.B"]/h3' '^B = 0$'
+pub enum S {
+    A = -1,
+    B,
+}
diff --git a/tests/ui/argument-suggestions/issue-100478.stderr b/tests/ui/argument-suggestions/issue-100478.stderr
index 8889a0ab5df..81dbff2f000 100644
--- a/tests/ui/argument-suggestions/issue-100478.stderr
+++ b/tests/ui/argument-suggestions/issue-100478.stderr
@@ -75,12 +75,16 @@ LL | fn foo(p1: T1, p2: Arc<T2>, p3: T3, p4: Arc<T4>, p5: T5, p6: T6, p7: T7, p8
    |    ^^^         -----------
 help: provide the argument
    |
-LL -     foo(
-LL -
-LL -         p1, //p2,
-LL -         p3, p4, p5, p6, p7, p8,
-LL -     );
-LL +     foo(p1, /* Arc<T2> */, p3, p4, p5, p6, p7, p8);
+LL ~     foo(
+LL +         p1,
+LL +         /* Arc<T2> */,
+LL +         p3,
+LL +         p4,
+LL +         p5,
+LL +         p6,
+LL +         p7,
+LL +         p8,
+LL ~     );
    |
 
 error: aborting due to 4 previous errors
diff --git a/tests/ui/async-await/drop-live-upvar-2.may_not_dangle.stderr b/tests/ui/async-await/drop-live-upvar-2.may_not_dangle.stderr
new file mode 100644
index 00000000000..34f6ba79246
--- /dev/null
+++ b/tests/ui/async-await/drop-live-upvar-2.may_not_dangle.stderr
@@ -0,0 +1,18 @@
+error[E0597]: `y` does not live long enough
+  --> $DIR/drop-live-upvar-2.rs:31:26
+   |
+LL |         let y = ();
+   |             - binding `y` declared here
+LL |         drop_me = Droppy(&y);
+   |                          ^^ borrowed value does not live long enough
+...
+LL |     }
+   |     - `y` dropped here while still borrowed
+LL | }
+   | - borrow might be used here, when `fut` is dropped and runs the destructor for coroutine
+   |
+   = note: values in a scope are dropped in the opposite order they are defined
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/async-await/drop-live-upvar-2.rs b/tests/ui/async-await/drop-live-upvar-2.rs
new file mode 100644
index 00000000000..605db4c8f76
--- /dev/null
+++ b/tests/ui/async-await/drop-live-upvar-2.rs
@@ -0,0 +1,37 @@
+//@ revisions: may_dangle may_not_dangle
+//@[may_dangle] check-pass
+//@ edition: 2018
+
+// Ensure that if a coroutine's interior has no drop types then we don't require the upvars to
+// be *use-live*, but instead require them to be *drop-live*. In this case, `Droppy<&'?0 ()>`
+// does not require that `'?0` is live for drops since the parameter is `#[may_dangle]` in
+// the may_dangle revision, but not in the may_not_dangle revision.
+
+#![feature(dropck_eyepatch)]
+
+struct Droppy<T>(T);
+
+#[cfg(may_dangle)]
+unsafe impl<#[may_dangle] T> Drop for Droppy<T> {
+    fn drop(&mut self) {
+        // This does not use `T` of course.
+    }
+}
+
+#[cfg(may_not_dangle)]
+impl<T> Drop for Droppy<T> {
+    fn drop(&mut self) {}
+}
+
+fn main() {
+    let drop_me;
+    let fut;
+    {
+        let y = ();
+        drop_me = Droppy(&y);
+        //[may_not_dangle]~^ ERROR `y` does not live long enough
+        fut = async {
+            std::mem::drop(drop_me);
+        };
+    }
+}
diff --git a/tests/ui/async-await/drop-live-upvar.rs b/tests/ui/async-await/drop-live-upvar.rs
new file mode 100644
index 00000000000..8e881f729b9
--- /dev/null
+++ b/tests/ui/async-await/drop-live-upvar.rs
@@ -0,0 +1,23 @@
+//@ edition: 2018
+// Regression test for <https://github.com/rust-lang/rust/issues/144155>.
+
+struct NeedsDrop<'a>(&'a Vec<i32>);
+
+async fn await_point() {}
+
+impl Drop for NeedsDrop<'_> {
+    fn drop(&mut self) {}
+}
+
+fn foo() {
+    let v = vec![1, 2, 3];
+    let x = NeedsDrop(&v);
+    let c = async {
+        std::future::ready(()).await;
+        drop(x);
+    };
+    drop(v);
+    //~^ ERROR cannot move out of `v` because it is borrowed
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/drop-live-upvar.stderr b/tests/ui/async-await/drop-live-upvar.stderr
new file mode 100644
index 00000000000..f804484536b
--- /dev/null
+++ b/tests/ui/async-await/drop-live-upvar.stderr
@@ -0,0 +1,22 @@
+error[E0505]: cannot move out of `v` because it is borrowed
+  --> $DIR/drop-live-upvar.rs:19:10
+   |
+LL |     let v = vec![1, 2, 3];
+   |         - binding `v` declared here
+LL |     let x = NeedsDrop(&v);
+   |                       -- borrow of `v` occurs here
+...
+LL |     drop(v);
+   |          ^ move out of `v` occurs here
+LL |
+LL | }
+   | - borrow might be used here, when `c` is dropped and runs the destructor for coroutine
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let x = NeedsDrop(&v.clone());
+   |                         ++++++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0505`.
diff --git a/tests/ui/async-await/recursive-async-auto-trait-overflow.rs b/tests/ui/async-await/recursive-async-auto-trait-overflow.rs
new file mode 100644
index 00000000000..716600ce472
--- /dev/null
+++ b/tests/ui/async-await/recursive-async-auto-trait-overflow.rs
@@ -0,0 +1,14 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/145151>.
+
+//@ edition: 2024
+//@ check-pass
+
+async fn process<'a>() {
+    Box::pin(process()).await;
+}
+
+fn require_send(_: impl Send) {}
+
+fn main() {
+    require_send(process());
+}
diff --git a/tests/ui/attributes/crate-name-macro-call.stderr b/tests/ui/attributes/crate-name-macro-call.stderr
index ab562b41a31..56827aa11a4 100644
--- a/tests/ui/attributes/crate-name-macro-call.stderr
+++ b/tests/ui/attributes/crate-name-macro-call.stderr
@@ -3,6 +3,8 @@ error: malformed `crate_name` attribute input
    |
 LL | #![crate_name = concat!("my", "crate")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_name = "name"]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/crates-and-source-files.html#the-crate_name-attribute>
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/attributes/crate-type-delimited.stderr b/tests/ui/attributes/crate-type-delimited.stderr
index 0bbbe07b198..7f080f74838 100644
--- a/tests/ui/attributes/crate-type-delimited.stderr
+++ b/tests/ui/attributes/crate-type-delimited.stderr
@@ -2,7 +2,24 @@ error: malformed `crate_type` attribute input
   --> $DIR/crate-type-delimited.rs:2:1
    |
 LL | #![crate_type(lib)]
-   | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_type = "bin|lib|..."]`
+   | ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/linkage.html>
+help: the following are the possible correct uses
+   |
+LL - #![crate_type(lib)]
+LL + #![crate_type = "bin"]
+   |
+LL - #![crate_type(lib)]
+LL + #![crate_type = "cdylib"]
+   |
+LL - #![crate_type(lib)]
+LL + #![crate_type = "dylib"]
+   |
+LL - #![crate_type(lib)]
+LL + #![crate_type = "lib"]
+   |
+   = and 4 other candidates
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/attributes/crate-type-empty.stderr b/tests/ui/attributes/crate-type-empty.stderr
index b9279d961ee..f50bb33d6bb 100644
--- a/tests/ui/attributes/crate-type-empty.stderr
+++ b/tests/ui/attributes/crate-type-empty.stderr
@@ -2,7 +2,20 @@ error: malformed `crate_type` attribute input
   --> $DIR/crate-type-empty.rs:2:1
    |
 LL | #![crate_type]
-   | ^^^^^^^^^^^^^^ help: must be of the form: `#![crate_type = "bin|lib|..."]`
+   | ^^^^^^^^^^^^^^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/linkage.html>
+help: the following are the possible correct uses
+   |
+LL | #![crate_type = "bin"]
+   |               +++++++
+LL | #![crate_type = "cdylib"]
+   |               ++++++++++
+LL | #![crate_type = "dylib"]
+   |               +++++++++
+LL | #![crate_type = "lib"]
+   |               +++++++
+   = and 4 other candidates
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/attributes/crate-type-macro-call.stderr b/tests/ui/attributes/crate-type-macro-call.stderr
index 6ccc3edf885..97938f7af24 100644
--- a/tests/ui/attributes/crate-type-macro-call.stderr
+++ b/tests/ui/attributes/crate-type-macro-call.stderr
@@ -2,7 +2,24 @@ error: malformed `crate_type` attribute input
   --> $DIR/crate-type-macro-call.rs:1:1
    |
 LL | #![crate_type = foo!()]
-   | ^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_type = "bin|lib|..."]`
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/linkage.html>
+help: the following are the possible correct uses
+   |
+LL - #![crate_type = foo!()]
+LL + #![crate_type = "bin"]
+   |
+LL - #![crate_type = foo!()]
+LL + #![crate_type = "cdylib"]
+   |
+LL - #![crate_type = foo!()]
+LL + #![crate_type = "dylib"]
+   |
+LL - #![crate_type = foo!()]
+LL + #![crate_type = "lib"]
+   |
+   = and 4 other candidates
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/attributes/invalid-macro-use.rs b/tests/ui/attributes/invalid-macro-use.rs
index cfb13fd183c..52e4608303f 100644
--- a/tests/ui/attributes/invalid-macro-use.rs
+++ b/tests/ui/attributes/invalid-macro-use.rs
@@ -8,21 +8,25 @@ extern crate std as s1;
 #[macro_use(5)]
 //~^ ERROR malformed `macro_use` attribute input
 //~| NOTE expected a valid identifier here
+//~| NOTE for more information, visit
 extern crate std as s2;
 
 #[macro_use(a = "b")]
 //~^ ERROR malformed `macro_use` attribute input
 //~| NOTE didn't expect any arguments here
+//~| NOTE for more information, visit
 extern crate std as s3;
 
 #[macro_use(a(b))]
 //~^ ERROR malformed `macro_use` attribute input
 //~| NOTE didn't expect any arguments here
+//~| NOTE for more information, visit
 extern crate std as s4;
 
 #[macro_use(a::b)]
 //~^ ERROR malformed `macro_use` attribute input
 //~| NOTE expected a valid identifier here
+//~| NOTE for more information, visit
 extern crate std as s5;
 
 #[macro_use(a)]
diff --git a/tests/ui/attributes/invalid-macro-use.stderr b/tests/ui/attributes/invalid-macro-use.stderr
index 4f5db5c558a..ff3ed6196d3 100644
--- a/tests/ui/attributes/invalid-macro-use.stderr
+++ b/tests/ui/attributes/invalid-macro-use.stderr
@@ -1,11 +1,11 @@
 error[E0469]: imported macro not found
-  --> $DIR/invalid-macro-use.rs:47:13
+  --> $DIR/invalid-macro-use.rs:51:13
    |
 LL | #[macro_use(a)]
    |             ^
 
 error[E0469]: imported macro not found
-  --> $DIR/invalid-macro-use.rs:49:13
+  --> $DIR/invalid-macro-use.rs:53:13
    |
 LL | #[macro_use(b)]
    |             ^
@@ -24,6 +24,7 @@ LL | #[macro_use(5)]
    |             |
    |             expected a valid identifier here
    |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute>
 help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[macro_use(5)]
@@ -34,13 +35,14 @@ LL + #[macro_use]
    |
 
 error[E0565]: malformed `macro_use` attribute input
-  --> $DIR/invalid-macro-use.rs:13:1
+  --> $DIR/invalid-macro-use.rs:14:1
    |
 LL | #[macro_use(a = "b")]
    | ^^^^^^^^^^^^^^-----^^
    |               |
    |               didn't expect any arguments here
    |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute>
 help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[macro_use(a = "b")]
@@ -51,13 +53,14 @@ LL + #[macro_use]
    |
 
 error[E0565]: malformed `macro_use` attribute input
-  --> $DIR/invalid-macro-use.rs:18:1
+  --> $DIR/invalid-macro-use.rs:20:1
    |
 LL | #[macro_use(a(b))]
    | ^^^^^^^^^^^^^---^^
    |              |
    |              didn't expect any arguments here
    |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute>
 help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[macro_use(a(b))]
@@ -68,13 +71,14 @@ LL + #[macro_use]
    |
 
 error[E0539]: malformed `macro_use` attribute input
-  --> $DIR/invalid-macro-use.rs:23:1
+  --> $DIR/invalid-macro-use.rs:26:1
    |
 LL | #[macro_use(a::b)]
    | ^^^^^^^^^^^^----^^
    |             |
    |             expected a valid identifier here
    |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute>
 help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[macro_use(a::b)]
@@ -85,13 +89,13 @@ LL + #[macro_use]
    |
 
 error: unused attribute
-  --> $DIR/invalid-macro-use.rs:28:1
+  --> $DIR/invalid-macro-use.rs:32:1
    |
 LL | #[macro_use(a)]
    | ^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/invalid-macro-use.rs:30:1
+  --> $DIR/invalid-macro-use.rs:34:1
    |
 LL | #[macro_use]
    | ^^^^^^^^^^^^
@@ -102,25 +106,25 @@ LL | #![deny(unused_attributes)]
    |         ^^^^^^^^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/invalid-macro-use.rs:36:1
+  --> $DIR/invalid-macro-use.rs:40:1
    |
 LL | #[macro_use(a)]
    | ^^^^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/invalid-macro-use.rs:34:1
+  --> $DIR/invalid-macro-use.rs:38:1
    |
 LL | #[macro_use]
    | ^^^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/invalid-macro-use.rs:42:1
+  --> $DIR/invalid-macro-use.rs:46:1
    |
 LL | #[macro_use]
    | ^^^^^^^^^^^^ help: remove this attribute
    |
 note: attribute also specified here
-  --> $DIR/invalid-macro-use.rs:40:1
+  --> $DIR/invalid-macro-use.rs:44:1
    |
 LL | #[macro_use]
    | ^^^^^^^^^^^^
diff --git a/tests/ui/attributes/invalid-reprs.stderr b/tests/ui/attributes/invalid-reprs.stderr
index 415b969b244..72aaff92bd0 100644
--- a/tests/ui/attributes/invalid-reprs.stderr
+++ b/tests/ui/attributes/invalid-reprs.stderr
@@ -26,6 +26,7 @@ LL |     let y = #[repr(uwu(4))]
    |                    ^^^^^^
    |
    = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+   = note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html?highlight=repr#representations>
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/attributes/lint_on_root.rs b/tests/ui/attributes/lint_on_root.rs
index 93d47bf0d71..9029da7dc97 100644
--- a/tests/ui/attributes/lint_on_root.rs
+++ b/tests/ui/attributes/lint_on_root.rs
@@ -1,7 +1,7 @@
 // NOTE: this used to panic in debug builds (by a sanity assertion)
 // and not emit any lint on release builds. See https://github.com/rust-lang/rust/issues/142891.
 #![inline = ""]
-//~^ ERROR valid forms for the attribute are `#[inline(always|never)]` and `#[inline]`
+//~^ ERROR: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]` [ill_formed_attribute_input]
 //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 fn main() {}
diff --git a/tests/ui/attributes/lint_on_root.stderr b/tests/ui/attributes/lint_on_root.stderr
index aa0645b6194..91b72730530 100644
--- a/tests/ui/attributes/lint_on_root.stderr
+++ b/tests/ui/attributes/lint_on_root.stderr
@@ -1,4 +1,4 @@
-error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]`
+error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
   --> $DIR/lint_on_root.rs:3:1
    |
 LL | #![inline = ""]
@@ -11,7 +11,7 @@ LL | #![inline = ""]
 error: aborting due to 1 previous error
 
 Future incompatibility report: Future breakage diagnostic:
-error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]`
+error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
   --> $DIR/lint_on_root.rs:3:1
    |
 LL | #![inline = ""]
diff --git a/tests/ui/attributes/malformed-attrs.rs b/tests/ui/attributes/malformed-attrs.rs
index 0d5bf69d548..3261b29fe7e 100644
--- a/tests/ui/attributes/malformed-attrs.rs
+++ b/tests/ui/attributes/malformed-attrs.rs
@@ -78,7 +78,7 @@
 #[export_stable = 1]
 //~^ ERROR malformed
 #[link]
-//~^ ERROR attribute must be of the form
+//~^ ERROR valid forms for the attribute are
 //~| WARN this was previously accepted by the compiler
 #[link_name]
 //~^ ERROR malformed
diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr
index dd9dd3a6ce7..705050e9a7d 100644
--- a/tests/ui/attributes/malformed-attrs.stderr
+++ b/tests/ui/attributes/malformed-attrs.stderr
@@ -6,6 +6,8 @@ LL | #[cfg]
    | |
    | expected this to be a list
    | help: must be of the form: `#[cfg(predicate)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
 
 error: malformed `cfg_attr` attribute input
   --> $DIR/malformed-attrs.rs:101:1
@@ -29,13 +31,23 @@ error: malformed `windows_subsystem` attribute input
   --> $DIR/malformed-attrs.rs:26:1
    |
 LL | #![windows_subsystem]
-   | ^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![windows_subsystem = "windows|console"]`
+   | ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute>
+help: the following are the possible correct uses
+   |
+LL | #![windows_subsystem = "console"]
+   |                      +++++++++++
+LL | #![windows_subsystem = "windows"]
+   |                      +++++++++++
 
 error: malformed `crate_name` attribute input
   --> $DIR/malformed-attrs.rs:71:1
    |
 LL | #[crate_name]
    | ^^^^^^^^^^^^^ help: must be of the form: `#[crate_name = "name"]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/crates-and-source-files.html#the-crate_name-attribute>
 
 error: malformed `no_sanitize` attribute input
   --> $DIR/malformed-attrs.rs:89:1
@@ -48,6 +60,8 @@ error: malformed `instruction_set` attribute input
    |
 LL | #[instruction_set]
    | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[instruction_set(set)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/codegen.html#the-instruction_set-attribute>
 
 error: malformed `patchable_function_entry` attribute input
   --> $DIR/malformed-attrs.rs:105:1
@@ -80,43 +94,108 @@ error: malformed `linkage` attribute input
   --> $DIR/malformed-attrs.rs:170:5
    |
 LL |     #[linkage]
-   |     ^^^^^^^^^^ help: must be of the form: `#[linkage = "external|internal|..."]`
+   |     ^^^^^^^^^^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/linkage.html>
+help: the following are the possible correct uses
+   |
+LL |     #[linkage = "available_externally"]
+   |               ++++++++++++++++++++++++
+LL |     #[linkage = "common"]
+   |               ++++++++++
+LL |     #[linkage = "extern_weak"]
+   |               +++++++++++++++
+LL |     #[linkage = "external"]
+   |               ++++++++++++
+   = and 5 other candidates
 
 error: malformed `allow` attribute input
   --> $DIR/malformed-attrs.rs:175:1
    |
 LL | #[allow]
-   | ^^^^^^^^ help: must be of the form: `#[allow(lint1, lint2, ..., /*opt*/ reason = "...")]`
+   | ^^^^^^^^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+help: the following are the possible correct uses
+   |
+LL | #[allow(lint1)]
+   |        +++++++
+LL | #[allow(lint1, lint2, ...)]
+   |        +++++++++++++++++++
+LL | #[allow(lint1, lint2, lint3, reason = "...")]
+   |        +++++++++++++++++++++++++++++++++++++
 
 error: malformed `expect` attribute input
   --> $DIR/malformed-attrs.rs:177:1
    |
 LL | #[expect]
-   | ^^^^^^^^^ help: must be of the form: `#[expect(lint1, lint2, ..., /*opt*/ reason = "...")]`
+   | ^^^^^^^^^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+help: the following are the possible correct uses
+   |
+LL | #[expect(lint1)]
+   |         +++++++
+LL | #[expect(lint1, lint2, ...)]
+   |         +++++++++++++++++++
+LL | #[expect(lint1, lint2, lint3, reason = "...")]
+   |         +++++++++++++++++++++++++++++++++++++
 
 error: malformed `warn` attribute input
   --> $DIR/malformed-attrs.rs:179:1
    |
 LL | #[warn]
-   | ^^^^^^^ help: must be of the form: `#[warn(lint1, lint2, ..., /*opt*/ reason = "...")]`
+   | ^^^^^^^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+help: the following are the possible correct uses
+   |
+LL | #[warn(lint1)]
+   |       +++++++
+LL | #[warn(lint1, lint2, ...)]
+   |       +++++++++++++++++++
+LL | #[warn(lint1, lint2, lint3, reason = "...")]
+   |       +++++++++++++++++++++++++++++++++++++
 
 error: malformed `deny` attribute input
   --> $DIR/malformed-attrs.rs:181:1
    |
 LL | #[deny]
-   | ^^^^^^^ help: must be of the form: `#[deny(lint1, lint2, ..., /*opt*/ reason = "...")]`
+   | ^^^^^^^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+help: the following are the possible correct uses
+   |
+LL | #[deny(lint1)]
+   |       +++++++
+LL | #[deny(lint1, lint2, ...)]
+   |       +++++++++++++++++++
+LL | #[deny(lint1, lint2, lint3, reason = "...")]
+   |       +++++++++++++++++++++++++++++++++++++
 
 error: malformed `forbid` attribute input
   --> $DIR/malformed-attrs.rs:183:1
    |
 LL | #[forbid]
-   | ^^^^^^^^^ help: must be of the form: `#[forbid(lint1, lint2, ..., /*opt*/ reason = "...")]`
+   | ^^^^^^^^^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+help: the following are the possible correct uses
+   |
+LL | #[forbid(lint1)]
+   |         +++++++
+LL | #[forbid(lint1, lint2, ...)]
+   |         +++++++++++++++++++
+LL | #[forbid(lint1, lint2, lint3, reason = "...")]
+   |         +++++++++++++++++++++++++++++++++++++
 
 error: malformed `debugger_visualizer` attribute input
   --> $DIR/malformed-attrs.rs:185:1
    |
 LL | #[debugger_visualizer]
    | ^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[debugger_visualizer(natvis_file = "...", gdb_script_file = "...")]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute>
 
 error: malformed `thread_local` attribute input
   --> $DIR/malformed-attrs.rs:200:1
@@ -129,6 +208,8 @@ error: malformed `no_link` attribute input
    |
 LL | #[no_link()]
    | ^^^^^^^^^^^^ help: must be of the form: `#[no_link]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/extern-crates.html#the-no_link-attribute>
 
 error: malformed `macro_export` attribute input
   --> $DIR/malformed-attrs.rs:211:1
@@ -136,6 +217,7 @@ error: malformed `macro_export` attribute input
 LL | #[macro_export = 18]
    | ^^^^^^^^^^^^^^^^^^^^
    |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope>
 help: the following are the possible correct uses
    |
 LL - #[macro_export = 18]
@@ -145,12 +227,6 @@ LL - #[macro_export = 18]
 LL + #[macro_export]
    |
 
-error: malformed `allow_internal_unsafe` attribute input
-  --> $DIR/malformed-attrs.rs:213:1
-   |
-LL | #[allow_internal_unsafe = 1]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[allow_internal_unsafe]`
-
 error: the `#[proc_macro]` attribute is only usable with crates of the `proc-macro` crate type
   --> $DIR/malformed-attrs.rs:96:1
    |
@@ -178,7 +254,7 @@ LL | #[allow_internal_unsafe = 1]
    = help: add `#![feature(allow_internal_unsafe)]` 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: valid forms for the attribute are `#[doc(hidden|inline|...)]` and `#[doc = "string"]`
+error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]`
   --> $DIR/malformed-attrs.rs:40:1
    |
 LL | #[doc]
@@ -186,9 +262,10 @@ LL | #[doc]
    |
    = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: for more information, visit <https://doc.rust-lang.org/rustdoc/write-documentation/the-doc-attribute.html>
    = note: `#[deny(ill_formed_attribute_input)]` on by default
 
-error: valid forms for the attribute are `#[doc(hidden|inline|...)]` and `#[doc = "string"]`
+error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]`
   --> $DIR/malformed-attrs.rs:73:1
    |
 LL | #[doc]
@@ -196,8 +273,9 @@ LL | #[doc]
    |
    = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: for more information, visit <https://doc.rust-lang.org/rustdoc/write-documentation/the-doc-attribute.html>
 
-error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
+error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]`
   --> $DIR/malformed-attrs.rs:80:1
    |
 LL | #[link]
@@ -205,6 +283,7 @@ LL | #[link]
    |
    = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
 
 error: invalid argument
   --> $DIR/malformed-attrs.rs:185:1
@@ -257,26 +336,49 @@ LL - #[deprecated = 5]
 LL + #[deprecated = "reason"]
    |
 LL - #[deprecated = 5]
-LL + #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")]
+LL + #[deprecated(note = "reason")]
    |
 LL - #[deprecated = 5]
-LL + #[deprecated]
+LL + #[deprecated(since = "version")]
    |
+LL - #[deprecated = 5]
+LL + #[deprecated(since = "version", note = "reason")]
+   |
+   = and 1 other candidate
 
 error[E0539]: malformed `rustc_macro_transparency` attribute input
   --> $DIR/malformed-attrs.rs:43:1
    |
 LL | #[rustc_macro_transparency]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_macro_transparency = "transparent|semitransparent|opaque"]`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL | #[rustc_macro_transparency = "opaque"]
+   |                            ++++++++++
+LL | #[rustc_macro_transparency = "semitransparent"]
+   |                            +++++++++++++++++++
+LL | #[rustc_macro_transparency = "transparent"]
+   |                            +++++++++++++++
 
 error[E0539]: malformed `repr` attribute input
   --> $DIR/malformed-attrs.rs:45:1
    |
 LL | #[repr]
-   | ^^^^^^^
-   | |
-   | expected this to be a list
-   | help: must be of the form: `#[repr(C | Rust | align(...) | packed(...) | <integer type> | transparent)]`
+   | ^^^^^^^ expected this to be a list
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html#representations>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL | #[repr(<integer type>)]
+   |       ++++++++++++++++
+LL | #[repr(C)]
+   |       +++
+LL | #[repr(Rust)]
+   |       ++++++
+LL | #[repr(align(...))]
+   |       ++++++++++++
+   = and 2 other candidates
 
 error[E0565]: malformed `rustc_as_ptr` attribute input
   --> $DIR/malformed-attrs.rs:48:1
@@ -300,10 +402,16 @@ error[E0539]: malformed `optimize` attribute input
   --> $DIR/malformed-attrs.rs:55:1
    |
 LL | #[optimize]
-   | ^^^^^^^^^^^
-   | |
-   | expected this to be a list
-   | help: must be of the form: `#[optimize(size|speed|none)]`
+   | ^^^^^^^^^^^ expected this to be a list
+   |
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL | #[optimize(none)]
+   |           ++++++
+LL | #[optimize(size)]
+   |           ++++++
+LL | #[optimize(speed)]
+   |           +++++++
 
 error[E0565]: malformed `cold` attribute input
   --> $DIR/malformed-attrs.rs:57:1
@@ -363,8 +471,10 @@ LL | #[used()]
    |
 help: try changing it to one of the following valid forms of the attribute
    |
-LL | #[used(compiler|linker)]
-   |        +++++++++++++++
+LL | #[used(compiler)]
+   |        ++++++++
+LL | #[used(linker)]
+   |        ++++++
 LL - #[used()]
 LL + #[used]
    |
@@ -392,12 +502,16 @@ error[E0539]: malformed `link_name` attribute input
    |
 LL | #[link_name]
    | ^^^^^^^^^^^^ help: must be of the form: `#[link_name = "name"]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute>
 
 error[E0539]: malformed `link_section` attribute input
   --> $DIR/malformed-attrs.rs:85:1
    |
 LL | #[link_section]
    | ^^^^^^^^^^^^^^^ help: must be of the form: `#[link_section = "name"]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute>
 
 error[E0539]: malformed `coverage` attribute input
   --> $DIR/malformed-attrs.rs:87:1
@@ -456,6 +570,7 @@ LL | #[must_use = 1]
    |              |
    |              expected a string literal here
    |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute>
 help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[must_use = 1]
@@ -469,10 +584,15 @@ error[E0539]: malformed `proc_macro_derive` attribute input
   --> $DIR/malformed-attrs.rs:120:1
    |
 LL | #[proc_macro_derive]
-   | ^^^^^^^^^^^^^^^^^^^^
-   | |
-   | expected this to be a list
-   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+   | ^^^^^^^^^^^^^^^^^^^^ expected this to be a list
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL | #[proc_macro_derive(TraitName)]
+   |                    +++++++++++
+LL | #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
+   |                    ++++++++++++++++++++++++++++++++++++++++++
 
 error[E0539]: malformed `rustc_layout_scalar_valid_range_start` attribute input
   --> $DIR/malformed-attrs.rs:125:1
@@ -527,6 +647,8 @@ LL |     #[link_ordinal]
    |     |
    |     expected this to be a list
    |     help: must be of the form: `#[link_ordinal(ordinal)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute>
 
 error[E0565]: malformed `ffi_const` attribute input
   --> $DIR/malformed-attrs.rs:168:5
@@ -561,6 +683,15 @@ error: valid forms for the attribute are `#[macro_use(name1, name2, ...)]` and `
 LL | #[macro_use = 1]
    | ^^^^^^^^^^^^^^^^
 
+error[E0565]: malformed `allow_internal_unsafe` attribute input
+  --> $DIR/malformed-attrs.rs:213:1
+   |
+LL | #[allow_internal_unsafe = 1]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^---^
+   | |                       |
+   | |                       didn't expect any arguments here
+   | help: must be of the form: `#[allow_internal_unsafe]`
+
 error[E0565]: malformed `type_const` attribute input
   --> $DIR/malformed-attrs.rs:140:5
    |
@@ -618,7 +749,7 @@ LL | #[diagnostic::on_unimplemented = 1]
    |
    = help: only `message`, `note` and `label` are allowed as options
 
-error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]`
+error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
   --> $DIR/malformed-attrs.rs:50:1
    |
 LL | #[inline = 5]
@@ -661,7 +792,7 @@ error: aborting due to 74 previous errors; 3 warnings emitted
 Some errors have detailed explanations: E0308, E0463, E0539, E0565, E0658, E0805.
 For more information about an error, try `rustc --explain E0308`.
 Future incompatibility report: Future breakage diagnostic:
-error: valid forms for the attribute are `#[doc(hidden|inline|...)]` and `#[doc = "string"]`
+error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]`
   --> $DIR/malformed-attrs.rs:40:1
    |
 LL | #[doc]
@@ -669,10 +800,11 @@ LL | #[doc]
    |
    = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: for more information, visit <https://doc.rust-lang.org/rustdoc/write-documentation/the-doc-attribute.html>
    = note: `#[deny(ill_formed_attribute_input)]` on by default
 
 Future breakage diagnostic:
-error: valid forms for the attribute are `#[doc(hidden|inline|...)]` and `#[doc = "string"]`
+error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]`
   --> $DIR/malformed-attrs.rs:73:1
    |
 LL | #[doc]
@@ -680,10 +812,11 @@ LL | #[doc]
    |
    = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: for more information, visit <https://doc.rust-lang.org/rustdoc/write-documentation/the-doc-attribute.html>
    = note: `#[deny(ill_formed_attribute_input)]` on by default
 
 Future breakage diagnostic:
-error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
+error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]`
   --> $DIR/malformed-attrs.rs:80:1
    |
 LL | #[link]
@@ -691,10 +824,11 @@ LL | #[link]
    |
    = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
    = note: `#[deny(ill_formed_attribute_input)]` on by default
 
 Future breakage diagnostic:
-error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]`
+error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
   --> $DIR/malformed-attrs.rs:50:1
    |
 LL | #[inline = 5]
diff --git a/tests/ui/attributes/malformed-reprs.stderr b/tests/ui/attributes/malformed-reprs.stderr
index c39c98dde31..43085b9c341 100644
--- a/tests/ui/attributes/malformed-reprs.stderr
+++ b/tests/ui/attributes/malformed-reprs.stderr
@@ -2,10 +2,24 @@ error[E0539]: malformed `repr` attribute input
   --> $DIR/malformed-reprs.rs:4:1
    |
 LL | #![repr]
-   | ^^^^^^^^
-   | |
-   | expected this to be a list
-   | help: must be of the form: `#[repr(C | Rust | align(...) | packed(...) | <integer type> | transparent)]`
+   | ^^^^^^^^ expected this to be a list
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html#representations>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #![repr]
+LL + #[repr(<integer type>)]
+   |
+LL - #![repr]
+LL + #[repr(C)]
+   |
+LL - #![repr]
+LL + #[repr(Rust)]
+   |
+LL - #![repr]
+LL + #[repr(align(...))]
+   |
+   = and 2 other candidates
 
 error[E0589]: invalid `repr(align)` attribute: not a power of two
   --> $DIR/malformed-reprs.rs:9:14
diff --git a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr
index 884e7663c85..107e053ae0c 100644
--- a/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr
+++ b/tests/ui/attributes/unsafe/proc-unsafe-attributes.stderr
@@ -119,9 +119,18 @@ error[E0565]: malformed `proc_macro_derive` attribute input
    |
 LL | #[proc_macro_derive(unsafe(Foo))]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^-----^^
-   | |                         |
-   | |                         didn't expect any arguments here
-   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+   |                           |
+   |                           didn't expect any arguments here
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[proc_macro_derive(unsafe(Foo))]
+LL + #[proc_macro_derive(TraitName)]
+   |
+LL - #[proc_macro_derive(unsafe(Foo))]
+LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
+   |
 
 error[E0452]: malformed lint attribute input
   --> $DIR/proc-unsafe-attributes.rs:27:16
diff --git a/tests/ui/attributes/used_with_multi_args.stderr b/tests/ui/attributes/used_with_multi_args.stderr
index e48209cf204..308f0519b8c 100644
--- a/tests/ui/attributes/used_with_multi_args.stderr
+++ b/tests/ui/attributes/used_with_multi_args.stderr
@@ -9,7 +9,10 @@ LL | #[used(compiler, linker)]
 help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[used(compiler, linker)]
-LL + #[used(compiler|linker)]
+LL + #[used(compiler)]
+   |
+LL - #[used(compiler, linker)]
+LL + #[used(linker)]
    |
 LL - #[used(compiler, linker)]
 LL + #[used]
diff --git a/tests/ui/cfg/cfg-target-compact-errors.stderr b/tests/ui/cfg/cfg-target-compact-errors.stderr
index 7df6729e881..cf61f94278a 100644
--- a/tests/ui/cfg/cfg-target-compact-errors.stderr
+++ b/tests/ui/cfg/cfg-target-compact-errors.stderr
@@ -6,6 +6,8 @@ LL | #[cfg(target(o::o))]
    | |            |
    | |            expected this to be of the form `... = "..."`
    | help: must be of the form: `#[cfg(predicate)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
 
 error[E0539]: malformed `cfg` attribute input
   --> $DIR/cfg-target-compact-errors.rs:9:1
@@ -15,6 +17,8 @@ LL | #[cfg(target(os = 8))]
    | |                 |
    | |                 expected a string literal here
    | help: must be of the form: `#[cfg(predicate)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
 
 error[E0539]: malformed `cfg` attribute input
   --> $DIR/cfg-target-compact-errors.rs:13:1
@@ -24,6 +28,8 @@ LL | #[cfg(target(os = "linux", pointer(width = "64")))]
    | |                          |
    | |                          expected this to be of the form `... = "..."`
    | help: must be of the form: `#[cfg(predicate)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
 
 error[E0539]: malformed `cfg` attribute input
   --> $DIR/cfg-target-compact-errors.rs:17:1
@@ -33,6 +39,8 @@ LL | #[cfg(target(true))]
    | |            |
    | |            expected this to be of the form `... = "..."`
    | help: must be of the form: `#[cfg(predicate)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
 
 error: `cfg` predicate key must be an identifier
   --> $DIR/cfg-target-compact-errors.rs:21:14
diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr
index 44fc23b6390..5dd81f486c8 100644
--- a/tests/ui/check-cfg/target_feature.stderr
+++ b/tests/ui/check-cfg/target_feature.stderr
@@ -183,6 +183,7 @@ LL |     cfg!(target_feature = "_UNEXPECTED_VALUE");
 `nnp-assist`
 `nontrapping-fptoint`
 `nvic`
+`outline-atomics`
 `paca`
 `pacg`
 `pan`
diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs
index df87a3d846e..126a534dc6f 100644
--- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs
+++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs
@@ -1,21 +1,25 @@
 #[cfg]
 //~^ ERROR malformed `cfg` attribute
 //~| NOTE expected this to be a list
+//~| NOTE for more information, visit
 struct S1;
 
 #[cfg = 10]
 //~^ ERROR malformed `cfg` attribute
 //~| NOTE expected this to be a list
+//~| NOTE for more information, visit
 struct S2;
 
 #[cfg()]
 //~^ ERROR malformed `cfg` attribute
 //~| NOTE expected a single argument here
+//~| NOTE for more information, visit
 struct S3;
 
 #[cfg(a, b)]
 //~^ ERROR malformed `cfg` attribute
 //~| NOTE expected a single argument here
+//~| NOTE for more information, visit
 struct S4;
 
 #[cfg("str")] //~ ERROR `cfg` predicate key must be an identifier
@@ -29,6 +33,7 @@ struct S7;
 
 #[cfg(a = 10)] //~ ERROR malformed `cfg` attribute input
 //~^ NOTE expected a string literal here
+//~| NOTE for more information, visit
 struct S8;
 
 #[cfg(a = b"hi")]  //~ ERROR malformed `cfg` attribute input
diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
index 75e9b9209c0..6acde758ea5 100644
--- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
+++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
@@ -6,63 +6,73 @@ LL | #[cfg]
    | |
    | expected this to be a list
    | help: must be of the form: `#[cfg(predicate)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
 
 error[E0539]: malformed `cfg` attribute input
-  --> $DIR/cfg-attr-syntax-validation.rs:6:1
+  --> $DIR/cfg-attr-syntax-validation.rs:7:1
    |
 LL | #[cfg = 10]
    | ^^^^^^^^^^^
    | |
    | expected this to be a list
    | help: must be of the form: `#[cfg(predicate)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
 
 error[E0805]: malformed `cfg` attribute input
-  --> $DIR/cfg-attr-syntax-validation.rs:11:1
+  --> $DIR/cfg-attr-syntax-validation.rs:13:1
    |
 LL | #[cfg()]
    | ^^^^^--^
    | |    |
    | |    expected a single argument here
    | help: must be of the form: `#[cfg(predicate)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
 
 error[E0805]: malformed `cfg` attribute input
-  --> $DIR/cfg-attr-syntax-validation.rs:16:1
+  --> $DIR/cfg-attr-syntax-validation.rs:19:1
    |
 LL | #[cfg(a, b)]
    | ^^^^^------^
    | |    |
    | |    expected a single argument here
    | help: must be of the form: `#[cfg(predicate)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
 
 error: `cfg` predicate key must be an identifier
-  --> $DIR/cfg-attr-syntax-validation.rs:21:7
+  --> $DIR/cfg-attr-syntax-validation.rs:25:7
    |
 LL | #[cfg("str")]
    |       ^^^^^
 
 error: `cfg` predicate key must be an identifier
-  --> $DIR/cfg-attr-syntax-validation.rs:24:7
+  --> $DIR/cfg-attr-syntax-validation.rs:28:7
    |
 LL | #[cfg(a::b)]
    |       ^^^^
 
 error[E0537]: invalid predicate `a`
-  --> $DIR/cfg-attr-syntax-validation.rs:27:7
+  --> $DIR/cfg-attr-syntax-validation.rs:31:7
    |
 LL | #[cfg(a())]
    |       ^^^
 
 error[E0539]: malformed `cfg` attribute input
-  --> $DIR/cfg-attr-syntax-validation.rs:30:1
+  --> $DIR/cfg-attr-syntax-validation.rs:34:1
    |
 LL | #[cfg(a = 10)]
    | ^^^^^^^^^^--^^
    | |         |
    | |         expected a string literal here
    | help: must be of the form: `#[cfg(predicate)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute>
 
 error[E0539]: malformed `cfg` attribute input
-  --> $DIR/cfg-attr-syntax-validation.rs:34:1
+  --> $DIR/cfg-attr-syntax-validation.rs:39:1
    |
 LL | #[cfg(a = b"hi")]
    | ^^^^^^^^^^-^^^^^^
@@ -72,7 +82,7 @@ LL | #[cfg(a = b"hi")]
    = note: expected a normal string literal, not a byte string literal
 
 error: expected unsuffixed literal, found `expr` metavariable
-  --> $DIR/cfg-attr-syntax-validation.rs:40:25
+  --> $DIR/cfg-attr-syntax-validation.rs:45:25
    |
 LL |         #[cfg(feature = $expr)]
    |                         ^^^^^
diff --git a/tests/ui/deprecation/deprecation-sanity.stderr b/tests/ui/deprecation/deprecation-sanity.stderr
index f1b4697485c..856f51a4b24 100644
--- a/tests/ui/deprecation/deprecation-sanity.stderr
+++ b/tests/ui/deprecation/deprecation-sanity.stderr
@@ -18,11 +18,15 @@ LL -     #[deprecated(since = "a", note)]
 LL +     #[deprecated = "reason"]
    |
 LL -     #[deprecated(since = "a", note)]
-LL +     #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")]
+LL +     #[deprecated(note = "reason")]
    |
 LL -     #[deprecated(since = "a", note)]
-LL +     #[deprecated]
+LL +     #[deprecated(since = "version")]
    |
+LL -     #[deprecated(since = "a", note)]
+LL +     #[deprecated(since = "version", note = "reason")]
+   |
+   = and 1 other candidate
 
 error[E0539]: malformed `deprecated` attribute input
   --> $DIR/deprecation-sanity.rs:10:5
@@ -38,11 +42,15 @@ LL -     #[deprecated(since, note = "a")]
 LL +     #[deprecated = "reason"]
    |
 LL -     #[deprecated(since, note = "a")]
-LL +     #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")]
+LL +     #[deprecated(note = "reason")]
+   |
+LL -     #[deprecated(since, note = "a")]
+LL +     #[deprecated(since = "version")]
    |
 LL -     #[deprecated(since, note = "a")]
-LL +     #[deprecated]
+LL +     #[deprecated(since = "version", note = "reason")]
    |
+   = and 1 other candidate
 
 error[E0539]: malformed `deprecated` attribute input
   --> $DIR/deprecation-sanity.rs:13:5
@@ -58,11 +66,15 @@ LL -     #[deprecated(since = "a", note(b))]
 LL +     #[deprecated = "reason"]
    |
 LL -     #[deprecated(since = "a", note(b))]
-LL +     #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")]
+LL +     #[deprecated(note = "reason")]
+   |
+LL -     #[deprecated(since = "a", note(b))]
+LL +     #[deprecated(since = "version")]
    |
 LL -     #[deprecated(since = "a", note(b))]
-LL +     #[deprecated]
+LL +     #[deprecated(since = "version", note = "reason")]
    |
+   = and 1 other candidate
 
 error[E0539]: malformed `deprecated` attribute input
   --> $DIR/deprecation-sanity.rs:16:5
@@ -78,11 +90,15 @@ LL -     #[deprecated(since(b), note = "a")]
 LL +     #[deprecated = "reason"]
    |
 LL -     #[deprecated(since(b), note = "a")]
-LL +     #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")]
+LL +     #[deprecated(note = "reason")]
    |
 LL -     #[deprecated(since(b), note = "a")]
-LL +     #[deprecated]
+LL +     #[deprecated(since = "version")]
    |
+LL -     #[deprecated(since(b), note = "a")]
+LL +     #[deprecated(since = "version", note = "reason")]
+   |
+   = and 1 other candidate
 
 error[E0539]: malformed `deprecated` attribute input
   --> $DIR/deprecation-sanity.rs:19:5
@@ -108,11 +124,15 @@ LL -     #[deprecated("test")]
 LL +     #[deprecated = "reason"]
    |
 LL -     #[deprecated("test")]
-LL +     #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")]
+LL +     #[deprecated(note = "reason")]
+   |
+LL -     #[deprecated("test")]
+LL +     #[deprecated(since = "version")]
    |
 LL -     #[deprecated("test")]
-LL +     #[deprecated]
+LL +     #[deprecated(since = "version", note = "reason")]
    |
+   = and 1 other candidate
 
 error: multiple `deprecated` attributes
   --> $DIR/deprecation-sanity.rs:27:1
@@ -140,11 +160,15 @@ LL - #[deprecated(since = "a", since = "b", note = "c")]
 LL + #[deprecated = "reason"]
    |
 LL - #[deprecated(since = "a", since = "b", note = "c")]
-LL + #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")]
+LL + #[deprecated(note = "reason")]
+   |
+LL - #[deprecated(since = "a", since = "b", note = "c")]
+LL + #[deprecated(since = "version")]
    |
 LL - #[deprecated(since = "a", since = "b", note = "c")]
-LL + #[deprecated]
+LL + #[deprecated(since = "version", note = "reason")]
    |
+   = and 1 other candidate
 
 error: this `#[deprecated]` annotation has no effect
   --> $DIR/deprecation-sanity.rs:35:1
diff --git a/tests/ui/dist/cranelift-x86_64-unknown-linux-gnu-dist.rs b/tests/ui/dist/cranelift-x86_64-unknown-linux-gnu-dist.rs
new file mode 100644
index 00000000000..198f8d1bc10
--- /dev/null
+++ b/tests/ui/dist/cranelift-x86_64-unknown-linux-gnu-dist.rs
@@ -0,0 +1,11 @@
+// Ensure that Cranelift can be used to compile a simple program with `x86_64-unknown-linux-gnu`
+// dist artifacts.
+
+//@ only-dist
+//@ only-x86_64-unknown-linux-gnu
+//@ compile-flags: -Z codegen-backend=cranelift
+//@ run-pass
+
+fn main() {
+    println!("Hello world!");
+}
diff --git a/tests/ui/error-codes/E0197.stderr b/tests/ui/error-codes/E0197.stderr
index c06777396e8..04c6174b9f1 100644
--- a/tests/ui/error-codes/E0197.stderr
+++ b/tests/ui/error-codes/E0197.stderr
@@ -5,6 +5,8 @@ LL | unsafe impl Foo { }
    | ------      ^^^ inherent impl for this type
    | |
    | unsafe because of this
+   |
+   = note: only trait implementations may be annotated with `unsafe`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/error-codes/E0540.stderr b/tests/ui/error-codes/E0540.stderr
index 3e5f408feb5..ae23dce5c50 100644
--- a/tests/ui/error-codes/E0540.stderr
+++ b/tests/ui/error-codes/E0540.stderr
@@ -6,10 +6,13 @@ LL | #[inline()]
    |         |
    |         expected a single argument here
    |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute>
 help: try changing it to one of the following valid forms of the attribute
    |
-LL | #[inline(always|never)]
-   |          ++++++++++++
+LL | #[inline(always)]
+   |          ++++++
+LL | #[inline(never)]
+   |          +++++
 LL - #[inline()]
 LL + #[inline]
    |
diff --git a/tests/ui/error-codes/E0565-1.stderr b/tests/ui/error-codes/E0565-1.stderr
index 6277e6400d7..52daf2a62fc 100644
--- a/tests/ui/error-codes/E0565-1.stderr
+++ b/tests/ui/error-codes/E0565-1.stderr
@@ -12,11 +12,15 @@ LL - #[deprecated("since")]
 LL + #[deprecated = "reason"]
    |
 LL - #[deprecated("since")]
-LL + #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")]
+LL + #[deprecated(note = "reason")]
    |
 LL - #[deprecated("since")]
-LL + #[deprecated]
+LL + #[deprecated(since = "version")]
    |
+LL - #[deprecated("since")]
+LL + #[deprecated(since = "version", note = "reason")]
+   |
+   = and 1 other candidate
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/extern/issue-47725.rs b/tests/ui/extern/issue-47725.rs
index 60d0cd62347..8ac866dc7d9 100644
--- a/tests/ui/extern/issue-47725.rs
+++ b/tests/ui/extern/issue-47725.rs
@@ -17,6 +17,7 @@ extern "C" {
 #[link_name]
 //~^ ERROR malformed `link_name` attribute input
 //~| HELP must be of the form
+//~| NOTE for more information, visit
 extern "C" {
     fn bar() -> u32;
 }
diff --git a/tests/ui/extern/issue-47725.stderr b/tests/ui/extern/issue-47725.stderr
index 4fd02a1778b..c5af54b8029 100644
--- a/tests/ui/extern/issue-47725.stderr
+++ b/tests/ui/extern/issue-47725.stderr
@@ -3,6 +3,8 @@ error[E0539]: malformed `link_name` attribute input
    |
 LL | #[link_name]
    | ^^^^^^^^^^^^ help: must be of the form: `#[link_name = "name"]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute>
 
 warning: attribute should be applied to a foreign function or static
   --> $DIR/issue-47725.rs:3:1
diff --git a/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr b/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr
index e7e62b4f989..646abf8e4a1 100644
--- a/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr
+++ b/tests/ui/feature-gates/feature-gate-optimize_attribute.stderr
@@ -43,9 +43,20 @@ error[E0539]: malformed `optimize` attribute input
    |
 LL | #[optimize(banana)]
    | ^^^^^^^^^^^------^^
-   | |          |
-   | |          valid arguments are `size`, `speed` or `none`
-   | help: must be of the form: `#[optimize(size|speed|none)]`
+   |            |
+   |            valid arguments are `size`, `speed` or `none`
+   |
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[optimize(banana)]
+LL + #[optimize(none)]
+   |
+LL - #[optimize(banana)]
+LL + #[optimize(size)]
+   |
+LL - #[optimize(banana)]
+LL + #[optimize(speed)]
+   |
 
 error: aborting due to 5 previous errors
 
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 324f7e9fd8a..7550e26f4a7 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
@@ -304,7 +304,7 @@ error[E0517]: attribute should be applied to a struct, enum, or union
 LL |     #[repr(Rust)] impl S { }
    |            ^^^^   ---------- not a struct, enum, or union
 
-error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]`
+error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
   --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:5
    |
 LL |     #[inline = "2100"] fn f() { }
@@ -319,7 +319,7 @@ error: aborting due to 38 previous errors
 Some errors have detailed explanations: E0517, E0518, E0658.
 For more information about an error, try `rustc --explain E0517`.
 Future incompatibility report: Future breakage diagnostic:
-error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]`
+error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
   --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:5
    |
 LL |     #[inline = "2100"] fn f() { }
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
index b93cb2ea006..c91fd600068 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.rs
@@ -71,6 +71,7 @@
 //~^^ WARN this was previously accepted by the compiler
 #![must_use]
 //~^ WARN `#[must_use]` has no effect
+//~| HELP remove the attribute
 // see issue-43106-gating-of-stable.rs
 // see issue-43106-gating-of-unstable.rs
 // see issue-43106-gating-of-deprecated.rs
@@ -599,16 +600,20 @@ mod deprecated {
 }
 
 #[must_use] //~ WARN `#[must_use]` has no effect
+//~^ HELP remove the attribute
 mod must_use {
     mod inner { #![must_use] } //~ WARN `#[must_use]` has no effect
+    //~^ HELP remove the attribute
 
     #[must_use] fn f() { }
 
     #[must_use] struct S;
 
     #[must_use] type T = S; //~ WARN `#[must_use]` has no effect
+    //~^ HELP remove the attribute
 
     #[must_use] impl S { } //~ WARN `#[must_use]` has no effect
+    //~^ HELP remove the attribute
 }
 
 #[windows_subsystem = "windows"]
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
index f2ae50b75a3..e0ea5382faa 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr
@@ -1,5 +1,5 @@
 warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:397:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:398:17
    |
 LL |     mod inner { #![macro_escape] }
    |                 ^^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL |     mod inner { #![macro_escape] }
    = help: try an outer attribute: `#[macro_use]`
 
 warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:394:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:395:1
    |
 LL | #[macro_escape]
    | ^^^^^^^^^^^^^^^
@@ -43,151 +43,151 @@ LL | #![deny(x5100)]
    |         ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:96:8
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:97:8
    |
 LL | #[warn(x5400)]
    |        ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:99:25
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:100:25
    |
 LL |     mod inner { #![warn(x5400)] }
    |                         ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:102:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:103:12
    |
 LL |     #[warn(x5400)] fn f() { }
    |            ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:105:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:106:12
    |
 LL |     #[warn(x5400)] struct S;
    |            ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:108:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:109:12
    |
 LL |     #[warn(x5400)] type T = S;
    |            ^^^^^
 
 warning: unknown lint: `x5400`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:111:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:112:12
    |
 LL |     #[warn(x5400)] impl S { }
    |            ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:115:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:116:9
    |
 LL | #[allow(x5300)]
    |         ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:118:26
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:119:26
    |
 LL |     mod inner { #![allow(x5300)] }
    |                          ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:121:13
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:122:13
    |
 LL |     #[allow(x5300)] fn f() { }
    |             ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:124:13
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:125:13
    |
 LL |     #[allow(x5300)] struct S;
    |             ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:127:13
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:128:13
    |
 LL |     #[allow(x5300)] type T = S;
    |             ^^^^^
 
 warning: unknown lint: `x5300`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:130:13
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:131:13
    |
 LL |     #[allow(x5300)] impl S { }
    |             ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:134:10
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:135:10
    |
 LL | #[forbid(x5200)]
    |          ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:137:27
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:138:27
    |
 LL |     mod inner { #![forbid(x5200)] }
    |                           ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:140:14
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:141:14
    |
 LL |     #[forbid(x5200)] fn f() { }
    |              ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:143:14
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:144:14
    |
 LL |     #[forbid(x5200)] struct S;
    |              ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:146:14
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:147:14
    |
 LL |     #[forbid(x5200)] type T = S;
    |              ^^^^^
 
 warning: unknown lint: `x5200`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:149:14
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:150:14
    |
 LL |     #[forbid(x5200)] impl S { }
    |              ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:153:8
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:154:8
    |
 LL | #[deny(x5100)]
    |        ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:156:25
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:157:25
    |
 LL |     mod inner { #![deny(x5100)] }
    |                         ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:159:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:160:12
    |
 LL |     #[deny(x5100)] fn f() { }
    |            ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:162:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:163:12
    |
 LL |     #[deny(x5100)] struct S;
    |            ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:165:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:166:12
    |
 LL |     #[deny(x5100)] type T = S;
    |            ^^^^^
 
 warning: unknown lint: `x5100`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:168:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:169:12
    |
 LL |     #[deny(x5100)] impl S { }
    |            ^^^^^
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:189:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:190:1
    |
 LL | #[macro_export]
    | ^^^^^^^^^^^^^^^
@@ -199,13 +199,13 @@ LL | #![warn(unused_attributes, unknown_lints)]
    |         ^^^^^^^^^^^^^^^^^
 
 warning: `#[automatically_derived]` only has an effect on trait implementation blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:257:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:258:1
    |
 LL | #[automatically_derived]
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:281:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:282:1
    |
 LL |   #[no_mangle]
    |   ^^^^^^^^^^^^
@@ -220,31 +220,31 @@ LL | | }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: `#[should_panic]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:321:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:322:1
    |
 LL | #[should_panic]
    | ^^^^^^^^^^^^^^^
 
 warning: `#[ignore]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:339:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:340:1
    |
 LL | #[ignore]
    | ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:374:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:375:1
    |
 LL | #[reexport_test_harness_main = "2900"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:415:1
    |
 LL | #[no_std]
    | ^^^^^^^^^
 
 warning: attribute should be applied to a function definition
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:450:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:451:1
    |
 LL |   #[cold]
    |   ^^^^^^^
@@ -260,7 +260,7 @@ LL | | }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:480:1
    |
 LL |   #[link_name = "1900"]
    |   ^^^^^^^^^^^^^^^^^^^^^
@@ -276,7 +276,7 @@ LL | | }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:518:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:519:1
    |
 LL |   #[link_section = "1800"]
    |   ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -292,7 +292,7 @@ LL | | }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:550:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:551:1
    |
 LL |   #[link()]
    |   ^^^^^^^^^
@@ -308,55 +308,55 @@ LL | | }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: `#[must_use]` has no effect when applied to a module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:601:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:602:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:614:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:619:1
    |
 LL | #[windows_subsystem = "windows"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:635:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:640:1
    |
 LL | #[crate_name = "0900"]
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:654:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:659:1
    |
 LL | #[crate_type = "0800"]
    | ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:673:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:678:1
    |
 LL | #[feature(x0600)]
    | ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:698:1
    |
 LL | #[no_main]
    | ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:717:1
    |
 LL | #[no_builtins]
    | ^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:731:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:736:1
    |
 LL | #[recursion_limit="0200"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:1
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:755:1
    |
 LL | #[type_length_limit="0100"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -418,7 +418,7 @@ LL | #![cold]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:85:12
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:86:12
    |
 LL | #![feature(rust1)]
    |            ^^^^^
@@ -426,121 +426,121 @@ LL | #![feature(rust1)]
    = note: `#[warn(stable_features)]` on by default
 
 warning: `#[macro_use]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:176:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:177:5
    |
 LL |     #[macro_use] fn f() { }
    |     ^^^^^^^^^^^^
 
 warning: `#[macro_use]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:179:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:180:5
    |
 LL |     #[macro_use] struct S;
    |     ^^^^^^^^^^^^
 
 warning: `#[macro_use]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:182:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:183:5
    |
 LL |     #[macro_use] type T = S;
    |     ^^^^^^^^^^^^
 
 warning: `#[macro_use]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:185:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:186:5
    |
 LL |     #[macro_use] impl S { }
    |     ^^^^^^^^^^^^
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:192:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:193:17
    |
 LL |     mod inner { #![macro_export] }
    |                 ^^^^^^^^^^^^^^^^
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:195:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:196:5
    |
 LL |     #[macro_export] fn f() { }
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:198:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:199:5
    |
 LL |     #[macro_export] struct S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:201:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:202:5
    |
 LL |     #[macro_export] type T = S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_export]` only has an effect on macro definitions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:204:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:205:5
    |
 LL |     #[macro_export] impl S { }
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[path]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:244:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:245:5
    |
 LL |     #[path = "3800"] fn f() { }
    |     ^^^^^^^^^^^^^^^^
 
 warning: `#[path]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:247:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:248:5
    |
 LL |     #[path = "3800"]  struct S;
    |     ^^^^^^^^^^^^^^^^
 
 warning: `#[path]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:250:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:251:5
    |
 LL |     #[path = "3800"] type T = S;
    |     ^^^^^^^^^^^^^^^^
 
 warning: `#[path]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:253:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:254:5
    |
 LL |     #[path = "3800"] impl S { }
    |     ^^^^^^^^^^^^^^^^
 
 warning: `#[automatically_derived]` only has an effect on trait implementation blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:260:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:261:17
    |
 LL |     mod inner { #![automatically_derived] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[automatically_derived]` only has an effect on trait implementation blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:263:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:264:5
    |
 LL |     #[automatically_derived] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[automatically_derived]` only has an effect on trait implementation blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:266:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:267:5
    |
 LL |     #[automatically_derived] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[automatically_derived]` only has an effect on trait implementation blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:269:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:270:5
    |
 LL |     #[automatically_derived] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[automatically_derived]` only has an effect on trait implementation blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:272:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:273:5
    |
 LL |     #[automatically_derived] trait W { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[automatically_derived]` only has an effect on trait implementation blocks
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:275:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:276:5
    |
 LL |     #[automatically_derived] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:286:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:287:17
    |
 LL |     mod inner { #![no_mangle] }
    |     ------------^^^^^^^^^^^^^-- not a free function, impl method or static
@@ -548,7 +548,7 @@ LL |     mod inner { #![no_mangle] }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:293:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:294:5
    |
 LL |     #[no_mangle] struct S;
    |     ^^^^^^^^^^^^ --------- not a free function, impl method or static
@@ -556,7 +556,7 @@ LL |     #[no_mangle] struct S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:298:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:299:5
    |
 LL |     #[no_mangle] type T = S;
    |     ^^^^^^^^^^^^ ----------- not a free function, impl method or static
@@ -564,7 +564,7 @@ LL |     #[no_mangle] type T = S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:303:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:304:5
    |
 LL |     #[no_mangle] impl S { }
    |     ^^^^^^^^^^^^ ---------- not a free function, impl method or static
@@ -572,7 +572,7 @@ LL |     #[no_mangle] impl S { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:309:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:310:9
    |
 LL |         #[no_mangle] fn foo();
    |         ^^^^^^^^^^^^ --------- not a free function, impl method or static
@@ -580,7 +580,7 @@ LL |         #[no_mangle] fn foo();
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a free function, impl method or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:314:9
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:315:9
    |
 LL |         #[no_mangle] fn bar() {}
    |         ^^^^^^^^^^^^ ----------- not a free function, impl method or static
@@ -588,163 +588,163 @@ LL |         #[no_mangle] fn bar() {}
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: `#[should_panic]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:324:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:325:17
    |
 LL |     mod inner { #![should_panic] }
    |                 ^^^^^^^^^^^^^^^^
 
 warning: `#[should_panic]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:329:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:330:5
    |
 LL |     #[should_panic] struct S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[should_panic]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:332:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:333:5
    |
 LL |     #[should_panic] type T = S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[should_panic]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:335:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:336:5
    |
 LL |     #[should_panic] impl S { }
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[ignore]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:342:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:343:17
    |
 LL |     mod inner { #![ignore] }
    |                 ^^^^^^^^^^
 
 warning: `#[ignore]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:347:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:348:5
    |
 LL |     #[ignore] struct S;
    |     ^^^^^^^^^
 
 warning: `#[ignore]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:350:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:351:5
    |
 LL |     #[ignore] type T = S;
    |     ^^^^^^^^^
 
 warning: `#[ignore]` only has an effect on functions
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:353:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:354:5
    |
 LL |     #[ignore] impl S { }
    |     ^^^^^^^^^
 
 warning: `#[no_implicit_prelude]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:361:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:362:5
    |
 LL |     #[no_implicit_prelude] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[no_implicit_prelude]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:364:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:365:5
    |
 LL |     #[no_implicit_prelude] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[no_implicit_prelude]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:367:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:368:5
    |
 LL |     #[no_implicit_prelude] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[no_implicit_prelude]` only has an effect on modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:371:5
    |
 LL |     #[no_implicit_prelude] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:377:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:378:17
    |
 LL |     mod inner { #![reexport_test_harness_main="2900"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:380:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:381:5
    |
 LL |     #[reexport_test_harness_main = "2900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:383:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:384:5
    |
 LL |     #[reexport_test_harness_main = "2900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:386:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:387:5
    |
 LL |     #[reexport_test_harness_main = "2900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:389:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:390:5
    |
 LL |     #[reexport_test_harness_main = "2900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: `#[macro_escape]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:401:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:402:5
    |
 LL |     #[macro_escape] fn f() { }
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_escape]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:404:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:405:5
    |
 LL |     #[macro_escape] struct S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_escape]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:407:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:5
    |
 LL |     #[macro_escape] type T = S;
    |     ^^^^^^^^^^^^^^^
 
 warning: `#[macro_escape]` only has an effect on `extern crate` and modules
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:410:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:411:5
    |
 LL |     #[macro_escape] impl S { }
    |     ^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:418:17
    |
 LL |     mod inner { #![no_std] }
    |                 ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:421:5
    |
 LL |     #[no_std] fn f() { }
    |     ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:423:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:424:5
    |
 LL |     #[no_std] struct S;
    |     ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:426:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:427:5
    |
 LL |     #[no_std] type T = S;
    |     ^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:429:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:430:5
    |
 LL |     #[no_std] impl S { }
    |     ^^^^^^^^^
 
 warning: attribute should be applied to a function definition
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:456:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:457:17
    |
 LL |     mod inner { #![cold] }
    |     ------------^^^^^^^^-- not a function definition
@@ -752,7 +752,7 @@ LL |     mod inner { #![cold] }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function definition
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:463:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:464:5
    |
 LL |     #[cold] struct S;
    |     ^^^^^^^ --------- not a function definition
@@ -760,7 +760,7 @@ LL |     #[cold] struct S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function definition
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:468:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:469:5
    |
 LL |     #[cold] type T = S;
    |     ^^^^^^^ ----------- not a function definition
@@ -768,7 +768,7 @@ LL |     #[cold] type T = S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function definition
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:473:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:474:5
    |
 LL |     #[cold] impl S { }
    |     ^^^^^^^ ---------- not a function definition
@@ -776,7 +776,7 @@ LL |     #[cold] impl S { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:485:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:486:5
    |
 LL |     #[link_name = "1900"]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -786,13 +786,13 @@ LL |     extern "C" { }
    |
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 help: try `#[link(name = "1900")]` instead
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:485:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:486:5
    |
 LL |     #[link_name = "1900"]
    |     ^^^^^^^^^^^^^^^^^^^^^
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:492:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:493:17
    |
 LL |     mod inner { #![link_name="1900"] }
    |     ------------^^^^^^^^^^^^^^^^^^^^-- not a foreign function or static
@@ -800,7 +800,7 @@ LL |     mod inner { #![link_name="1900"] }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:497:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:498:5
    |
 LL |     #[link_name = "1900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static
@@ -808,7 +808,7 @@ LL |     #[link_name = "1900"] fn f() { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:502:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:503:5
    |
 LL |     #[link_name = "1900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^ --------- not a foreign function or static
@@ -816,7 +816,7 @@ LL |     #[link_name = "1900"] struct S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:507:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:508:5
    |
 LL |     #[link_name = "1900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^ ----------- not a foreign function or static
@@ -824,7 +824,7 @@ LL |     #[link_name = "1900"] type T = S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a foreign function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:512:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:513:5
    |
 LL |     #[link_name = "1900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static
@@ -832,7 +832,7 @@ LL |     #[link_name = "1900"] impl S { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:524:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:525:17
    |
 LL |     mod inner { #![link_section="1800"] }
    |     ------------^^^^^^^^^^^^^^^^^^^^^^^-- not a function or static
@@ -840,7 +840,7 @@ LL |     mod inner { #![link_section="1800"] }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:531:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:532:5
    |
 LL |     #[link_section = "1800"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ --------- not a function or static
@@ -848,7 +848,7 @@ LL |     #[link_section = "1800"] struct S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:536:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:537:5
    |
 LL |     #[link_section = "1800"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a function or static
@@ -856,7 +856,7 @@ LL |     #[link_section = "1800"] type T = S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to a function or static
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:541:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:542:5
    |
 LL |     #[link_section = "1800"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a function or static
@@ -864,7 +864,7 @@ LL |     #[link_section = "1800"] impl S { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:556:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:557:17
    |
 LL |     mod inner { #![link()] }
    |     ------------^^^^^^^^^^-- not an `extern` block
@@ -872,7 +872,7 @@ LL |     mod inner { #![link()] }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:561:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:562:5
    |
 LL |     #[link()] fn f() { }
    |     ^^^^^^^^^ ---------- not an `extern` block
@@ -880,7 +880,7 @@ LL |     #[link()] fn f() { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:566:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:567:5
    |
 LL |     #[link()] struct S;
    |     ^^^^^^^^^ --------- not an `extern` block
@@ -888,7 +888,7 @@ LL |     #[link()] struct S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:571:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:572:5
    |
 LL |     #[link()] type T = S;
    |     ^^^^^^^^^ ----------- not an `extern` block
@@ -896,7 +896,7 @@ LL |     #[link()] type T = S;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:576:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:577:5
    |
 LL |     #[link()] impl S { }
    |     ^^^^^^^^^ ---------- not an `extern` block
@@ -904,7 +904,7 @@ LL |     #[link()] impl S { }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: attribute should be applied to an `extern` block with non-Rust ABI
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:581:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:582:5
    |
 LL |     #[link()] extern "Rust" {}
    |     ^^^^^^^^^
@@ -912,259 +912,259 @@ LL |     #[link()] extern "Rust" {}
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
 
 warning: `#[must_use]` has no effect when applied to a module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:603:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:605:17
    |
 LL |     mod inner { #![must_use] }
    |                 ^^^^^^^^^^^^
 
 warning: `#[must_use]` has no effect when applied to a type alias
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:609:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:612:5
    |
 LL |     #[must_use] type T = S;
    |     ^^^^^^^^^^^
 
 warning: `#[must_use]` has no effect when applied to an inherent implementation block
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:611:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:615:5
    |
 LL |     #[must_use] impl S { }
    |     ^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:617:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:622:17
    |
 LL |     mod inner { #![windows_subsystem="windows"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:620:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:625:5
    |
 LL |     #[windows_subsystem = "windows"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:623:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:628:5
    |
 LL |     #[windows_subsystem = "windows"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:626:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:631:5
    |
 LL |     #[windows_subsystem = "windows"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:629:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:634:5
    |
 LL |     #[windows_subsystem = "windows"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:638:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:643:17
    |
 LL |     mod inner { #![crate_name="0900"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:641:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:646:5
    |
 LL |     #[crate_name = "0900"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:644:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:649:5
    |
 LL |     #[crate_name = "0900"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:647:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:652:5
    |
 LL |     #[crate_name = "0900"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:650:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:655:5
    |
 LL |     #[crate_name = "0900"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:657:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:662:17
    |
 LL |     mod inner { #![crate_type="0800"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:660:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:665:5
    |
 LL |     #[crate_type = "0800"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:663:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:668:5
    |
 LL |     #[crate_type = "0800"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:666:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:671:5
    |
 LL |     #[crate_type = "0800"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:669:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:674:5
    |
 LL |     #[crate_type = "0800"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:676:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:681:17
    |
 LL |     mod inner { #![feature(x0600)] }
    |                 ^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:679:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:684:5
    |
 LL |     #[feature(x0600)] fn f() { }
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:682:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:687:5
    |
 LL |     #[feature(x0600)] struct S;
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:690:5
    |
 LL |     #[feature(x0600)] type T = S;
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:688:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:693:5
    |
 LL |     #[feature(x0600)] impl S { }
    |     ^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:696:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:701:17
    |
 LL |     mod inner { #![no_main] }
    |                 ^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:699:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:5
    |
 LL |     #[no_main] fn f() { }
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:702:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:707:5
    |
 LL |     #[no_main] struct S;
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:705:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:5
    |
 LL |     #[no_main] type T = S;
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:713:5
    |
 LL |     #[no_main] impl S { }
    |     ^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:715:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:17
    |
 LL |     mod inner { #![no_builtins] }
    |                 ^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:718:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:723:5
    |
 LL |     #[no_builtins] fn f() { }
    |     ^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:721:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:726:5
    |
 LL |     #[no_builtins] struct S;
    |     ^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:5
    |
 LL |     #[no_builtins] type T = S;
    |     ^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:727:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:732:5
    |
 LL |     #[no_builtins] impl S { }
    |     ^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:734:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:739:17
    |
 LL |     mod inner { #![recursion_limit="0200"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:742:5
    |
 LL |     #[recursion_limit="0200"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:740:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:5
    |
 LL |     #[recursion_limit="0200"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:743:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:748:5
    |
 LL |     #[recursion_limit="0200"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:746:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:751:5
    |
 LL |     #[recursion_limit="0200"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be in the root module
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:753:17
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:17
    |
 LL |     mod inner { #![type_length_limit="0100"] }
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:756:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:761:5
    |
 LL |     #[type_length_limit="0100"] fn f() { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:759:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:764:5
    |
 LL |     #[type_length_limit="0100"] struct S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:767:5
    |
 LL |     #[type_length_limit="0100"] type T = S;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:765:5
+  --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:5
    |
 LL |     #[type_length_limit="0100"] impl S { }
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/fn/fn-arg-count-mismatch-diagnostics.rs b/tests/ui/fn/fn-arg-count-mismatch-diagnostics.rs
index b2f80ba1bf6..3b12ea1a736 100644
--- a/tests/ui/fn/fn-arg-count-mismatch-diagnostics.rs
+++ b/tests/ui/fn/fn-arg-count-mismatch-diagnostics.rs
@@ -46,9 +46,21 @@ impl Bar {
     }
 }
 
+fn function_with_lots_of_arguments(a: i32, b: char, c: i32, d: i32, e: i32, f: i32) {}
+
 fn main() {
     foo(1, 2, 3);
     //~^ ERROR function takes 4 arguments but 3
     bar(1, 2, 3);
     //~^ ERROR function takes 6 arguments but 3
+
+    let variable_name = 42;
+    function_with_lots_of_arguments(
+        variable_name,
+        variable_name,
+        variable_name,
+        variable_name,
+        variable_name,
+    );
+    //~^^^^^^^ ERROR this function takes 6 arguments but 5 arguments were supplied [E0061]
 }
diff --git a/tests/ui/fn/fn-arg-count-mismatch-diagnostics.stderr b/tests/ui/fn/fn-arg-count-mismatch-diagnostics.stderr
index 6af7671af03..dda9b398a83 100644
--- a/tests/ui/fn/fn-arg-count-mismatch-diagnostics.stderr
+++ b/tests/ui/fn/fn-arg-count-mismatch-diagnostics.stderr
@@ -52,7 +52,7 @@ LL |         <$from>::$method(8, /* u8 */)
    |                           ++++++++++
 
 error[E0061]: this function takes 4 arguments but 3 arguments were supplied
-  --> $DIR/fn-arg-count-mismatch-diagnostics.rs:50:5
+  --> $DIR/fn-arg-count-mismatch-diagnostics.rs:52:5
    |
 LL |     foo(1, 2, 3);
    |     ^^^--------- argument #4 of type `isize` is missing
@@ -68,7 +68,7 @@ LL |     foo(1, 2, 3, /* isize */);
    |                +++++++++++++
 
 error[E0061]: this function takes 6 arguments but 3 arguments were supplied
-  --> $DIR/fn-arg-count-mismatch-diagnostics.rs:52:5
+  --> $DIR/fn-arg-count-mismatch-diagnostics.rs:54:5
    |
 LL |     bar(1, 2, 3);
    |     ^^^--------- three arguments of type `i32`, `i32`, and `i32` are missing
@@ -83,6 +83,28 @@ help: provide the arguments
 LL |     bar(1, 2, 3, /* i32 */, /* i32 */, /* i32 */);
    |                +++++++++++++++++++++++++++++++++
 
-error: aborting due to 5 previous errors
+error[E0061]: this function takes 6 arguments but 5 arguments were supplied
+  --> $DIR/fn-arg-count-mismatch-diagnostics.rs:58:5
+   |
+LL |     function_with_lots_of_arguments(
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         variable_name,
+LL |         variable_name,
+   |         ------------- argument #2 of type `char` is missing
+   |
+note: function defined here
+  --> $DIR/fn-arg-count-mismatch-diagnostics.rs:49:4
+   |
+LL | fn function_with_lots_of_arguments(a: i32, b: char, c: i32, d: i32, e: i32, f: i32) {}
+   |    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^         -------
+help: provide the argument
+   |
+LL |     function_with_lots_of_arguments(
+LL |         variable_name,
+LL ~         /* char */,
+LL ~         variable_name,
+   |
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0061`.
diff --git a/tests/ui/infinite/issue-41731-infinite-macro-print.rs b/tests/ui/infinite/issue-41731-infinite-macro-print.rs
index 7cd3ff3d629..aa5555b117a 100644
--- a/tests/ui/infinite/issue-41731-infinite-macro-print.rs
+++ b/tests/ui/infinite/issue-41731-infinite-macro-print.rs
@@ -5,7 +5,7 @@
 fn main() {
     macro_rules! stack {
         ($overflow:expr) => {
-            print!(stack!($overflow));
+            print!(stack!($overflow))
             //~^ ERROR recursion limit reached while expanding
             //~| ERROR format argument must be a string literal
         };
diff --git a/tests/ui/infinite/issue-41731-infinite-macro-print.stderr b/tests/ui/infinite/issue-41731-infinite-macro-print.stderr
index 71510816d0b..84436de9aa3 100644
--- a/tests/ui/infinite/issue-41731-infinite-macro-print.stderr
+++ b/tests/ui/infinite/issue-41731-infinite-macro-print.stderr
@@ -14,11 +14,11 @@ LL |     stack!("overflow");
    |     ^^^^^^^^^^^^^^^^^^
    |
    = note: expanding `stack! { "overflow" }`
-   = note: to `print! (stack! ("overflow"));`
+   = note: to `print! (stack! ("overflow"))`
    = note: expanding `print! { stack! ("overflow") }`
    = note: to `{ $crate :: io :: _print($crate :: format_args! (stack! ("overflow"))); }`
    = note: expanding `stack! { "overflow" }`
-   = note: to `print! (stack! ("overflow"));`
+   = note: to `print! (stack! ("overflow"))`
    = note: expanding `print! { stack! ("overflow") }`
    = note: to `{ $crate :: io :: _print($crate :: format_args! (stack! ("overflow"))); }`
 
@@ -31,7 +31,7 @@ LL |     stack!("overflow");
    = note: this error originates in the macro `print` which comes from the expansion of the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: you might be missing a string literal to format with
    |
-LL |             print!("{}", stack!($overflow));
+LL |             print!("{}", stack!($overflow))
    |                    +++++
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/infinite/issue-41731-infinite-macro-println.rs b/tests/ui/infinite/issue-41731-infinite-macro-println.rs
index 491f18dc4c6..cf59afb0194 100644
--- a/tests/ui/infinite/issue-41731-infinite-macro-println.rs
+++ b/tests/ui/infinite/issue-41731-infinite-macro-println.rs
@@ -5,7 +5,7 @@
 fn main() {
     macro_rules! stack {
         ($overflow:expr) => {
-            println!(stack!($overflow));
+            println!(stack!($overflow))
             //~^ ERROR recursion limit reached while expanding
             //~| ERROR format argument must be a string literal
         };
diff --git a/tests/ui/infinite/issue-41731-infinite-macro-println.stderr b/tests/ui/infinite/issue-41731-infinite-macro-println.stderr
index 645176d45cb..6d0432abe4c 100644
--- a/tests/ui/infinite/issue-41731-infinite-macro-println.stderr
+++ b/tests/ui/infinite/issue-41731-infinite-macro-println.stderr
@@ -14,11 +14,11 @@ LL |     stack!("overflow");
    |     ^^^^^^^^^^^^^^^^^^
    |
    = note: expanding `stack! { "overflow" }`
-   = note: to `println! (stack! ("overflow"));`
+   = note: to `println! (stack! ("overflow"))`
    = note: expanding `println! { stack! ("overflow") }`
    = note: to `{ $crate :: io :: _print($crate :: format_args_nl! (stack! ("overflow"))); }`
    = note: expanding `stack! { "overflow" }`
-   = note: to `println! (stack! ("overflow"));`
+   = note: to `println! (stack! ("overflow"))`
    = note: expanding `println! { stack! ("overflow") }`
    = note: to `{ $crate :: io :: _print($crate :: format_args_nl! (stack! ("overflow"))); }`
 
@@ -31,7 +31,7 @@ LL |     stack!("overflow");
    = note: this error originates in the macro `println` which comes from the expansion of the macro `stack` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: you might be missing a string literal to format with
    |
-LL |             println!("{}", stack!($overflow));
+LL |             println!("{}", stack!($overflow))
    |                      +++++
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/intrinsics/bad-intrinsic-monomorphization.stderr b/tests/ui/intrinsics/bad-intrinsic-monomorphization.stderr
index f49d95e9cfc..51ef71c9e29 100644
--- a/tests/ui/intrinsics/bad-intrinsic-monomorphization.stderr
+++ b/tests/ui/intrinsics/bad-intrinsic-monomorphization.stderr
@@ -1,8 +1,8 @@
-error[E0511]: invalid monomorphization of `cttz` intrinsic: expected basic integer type, found `Foo`
-  --> $DIR/bad-intrinsic-monomorphization.rs:16:5
+error[E0511]: invalid monomorphization of `simd_add` intrinsic: expected SIMD input type, found non-SIMD `Foo`
+  --> $DIR/bad-intrinsic-monomorphization.rs:26:5
    |
-LL |     intrinsics::cttz(v)
-   |     ^^^^^^^^^^^^^^^^^^^
+LL |     intrinsics::simd::simd_add(a, b)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `fadd_fast` intrinsic: expected basic float type, found `Foo`
   --> $DIR/bad-intrinsic-monomorphization.rs:21:5
@@ -10,11 +10,11 @@ error[E0511]: invalid monomorphization of `fadd_fast` intrinsic: expected basic
 LL |     intrinsics::fadd_fast(a, b)
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_add` intrinsic: expected SIMD input type, found non-SIMD `Foo`
-  --> $DIR/bad-intrinsic-monomorphization.rs:26:5
+error[E0511]: invalid monomorphization of `cttz` intrinsic: expected basic integer type, found `Foo`
+  --> $DIR/bad-intrinsic-monomorphization.rs:16:5
    |
-LL |     intrinsics::simd::simd_add(a, b)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     intrinsics::cttz(v)
+   |     ^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/intrinsics/non-integer-atomic.stderr b/tests/ui/intrinsics/non-integer-atomic.stderr
index b96ee7ba846..330d313639d 100644
--- a/tests/ui/intrinsics/non-integer-atomic.stderr
+++ b/tests/ui/intrinsics/non-integer-atomic.stderr
@@ -1,59 +1,53 @@
-error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer or pointer type, found `bool`
-  --> $DIR/non-integer-atomic.rs:15:5
+error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer or pointer type, found `&dyn Fn()`
+  --> $DIR/non-integer-atomic.rs:55:5
    |
 LL |     intrinsics::atomic_load::<_, { SeqCst }>(p);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `bool`
-  --> $DIR/non-integer-atomic.rs:20:5
+error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer or pointer type, found `Foo`
+  --> $DIR/non-integer-atomic.rs:35:5
+   |
+LL |     intrinsics::atomic_load::<_, { SeqCst }>(p);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `&dyn Fn()`
+  --> $DIR/non-integer-atomic.rs:60:5
    |
 LL |     intrinsics::atomic_store::<_, { SeqCst }>(p, v);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `bool`
-  --> $DIR/non-integer-atomic.rs:25:5
+error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `[u8; 100]`
+  --> $DIR/non-integer-atomic.rs:85:5
    |
 LL |     intrinsics::atomic_xchg::<_, { SeqCst }>(p, v);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `bool`
-  --> $DIR/non-integer-atomic.rs:30:5
+error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `&dyn Fn()`
+  --> $DIR/non-integer-atomic.rs:70:5
    |
 LL |     intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer or pointer type, found `Foo`
-  --> $DIR/non-integer-atomic.rs:35:5
-   |
-LL |     intrinsics::atomic_load::<_, { SeqCst }>(p);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `Foo`
   --> $DIR/non-integer-atomic.rs:40:5
    |
 LL |     intrinsics::atomic_store::<_, { SeqCst }>(p, v);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `Foo`
-  --> $DIR/non-integer-atomic.rs:45:5
-   |
-LL |     intrinsics::atomic_xchg::<_, { SeqCst }>(p, v);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `Foo`
-  --> $DIR/non-integer-atomic.rs:50:5
+error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `[u8; 100]`
+  --> $DIR/non-integer-atomic.rs:90:5
    |
 LL |     intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer or pointer type, found `&dyn Fn()`
-  --> $DIR/non-integer-atomic.rs:55:5
+error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `[u8; 100]`
+  --> $DIR/non-integer-atomic.rs:80:5
    |
-LL |     intrinsics::atomic_load::<_, { SeqCst }>(p);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     intrinsics::atomic_store::<_, { SeqCst }>(p, v);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `&dyn Fn()`
-  --> $DIR/non-integer-atomic.rs:60:5
+error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `bool`
+  --> $DIR/non-integer-atomic.rs:20:5
    |
 LL |     intrinsics::atomic_store::<_, { SeqCst }>(p, v);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -64,36 +58,42 @@ error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basi
 LL |     intrinsics::atomic_xchg::<_, { SeqCst }>(p, v);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `&dyn Fn()`
-  --> $DIR/non-integer-atomic.rs:70:5
-   |
-LL |     intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer or pointer type, found `[u8; 100]`
   --> $DIR/non-integer-atomic.rs:75:5
    |
 LL |     intrinsics::atomic_load::<_, { SeqCst }>(p);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer or pointer type, found `[u8; 100]`
-  --> $DIR/non-integer-atomic.rs:80:5
+error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer or pointer type, found `bool`
+  --> $DIR/non-integer-atomic.rs:15:5
    |
-LL |     intrinsics::atomic_store::<_, { SeqCst }>(p, v);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     intrinsics::atomic_load::<_, { SeqCst }>(p);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `[u8; 100]`
-  --> $DIR/non-integer-atomic.rs:85:5
+error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `bool`
+  --> $DIR/non-integer-atomic.rs:30:5
    |
-LL |     intrinsics::atomic_xchg::<_, { SeqCst }>(p, v);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `[u8; 100]`
-  --> $DIR/non-integer-atomic.rs:90:5
+error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer or pointer type, found `Foo`
+  --> $DIR/non-integer-atomic.rs:50:5
    |
 LL |     intrinsics::atomic_cxchg::<_, { SeqCst }, { SeqCst }>(p, v, v);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `Foo`
+  --> $DIR/non-integer-atomic.rs:45:5
+   |
+LL |     intrinsics::atomic_xchg::<_, { SeqCst }>(p, v);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer or pointer type, found `bool`
+  --> $DIR/non-integer-atomic.rs:25:5
+   |
+LL |     intrinsics::atomic_xchg::<_, { SeqCst }>(p, v);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error: aborting due to 16 previous errors
 
 For more information about this error, try `rustc --explain E0511`.
diff --git a/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stderr b/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stderr
index 6bf09a2b131..b773f7c97aa 100644
--- a/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stderr
+++ b/tests/ui/invalid-compile-flags/print-crate-name-request-malformed-crate-name.stderr
@@ -3,6 +3,8 @@ error: malformed `crate_name` attribute input
    |
 LL | #![crate_name = concat!("wrapped")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_name = "name"]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/crates-and-source-files.html#the-crate_name-attribute>
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stderr b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stderr
index de62aed79fc..64e38ed8533 100644
--- a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stderr
+++ b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-1.stderr
@@ -3,6 +3,8 @@ error: malformed `crate_name` attribute input
    |
 LL | #![crate_name]
    | ^^^^^^^^^^^^^^ help: must be of the form: `#![crate_name = "name"]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/crates-and-source-files.html#the-crate_name-attribute>
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stderr b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stderr
index 42c33de1221..e9a5b58e4f9 100644
--- a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stderr
+++ b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name-2.stderr
@@ -3,6 +3,8 @@ error: malformed `crate_name` attribute input
    |
 LL | #![crate_name = concat!("this_one_is_not")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_name = "name"]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/crates-and-source-files.html#the-crate_name-attribute>
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stderr b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stderr
index cb5ffaab9ca..e63525c6a5d 100644
--- a/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stderr
+++ b/tests/ui/invalid-compile-flags/print-file-names-request-malformed-crate-name.stderr
@@ -3,6 +3,8 @@ error: malformed `crate_name` attribute input
    |
 LL | #![crate_name = concat!("wrapped")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_name = "name"]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/crates-and-source-files.html#the-crate_name-attribute>
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/invalid/invalid-inline.stderr b/tests/ui/invalid/invalid-inline.stderr
index 54e6b2b5408..78ffe3270a7 100644
--- a/tests/ui/invalid/invalid-inline.stderr
+++ b/tests/ui/invalid/invalid-inline.stderr
@@ -6,10 +6,14 @@ LL | #[inline(please,no)]
    |         |
    |         expected a single argument here
    |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute>
 help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[inline(please,no)]
-LL + #[inline(always|never)]
+LL + #[inline(always)]
+   |
+LL - #[inline(please,no)]
+LL + #[inline(never)]
    |
 LL - #[inline(please,no)]
 LL + #[inline]
@@ -23,10 +27,13 @@ LL | #[inline()]
    |         |
    |         expected a single argument here
    |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute>
 help: try changing it to one of the following valid forms of the attribute
    |
-LL | #[inline(always|never)]
-   |          ++++++++++++
+LL | #[inline(always)]
+   |          ++++++
+LL | #[inline(never)]
+   |          +++++
 LL - #[inline()]
 LL + #[inline]
    |
diff --git a/tests/ui/issues/issue-43988.stderr b/tests/ui/issues/issue-43988.stderr
index fe61e136a51..b50d691e685 100644
--- a/tests/ui/issues/issue-43988.stderr
+++ b/tests/ui/issues/issue-43988.stderr
@@ -6,10 +6,14 @@ LL |     #[inline(XYZ)]
    |              |
    |              valid arguments are `always` or `never`
    |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute>
 help: try changing it to one of the following valid forms of the attribute
    |
 LL -     #[inline(XYZ)]
-LL +     #[inline(always|never)]
+LL +     #[inline(always)]
+   |
+LL -     #[inline(XYZ)]
+LL +     #[inline(never)]
    |
 LL -     #[inline(XYZ)]
 LL +     #[inline]
@@ -22,6 +26,7 @@ LL |     #[repr(nothing)]
    |            ^^^^^^^
    |
    = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+   = note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html?highlight=repr#representations>
 
 error[E0552]: unrecognized representation hint
   --> $DIR/issue-43988.rs:18:12
@@ -30,15 +35,26 @@ LL |     #[repr(something_not_real)]
    |            ^^^^^^^^^^^^^^^^^^
    |
    = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+   = note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html?highlight=repr#representations>
 
 error[E0539]: malformed `repr` attribute input
   --> $DIR/issue-43988.rs:24:5
    |
 LL |     #[repr]
-   |     ^^^^^^^
-   |     |
-   |     expected this to be a list
-   |     help: must be of the form: `#[repr(C | Rust | align(...) | packed(...) | <integer type> | transparent)]`
+   |     ^^^^^^^ expected this to be a list
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html#representations>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL |     #[repr(<integer type>)]
+   |           ++++++++++++++++
+LL |     #[repr(C)]
+   |           +++
+LL |     #[repr(Rust)]
+   |           ++++++
+LL |     #[repr(align(...))]
+   |           ++++++++++++
+   = and 2 other candidates
 
 error[E0539]: malformed `inline` attribute input
   --> $DIR/issue-43988.rs:30:5
@@ -48,10 +64,14 @@ LL |     #[inline(ABC)]
    |              |
    |              valid arguments are `always` or `never`
    |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute>
 help: try changing it to one of the following valid forms of the attribute
    |
 LL -     #[inline(ABC)]
-LL +     #[inline(always|never)]
+LL +     #[inline(always)]
+   |
+LL -     #[inline(ABC)]
+LL +     #[inline(never)]
    |
 LL -     #[inline(ABC)]
 LL +     #[inline]
@@ -61,10 +81,20 @@ error[E0539]: malformed `repr` attribute input
   --> $DIR/issue-43988.rs:34:14
    |
 LL |     let _z = #[repr] 1;
-   |              ^^^^^^^
-   |              |
-   |              expected this to be a list
-   |              help: must be of the form: `#[repr(C | Rust | align(...) | packed(...) | <integer type> | transparent)]`
+   |              ^^^^^^^ expected this to be a list
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html#representations>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL |     let _z = #[repr(<integer type>)] 1;
+   |                    ++++++++++++++++
+LL |     let _z = #[repr(C)] 1;
+   |                    +++
+LL |     let _z = #[repr(Rust)] 1;
+   |                    ++++++
+LL |     let _z = #[repr(align(...))] 1;
+   |                    ++++++++++++
+   = and 2 other candidates
 
 error[E0518]: attribute should be applied to function or closure
   --> $DIR/issue-43988.rs:5:5
diff --git a/tests/ui/link-native-libs/link-attr-validation-early.rs b/tests/ui/link-native-libs/link-attr-validation-early.rs
index b9a835fb5e9..a7dd80f8920 100644
--- a/tests/ui/link-native-libs/link-attr-validation-early.rs
+++ b/tests/ui/link-native-libs/link-attr-validation-early.rs
@@ -1,7 +1,7 @@
 // Top-level ill-formed
-#[link] //~ ERROR attribute must be of the form
+#[link] //~ ERROR valid forms for the attribute are
         //~| WARN this was previously accepted
-#[link = "foo"] //~ ERROR attribute must be of the form
+#[link = "foo"] //~ ERROR valid forms for the attribute are
                 //~| WARN this was previously accepted
 extern "C" {}
 
diff --git a/tests/ui/link-native-libs/link-attr-validation-early.stderr b/tests/ui/link-native-libs/link-attr-validation-early.stderr
index c69899275d5..36cca6f27ef 100644
--- a/tests/ui/link-native-libs/link-attr-validation-early.stderr
+++ b/tests/ui/link-native-libs/link-attr-validation-early.stderr
@@ -1,4 +1,4 @@
-error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
+error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]`
   --> $DIR/link-attr-validation-early.rs:2:1
    |
 LL | #[link]
@@ -6,9 +6,10 @@ LL | #[link]
    |
    = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
    = note: `#[deny(ill_formed_attribute_input)]` on by default
 
-error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
+error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]`
   --> $DIR/link-attr-validation-early.rs:4:1
    |
 LL | #[link = "foo"]
@@ -16,11 +17,12 @@ LL | #[link = "foo"]
    |
    = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
 
 error: aborting due to 2 previous errors
 
 Future incompatibility report: Future breakage diagnostic:
-error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
+error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]`
   --> $DIR/link-attr-validation-early.rs:2:1
    |
 LL | #[link]
@@ -28,10 +30,11 @@ LL | #[link]
    |
    = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
    = note: `#[deny(ill_formed_attribute_input)]` on by default
 
 Future breakage diagnostic:
-error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
+error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]`
   --> $DIR/link-attr-validation-early.rs:4:1
    |
 LL | #[link = "foo"]
@@ -39,5 +42,6 @@ LL | #[link = "foo"]
    |
    = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
    = note: `#[deny(ill_formed_attribute_input)]` on by default
 
diff --git a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-invalid-format.stderr b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-invalid-format.stderr
index ffae30aabcc..6bf1eab311a 100644
--- a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-invalid-format.stderr
+++ b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-invalid-format.stderr
@@ -6,6 +6,8 @@ LL |     #[link_ordinal("JustMonika")]
    |     |              |
    |     |              expected an integer literal here
    |     help: must be of the form: `#[link_ordinal(ordinal)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute>
 
 error[E0539]: malformed `link_ordinal` attribute input
   --> $DIR/link-ordinal-invalid-format.rs:6:5
@@ -15,6 +17,8 @@ LL |     #[link_ordinal("JustMonika")]
    |     |              |
    |     |              expected an integer literal here
    |     help: must be of the form: `#[link_ordinal(ordinal)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute>
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.rs b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.rs
index 2a8b9ebacf7..58f19085540 100644
--- a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.rs
+++ b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.rs
@@ -3,10 +3,12 @@ extern "C" {
     #[link_ordinal()]
     //~^ ERROR malformed `link_ordinal` attribute input
     //~| NOTE  expected a single argument
+    //~| NOTE for more information, visit
     fn foo();
     #[link_ordinal()]
     //~^ ERROR malformed `link_ordinal` attribute input
     //~| NOTE  expected a single argument
+    //~| NOTE for more information, visit
     static mut imported_variable: i32;
 }
 
diff --git a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.stderr b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.stderr
index c6b8a18d03a..d575b0961af 100644
--- a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.stderr
+++ b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-missing-argument.stderr
@@ -6,15 +6,19 @@ LL |     #[link_ordinal()]
    |     |             |
    |     |             expected a single argument here
    |     help: must be of the form: `#[link_ordinal(ordinal)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute>
 
 error[E0805]: malformed `link_ordinal` attribute input
-  --> $DIR/link-ordinal-missing-argument.rs:7:5
+  --> $DIR/link-ordinal-missing-argument.rs:8:5
    |
 LL |     #[link_ordinal()]
    |     ^^^^^^^^^^^^^^--^
    |     |             |
    |     |             expected a single argument here
    |     help: must be of the form: `#[link_ordinal(ordinal)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute>
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-too-many-arguments.rs b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-too-many-arguments.rs
index ddf9583352f..55b18ae0d96 100644
--- a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-too-many-arguments.rs
+++ b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-too-many-arguments.rs
@@ -3,10 +3,12 @@ extern "C" {
     #[link_ordinal(3, 4)]
     //~^ ERROR malformed `link_ordinal` attribute input
     //~| NOTE  expected a single argument
+    //~| NOTE for more information, visit
     fn foo();
     #[link_ordinal(3, 4)]
     //~^ ERROR malformed `link_ordinal` attribute input
     //~| NOTE  expected a single argument
+    //~| NOTE for more information, visit
     static mut imported_variable: i32;
 }
 
diff --git a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-too-many-arguments.stderr b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-too-many-arguments.stderr
index 7d63304f598..a84fef9f9e4 100644
--- a/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-too-many-arguments.stderr
+++ b/tests/ui/linkage-attr/raw-dylib/windows/link-ordinal-too-many-arguments.stderr
@@ -6,15 +6,19 @@ LL |     #[link_ordinal(3, 4)]
    |     |             |
    |     |             expected a single argument here
    |     help: must be of the form: `#[link_ordinal(ordinal)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute>
 
 error[E0805]: malformed `link_ordinal` attribute input
-  --> $DIR/link-ordinal-too-many-arguments.rs:7:5
+  --> $DIR/link-ordinal-too-many-arguments.rs:8:5
    |
 LL |     #[link_ordinal(3, 4)]
    |     ^^^^^^^^^^^^^^------^
    |     |             |
    |     |             expected a single argument here
    |     help: must be of the form: `#[link_ordinal(ordinal)]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute>
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/lint/dead-code/self-assign.rs b/tests/ui/lint/dead-code/self-assign.rs
index 357846baf22..ce91f53cbf1 100644
--- a/tests/ui/lint/dead-code/self-assign.rs
+++ b/tests/ui/lint/dead-code/self-assign.rs
@@ -7,23 +7,20 @@
 //! - `dead_code` lint expansion for self-assignments was implemented in #87129.
 //! - Unfortunately implementation components of #87129 had to be disabled as part of reverts
 //!   #86212, #83171 (to revert #81473) to address regressions #81626 and #81658.
-//! - Consequently, none of the following warnings are emitted.
+//! - Re-enabled in current version to properly detect self-assignments.
 
 //@ check-pass
 
-// Implementation of self-assignment `dead_code` lint expansions disabled due to reverts.
-//@ known-bug: #75356
-
 #![allow(unused_assignments)]
 #![warn(dead_code)]
 
 fn main() {
     let mut x = 0;
     x = x;
-    // FIXME ~^ WARNING: useless assignment of variable of type `i32` to itself
+    //~^ WARNING: useless assignment of variable of type `i32` to itself
 
     x = (x);
-    // FIXME ~^ WARNING: useless assignment of variable of type `i32` to itself
+    //~^ WARNING: useless assignment of variable of type `i32` to itself
 
     x = {x};
     // block expressions don't count as self-assignments
@@ -32,10 +29,10 @@ fn main() {
     struct S<'a> { f: &'a str }
     let mut s = S { f: "abc" };
     s = s;
-    // FIXME ~^ WARNING: useless assignment of variable of type `S` to itself
+    //~^ WARNING: useless assignment of variable of type `S<'_>` to itself
 
     s.f = s.f;
-    // FIXME ~^ WARNING: useless assignment of field of type `&str` to itself
+    //~^ WARNING: useless assignment of field of type `&str` to itself
 
 
     struct N0 { x: Box<i32> }
@@ -44,11 +41,11 @@ fn main() {
     struct N3 { n: N2 };
     let mut n3 = N3 { n: N2(N1 { n: N0 { x: Box::new(42) } }) };
     n3.n.0.n.x = n3.n.0.n.x;
-    // FIXME ~^ WARNING: useless assignment of field of type `Box<i32>` to itself
+    //~^ WARNING: useless assignment of field of type `Box<i32>` to itself
 
     let mut t = (1, ((2, 3, (4, 5)),));
     t.1.0.2.1 = t.1.0.2.1;
-    // FIXME ~^ WARNING: useless assignment of field of type `i32` to itself
+    //~^ WARNING: useless assignment of field of type `i32` to itself
 
 
     let mut y = 0;
diff --git a/tests/ui/lint/dead-code/self-assign.stderr b/tests/ui/lint/dead-code/self-assign.stderr
new file mode 100644
index 00000000000..408ebdb658b
--- /dev/null
+++ b/tests/ui/lint/dead-code/self-assign.stderr
@@ -0,0 +1,44 @@
+warning: useless assignment of variable of type `i32` to itself
+  --> $DIR/self-assign.rs:19:5
+   |
+LL |     x = x;
+   |     ^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/self-assign.rs:15:9
+   |
+LL | #![warn(dead_code)]
+   |         ^^^^^^^^^
+
+warning: useless assignment of variable of type `i32` to itself
+  --> $DIR/self-assign.rs:22:5
+   |
+LL |     x = (x);
+   |     ^^^^^^^
+
+warning: useless assignment of variable of type `S<'_>` to itself
+  --> $DIR/self-assign.rs:31:5
+   |
+LL |     s = s;
+   |     ^^^^^
+
+warning: useless assignment of field of type `&str` to itself
+  --> $DIR/self-assign.rs:34:5
+   |
+LL |     s.f = s.f;
+   |     ^^^^^^^^^
+
+warning: useless assignment of field of type `Box<i32>` to itself
+  --> $DIR/self-assign.rs:43:5
+   |
+LL |     n3.n.0.n.x = n3.n.0.n.x;
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: useless assignment of field of type `i32` to itself
+  --> $DIR/self-assign.rs:47:5
+   |
+LL |     t.1.0.2.1 = t.1.0.2.1;
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+warning: 6 warnings emitted
+
diff --git a/tests/ui/lint/lint-malformed.stderr b/tests/ui/lint/lint-malformed.stderr
index 0bdcc293b65..25a4298bd75 100644
--- a/tests/ui/lint/lint-malformed.stderr
+++ b/tests/ui/lint/lint-malformed.stderr
@@ -16,7 +16,20 @@ error: malformed `deny` attribute input
   --> $DIR/lint-malformed.rs:1:1
    |
 LL | #![deny = "foo"]
-   | ^^^^^^^^^^^^^^^^ help: must be of the form: `#![deny(lint1, lint2, ..., /*opt*/ reason = "...")]`
+   | ^^^^^^^^^^^^^^^^
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes>
+help: the following are the possible correct uses
+   |
+LL - #![deny = "foo"]
+LL + #![deny(lint1)]
+   |
+LL - #![deny = "foo"]
+LL + #![deny(lint1, lint2, ...)]
+   |
+LL - #![deny = "foo"]
+LL + #![deny(lint1, lint2, lint3, reason = "...")]
+   |
 
 error[E0452]: malformed lint attribute input
   --> $DIR/lint-malformed.rs:2:10
diff --git a/tests/ui/lint/unused/unused_attributes-must_use.fixed b/tests/ui/lint/unused/unused_attributes-must_use.fixed
new file mode 100644
index 00000000000..80d488296ea
--- /dev/null
+++ b/tests/ui/lint/unused/unused_attributes-must_use.fixed
@@ -0,0 +1,139 @@
+//@ run-rustfix
+
+#![allow(dead_code, path_statements)]
+#![deny(unused_attributes, unused_must_use)]
+#![feature(asm_experimental_arch, stmt_expr_attributes, trait_alias)]
+
+ //~ ERROR `#[must_use]` has no effect
+extern crate std as std2;
+
+ //~ ERROR `#[must_use]` has no effect
+mod test_mod {}
+
+ //~ ERROR `#[must_use]` has no effect
+use std::arch::global_asm;
+
+ //~ ERROR `#[must_use]` has no effect
+const CONST: usize = 4;
+ //~ ERROR `#[must_use]` has no effect
+#[no_mangle]
+static STATIC: usize = 4;
+
+#[must_use]
+struct X;
+
+#[must_use]
+enum Y {
+    Z,
+}
+
+#[must_use]
+union U {
+    unit: (),
+}
+
+ //~ ERROR `#[must_use]` has no effect
+impl U {
+    #[must_use]
+    fn method() -> i32 {
+        4
+    }
+}
+
+#[must_use]
+#[no_mangle]
+fn foo() -> i64 {
+    4
+}
+
+ //~ ERROR `#[must_use]` has no effect
+extern "Rust" {
+    #[link_name = "STATIC"]
+     //~ ERROR `#[must_use]` has no effect
+    static FOREIGN_STATIC: usize;
+
+    #[link_name = "foo"]
+    #[must_use]
+    fn foreign_foo() -> i64;
+}
+
+ //~ ERROR unused attribute
+global_asm!("");
+
+ //~ ERROR `#[must_use]` has no effect
+type UseMe = ();
+
+fn qux< T>(_: T) {} //~ ERROR `#[must_use]` has no effect
+
+#[must_use]
+trait Use {
+     //~ ERROR `#[must_use]` has no effect
+    const ASSOC_CONST: usize = 4;
+     //~ ERROR `#[must_use]` has no effect
+    type AssocTy;
+
+    #[must_use]
+    fn get_four(&self) -> usize {
+        4
+    }
+}
+
+ //~ ERROR `#[must_use]` has no effect
+impl Use for () {
+    type AssocTy = ();
+
+     //~ ERROR `#[must_use]` has no effect
+    fn get_four(&self) -> usize {
+        4
+    }
+}
+
+ //~ ERROR `#[must_use]` has no effect
+trait Alias = Use;
+
+ //~ ERROR `#[must_use]` has no effect
+macro_rules! cool_macro {
+    () => {
+        4
+    };
+}
+
+fn main() {
+     //~ ERROR `#[must_use]` has no effect
+    let x = || {};
+    x();
+
+    let x =  //~ ERROR `#[must_use]` has no effect
+    || {};
+    x();
+
+    let _ = X; //~ ERROR that must be used
+    let _ = Y::Z; //~ ERROR that must be used
+    let _ = U { unit: () }; //~ ERROR that must be used
+    let _ = U::method(); //~ ERROR that must be used
+    let _ = foo(); //~ ERROR that must be used
+
+    unsafe {
+        let _ = foreign_foo(); //~ ERROR that must be used
+    };
+
+    CONST;
+    STATIC;
+    unsafe { FOREIGN_STATIC };
+    cool_macro!();
+    qux(4);
+    let _ = ().get_four(); //~ ERROR that must be used
+
+    match Some(4) {
+         //~ ERROR `#[must_use]` has no effect
+        Some(res) => res,
+        None => 0,
+    };
+
+    struct PatternField {
+        foo: i32,
+    }
+    let s = PatternField {   foo: 123 }; //~ ERROR `#[must_use]` has no effect
+    let PatternField {  foo } = s; //~ ERROR `#[must_use]` has no effect
+    let _ = foo;
+}
diff --git a/tests/ui/lint/unused/unused_attributes-must_use.rs b/tests/ui/lint/unused/unused_attributes-must_use.rs
index 860fc5046d1..edefe8ed65e 100644
--- a/tests/ui/lint/unused/unused_attributes-must_use.rs
+++ b/tests/ui/lint/unused/unused_attributes-must_use.rs
@@ -1,3 +1,5 @@
+//@ run-rustfix
+
 #![allow(dead_code, path_statements)]
 #![deny(unused_attributes, unused_must_use)]
 #![feature(asm_experimental_arch, stmt_expr_attributes, trait_alias)]
@@ -133,4 +135,5 @@ fn main() {
     }
     let s = PatternField { #[must_use]  foo: 123 }; //~ ERROR `#[must_use]` has no effect
     let PatternField { #[must_use] foo } = s; //~ ERROR `#[must_use]` has no effect
+    let _ = foo;
 }
diff --git a/tests/ui/lint/unused/unused_attributes-must_use.stderr b/tests/ui/lint/unused/unused_attributes-must_use.stderr
index 862ffa42d80..27927cf37e9 100644
--- a/tests/ui/lint/unused/unused_attributes-must_use.stderr
+++ b/tests/ui/lint/unused/unused_attributes-must_use.stderr
@@ -1,154 +1,154 @@
 error: unused attribute `must_use`
-  --> $DIR/unused_attributes-must_use.rs:58:1
+  --> $DIR/unused_attributes-must_use.rs:60:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
    |
 note: the built-in attribute `must_use` will be ignored, since it's applied to the macro invocation `global_asm`
-  --> $DIR/unused_attributes-must_use.rs:59:1
+  --> $DIR/unused_attributes-must_use.rs:61:1
    |
 LL | global_asm!("");
    | ^^^^^^^^^^
 note: the lint level is defined here
-  --> $DIR/unused_attributes-must_use.rs:2:9
+  --> $DIR/unused_attributes-must_use.rs:4:9
    |
 LL | #![deny(unused_attributes, unused_must_use)]
    |         ^^^^^^^^^^^^^^^^^
 
 error: `#[must_use]` has no effect when applied to an extern crate
-  --> $DIR/unused_attributes-must_use.rs:5:1
+  --> $DIR/unused_attributes-must_use.rs:7:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
 
 error: `#[must_use]` has no effect when applied to a module
-  --> $DIR/unused_attributes-must_use.rs:8:1
+  --> $DIR/unused_attributes-must_use.rs:10:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
 
 error: `#[must_use]` has no effect when applied to a use
-  --> $DIR/unused_attributes-must_use.rs:11:1
+  --> $DIR/unused_attributes-must_use.rs:13:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
 
 error: `#[must_use]` has no effect when applied to a constant item
-  --> $DIR/unused_attributes-must_use.rs:14:1
+  --> $DIR/unused_attributes-must_use.rs:16:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
 
 error: `#[must_use]` has no effect when applied to a static item
-  --> $DIR/unused_attributes-must_use.rs:16:1
+  --> $DIR/unused_attributes-must_use.rs:18:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
 
 error: `#[must_use]` has no effect when applied to an inherent implementation block
-  --> $DIR/unused_attributes-must_use.rs:33:1
+  --> $DIR/unused_attributes-must_use.rs:35:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
 
 error: `#[must_use]` has no effect when applied to a foreign module
-  --> $DIR/unused_attributes-must_use.rs:47:1
+  --> $DIR/unused_attributes-must_use.rs:49:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
 
 error: `#[must_use]` has no effect when applied to a type alias
-  --> $DIR/unused_attributes-must_use.rs:61:1
+  --> $DIR/unused_attributes-must_use.rs:63:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
 
 error: `#[must_use]` has no effect when applied to a type parameter
-  --> $DIR/unused_attributes-must_use.rs:64:8
+  --> $DIR/unused_attributes-must_use.rs:66:8
    |
 LL | fn qux<#[must_use] T>(_: T) {}
    |        ^^^^^^^^^^^
 
 error: `#[must_use]` has no effect when applied to an trait implementation block
-  --> $DIR/unused_attributes-must_use.rs:79:1
+  --> $DIR/unused_attributes-must_use.rs:81:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
 
 error: `#[must_use]` has no effect when applied to a trait alias
-  --> $DIR/unused_attributes-must_use.rs:89:1
+  --> $DIR/unused_attributes-must_use.rs:91:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
 
 error: `#[must_use]` has no effect when applied to a macro def
-  --> $DIR/unused_attributes-must_use.rs:92:1
+  --> $DIR/unused_attributes-must_use.rs:94:1
    |
 LL | #[must_use]
    | ^^^^^^^^^^^
 
 error: `#[must_use]` has no effect when applied to a statement
-  --> $DIR/unused_attributes-must_use.rs:100:5
+  --> $DIR/unused_attributes-must_use.rs:102:5
    |
 LL |     #[must_use]
    |     ^^^^^^^^^^^
 
 error: `#[must_use]` has no effect when applied to a closure
-  --> $DIR/unused_attributes-must_use.rs:104:13
+  --> $DIR/unused_attributes-must_use.rs:106:13
    |
 LL |     let x = #[must_use]
    |             ^^^^^^^^^^^
 
 error: `#[must_use]` has no effect when applied to an match arm
-  --> $DIR/unused_attributes-must_use.rs:126:9
+  --> $DIR/unused_attributes-must_use.rs:128:9
    |
 LL |         #[must_use]
    |         ^^^^^^^^^^^
 
 error: `#[must_use]` has no effect when applied to a struct field
-  --> $DIR/unused_attributes-must_use.rs:134:28
+  --> $DIR/unused_attributes-must_use.rs:136:28
    |
 LL |     let s = PatternField { #[must_use]  foo: 123 };
    |                            ^^^^^^^^^^^
 
 error: `#[must_use]` has no effect when applied to a pattern field
-  --> $DIR/unused_attributes-must_use.rs:135:24
+  --> $DIR/unused_attributes-must_use.rs:137:24
    |
 LL |     let PatternField { #[must_use] foo } = s;
    |                        ^^^^^^^^^^^
 
 error: `#[must_use]` has no effect when applied to an associated const
-  --> $DIR/unused_attributes-must_use.rs:68:5
+  --> $DIR/unused_attributes-must_use.rs:70:5
    |
 LL |     #[must_use]
    |     ^^^^^^^^^^^
 
 error: `#[must_use]` has no effect when applied to an associated type
-  --> $DIR/unused_attributes-must_use.rs:70:5
+  --> $DIR/unused_attributes-must_use.rs:72:5
    |
 LL |     #[must_use]
    |     ^^^^^^^^^^^
 
 error: `#[must_use]` has no effect when applied to a provided trait method
-  --> $DIR/unused_attributes-must_use.rs:83:5
+  --> $DIR/unused_attributes-must_use.rs:85:5
    |
 LL |     #[must_use]
    |     ^^^^^^^^^^^
 
 error: `#[must_use]` has no effect when applied to a foreign static item
-  --> $DIR/unused_attributes-must_use.rs:50:5
+  --> $DIR/unused_attributes-must_use.rs:52:5
    |
 LL |     #[must_use]
    |     ^^^^^^^^^^^
 
 error: unused `X` that must be used
-  --> $DIR/unused_attributes-must_use.rs:108:5
+  --> $DIR/unused_attributes-must_use.rs:110:5
    |
 LL |     X;
    |     ^
    |
 note: the lint level is defined here
-  --> $DIR/unused_attributes-must_use.rs:2:28
+  --> $DIR/unused_attributes-must_use.rs:4:28
    |
 LL | #![deny(unused_attributes, unused_must_use)]
    |                            ^^^^^^^^^^^^^^^
@@ -158,7 +158,7 @@ LL |     let _ = X;
    |     +++++++
 
 error: unused `Y` that must be used
-  --> $DIR/unused_attributes-must_use.rs:109:5
+  --> $DIR/unused_attributes-must_use.rs:111:5
    |
 LL |     Y::Z;
    |     ^^^^
@@ -169,7 +169,7 @@ LL |     let _ = Y::Z;
    |     +++++++
 
 error: unused `U` that must be used
-  --> $DIR/unused_attributes-must_use.rs:110:5
+  --> $DIR/unused_attributes-must_use.rs:112:5
    |
 LL |     U { unit: () };
    |     ^^^^^^^^^^^^^^
@@ -180,7 +180,7 @@ LL |     let _ = U { unit: () };
    |     +++++++
 
 error: unused return value of `U::method` that must be used
-  --> $DIR/unused_attributes-must_use.rs:111:5
+  --> $DIR/unused_attributes-must_use.rs:113:5
    |
 LL |     U::method();
    |     ^^^^^^^^^^^
@@ -191,7 +191,7 @@ LL |     let _ = U::method();
    |     +++++++
 
 error: unused return value of `foo` that must be used
-  --> $DIR/unused_attributes-must_use.rs:112:5
+  --> $DIR/unused_attributes-must_use.rs:114:5
    |
 LL |     foo();
    |     ^^^^^
@@ -202,7 +202,7 @@ LL |     let _ = foo();
    |     +++++++
 
 error: unused return value of `foreign_foo` that must be used
-  --> $DIR/unused_attributes-must_use.rs:115:9
+  --> $DIR/unused_attributes-must_use.rs:117:9
    |
 LL |         foreign_foo();
    |         ^^^^^^^^^^^^^
@@ -213,7 +213,7 @@ LL |         let _ = foreign_foo();
    |         +++++++
 
 error: unused return value of `Use::get_four` that must be used
-  --> $DIR/unused_attributes-must_use.rs:123:5
+  --> $DIR/unused_attributes-must_use.rs:125:5
    |
 LL |     ().get_four();
    |     ^^^^^^^^^^^^^
diff --git a/tests/ui/macros/macro-rules-attr-error.rs b/tests/ui/macros/macro-rules-attr-error.rs
index 1c8bb251e20..81eadb6692f 100644
--- a/tests/ui/macros/macro-rules-attr-error.rs
+++ b/tests/ui/macros/macro-rules-attr-error.rs
@@ -7,9 +7,46 @@ macro_rules! local_attr {
     //~^^ ERROR: local_attr
 }
 
+//~v NOTE: `fn_only` exists, but has no `attr` rules
+macro_rules! fn_only {
+    {} => {}
+}
+
+//~v NOTE: `attr_only` exists, but has no rules for function-like invocation
+macro_rules! attr_only {
+    attr() {} => {}
+}
+
 fn main() {
+    //~v NOTE: in this expansion of #[local_attr]
     #[local_attr]
     struct S;
 
-    local_attr!(arg); //~ ERROR: macro has no rules for function-like invocation
+    //~vv ERROR: cannot find macro `local_attr` in this scope
+    //~| NOTE: `local_attr` is in scope, but it is an attribute
+    local_attr!(arg);
+
+    //~v ERROR: cannot find attribute `fn_only` in this scope
+    #[fn_only]
+    struct S;
+
+    attr_only!(); //~ ERROR: cannot find macro `attr_only` in this scope
+}
+
+//~vv ERROR: cannot find attribute `forward_referenced_attr` in this scope
+//~| NOTE: consider moving the definition of `forward_referenced_attr` before this call
+#[forward_referenced_attr]
+struct S;
+
+//~v NOTE: a macro with the same name exists, but it appears later
+macro_rules! forward_referenced_attr {
+    attr() {} => {}
+}
+
+//~vv ERROR: cannot find attribute `cyclic_attr` in this scope
+//~| NOTE: consider moving the definition of `cyclic_attr` before this call
+#[cyclic_attr]
+//~v NOTE: a macro with the same name exists, but it appears later
+macro_rules! cyclic_attr {
+    attr() {} => {}
 }
diff --git a/tests/ui/macros/macro-rules-attr-error.stderr b/tests/ui/macros/macro-rules-attr-error.stderr
index 177b7009384..674d35091b6 100644
--- a/tests/ui/macros/macro-rules-attr-error.stderr
+++ b/tests/ui/macros/macro-rules-attr-error.stderr
@@ -9,14 +9,55 @@ LL |     #[local_attr]
    |
    = note: this error originates in the attribute macro `local_attr` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: macro has no rules for function-like invocation `local_attr!`
-  --> $DIR/macro-rules-attr-error.rs:14:5
+error: cannot find macro `local_attr` in this scope
+  --> $DIR/macro-rules-attr-error.rs:27:5
    |
-LL | macro_rules! local_attr {
-   | ----------------------- this macro has no rules for function-like invocation
-...
 LL |     local_attr!(arg);
-   |     ^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^
+   |
+   = note: `local_attr` is in scope, but it is an attribute: `#[local_attr]`
+
+error: cannot find attribute `fn_only` in this scope
+  --> $DIR/macro-rules-attr-error.rs:30:7
+   |
+LL | macro_rules! fn_only {
+   |              ------- `fn_only` exists, but has no `attr` rules
+...
+LL |     #[fn_only]
+   |       ^^^^^^^
+
+error: cannot find macro `attr_only` in this scope
+  --> $DIR/macro-rules-attr-error.rs:33:5
+   |
+LL | macro_rules! attr_only {
+   |              --------- `attr_only` exists, but has no rules for function-like invocation
+...
+LL |     attr_only!();
+   |     ^^^^^^^^^
+
+error: cannot find attribute `forward_referenced_attr` in this scope
+  --> $DIR/macro-rules-attr-error.rs:38:3
+   |
+LL | #[forward_referenced_attr]
+   |   ^^^^^^^^^^^^^^^^^^^^^^^ consider moving the definition of `forward_referenced_attr` before this call
+   |
+note: a macro with the same name exists, but it appears later
+  --> $DIR/macro-rules-attr-error.rs:42:14
+   |
+LL | macro_rules! forward_referenced_attr {
+   |              ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: cannot find attribute `cyclic_attr` in this scope
+  --> $DIR/macro-rules-attr-error.rs:48:3
+   |
+LL | #[cyclic_attr]
+   |   ^^^^^^^^^^^ consider moving the definition of `cyclic_attr` before this call
+   |
+note: a macro with the same name exists, but it appears later
+  --> $DIR/macro-rules-attr-error.rs:50:14
+   |
+LL | macro_rules! cyclic_attr {
+   |              ^^^^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to 6 previous errors
 
diff --git a/tests/ui/macros/macro-use-bad-args-1.stderr b/tests/ui/macros/macro-use-bad-args-1.stderr
index 2f43d0997df..542b4ae2b7a 100644
--- a/tests/ui/macros/macro-use-bad-args-1.stderr
+++ b/tests/ui/macros/macro-use-bad-args-1.stderr
@@ -6,6 +6,7 @@ LL | #[macro_use(foo(bar))]
    |                |
    |                didn't expect any arguments here
    |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute>
 help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[macro_use(foo(bar))]
diff --git a/tests/ui/macros/macro-use-bad-args-2.stderr b/tests/ui/macros/macro-use-bad-args-2.stderr
index d7b03c93588..2db9ffe50b0 100644
--- a/tests/ui/macros/macro-use-bad-args-2.stderr
+++ b/tests/ui/macros/macro-use-bad-args-2.stderr
@@ -6,6 +6,7 @@ LL | #[macro_use(foo="bar")]
    |                |
    |                didn't expect any arguments here
    |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute>
 help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[macro_use(foo="bar")]
diff --git a/tests/ui/malformed/malformed-regressions.rs b/tests/ui/malformed/malformed-regressions.rs
index f0a7aac59c1..99f0fc904a9 100644
--- a/tests/ui/malformed/malformed-regressions.rs
+++ b/tests/ui/malformed/malformed-regressions.rs
@@ -4,9 +4,9 @@
 //~^ WARN this was previously accepted
 #[inline = ""] //~ ERROR valid forms for the attribute are
 //~^ WARN this was previously accepted
-#[link] //~ ERROR attribute must be of the form
+#[link] //~ ERROR valid forms for the attribute are
 //~^ WARN this was previously accepted
-#[link = ""] //~ ERROR attribute must be of the form
+#[link = ""] //~ ERROR valid forms for the attribute are
 //~^ WARN this was previously accepted
 
 fn main() {}
diff --git a/tests/ui/malformed/malformed-regressions.stderr b/tests/ui/malformed/malformed-regressions.stderr
index 60ea5da761d..4a00c9b4a7d 100644
--- a/tests/ui/malformed/malformed-regressions.stderr
+++ b/tests/ui/malformed/malformed-regressions.stderr
@@ -1,4 +1,4 @@
-error: valid forms for the attribute are `#[doc(hidden|inline|...)]` and `#[doc = "string"]`
+error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]`
   --> $DIR/malformed-regressions.rs:1:1
    |
 LL | #[doc]
@@ -6,9 +6,10 @@ LL | #[doc]
    |
    = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: for more information, visit <https://doc.rust-lang.org/rustdoc/write-documentation/the-doc-attribute.html>
    = note: `#[deny(ill_formed_attribute_input)]` on by default
 
-error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
+error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]`
   --> $DIR/malformed-regressions.rs:7:1
    |
 LL | #[link]
@@ -16,8 +17,9 @@ LL | #[link]
    |
    = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
 
-error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
+error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]`
   --> $DIR/malformed-regressions.rs:9:1
    |
 LL | #[link = ""]
@@ -25,6 +27,7 @@ LL | #[link = ""]
    |
    = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
 
 error: valid forms for the attribute are `#[ignore = "reason"]` and `#[ignore]`
   --> $DIR/malformed-regressions.rs:3:1
@@ -35,7 +38,7 @@ LL | #[ignore()]
    = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
 
-error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]`
+error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
   --> $DIR/malformed-regressions.rs:5:1
    |
 LL | #[inline = ""]
@@ -47,7 +50,7 @@ LL | #[inline = ""]
 error: aborting due to 5 previous errors
 
 Future incompatibility report: Future breakage diagnostic:
-error: valid forms for the attribute are `#[doc(hidden|inline|...)]` and `#[doc = "string"]`
+error: valid forms for the attribute are `#[doc(hidden)]`, `#[doc(inline)]`, and `#[doc = "string"]`
   --> $DIR/malformed-regressions.rs:1:1
    |
 LL | #[doc]
@@ -55,10 +58,11 @@ LL | #[doc]
    |
    = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: for more information, visit <https://doc.rust-lang.org/rustdoc/write-documentation/the-doc-attribute.html>
    = note: `#[deny(ill_formed_attribute_input)]` on by default
 
 Future breakage diagnostic:
-error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
+error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]`
   --> $DIR/malformed-regressions.rs:7:1
    |
 LL | #[link]
@@ -66,10 +70,11 @@ LL | #[link]
    |
    = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
    = note: `#[deny(ill_formed_attribute_input)]` on by default
 
 Future breakage diagnostic:
-error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
+error: valid forms for the attribute are `#[link(name = "...")]`, `#[link(name = "...", kind = "dylib|static|...")]`, `#[link(name = "...", wasm_import_module = "...")]`, `#[link(name = "...", import_name_type = "decorated|noprefix|undecorated")]`, and `#[link(name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated")]`
   --> $DIR/malformed-regressions.rs:9:1
    |
 LL | #[link = ""]
@@ -77,6 +82,7 @@ LL | #[link = ""]
    |
    = 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 #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute>
    = note: `#[deny(ill_formed_attribute_input)]` on by default
 
 Future breakage diagnostic:
@@ -91,7 +97,7 @@ LL | #[ignore()]
    = note: `#[deny(ill_formed_attribute_input)]` on by default
 
 Future breakage diagnostic:
-error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]`
+error: valid forms for the attribute are `#[inline(always)]`, `#[inline(never)]`, and `#[inline]`
   --> $DIR/malformed-regressions.rs:5:1
    |
 LL | #[inline = ""]
diff --git a/tests/ui/modules/path-invalid-form.stderr b/tests/ui/modules/path-invalid-form.stderr
index e8ded1343f7..4e9a62fa7a9 100644
--- a/tests/ui/modules/path-invalid-form.stderr
+++ b/tests/ui/modules/path-invalid-form.stderr
@@ -3,6 +3,8 @@ error: malformed `path` attribute input
    |
 LL | #[path = 123]
    | ^^^^^^^^^^^^^ help: must be of the form: `#[path = "file"]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute>
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/modules/path-macro.stderr b/tests/ui/modules/path-macro.stderr
index eb02c721edd..fd93871f3a6 100644
--- a/tests/ui/modules/path-macro.stderr
+++ b/tests/ui/modules/path-macro.stderr
@@ -3,6 +3,8 @@ error: malformed `path` attribute input
    |
 LL | #[path = foo!()]
    | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[path = "file"]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute>
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/parser/bad-lit-suffixes.stderr b/tests/ui/parser/bad-lit-suffixes.stderr
index 7876d75c5a4..9a51cf70960 100644
--- a/tests/ui/parser/bad-lit-suffixes.stderr
+++ b/tests/ui/parser/bad-lit-suffixes.stderr
@@ -158,6 +158,7 @@ LL | #[must_use = "string"suffix]
    |              |
    |              expected a string literal here
    |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute>
 help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[must_use = "string"suffix]
diff --git a/tests/ui/parser/default-on-wrong-item-kind.rs b/tests/ui/parser/default-on-wrong-item-kind.rs
index da990a4b421..9de85640565 100644
--- a/tests/ui/parser/default-on-wrong-item-kind.rs
+++ b/tests/ui/parser/default-on-wrong-item-kind.rs
@@ -19,7 +19,7 @@ mod free_items {
     default union foo {} //~ ERROR a union cannot be `default`
     default trait foo {} //~ ERROR a trait cannot be `default`
     default trait foo = Ord; //~ ERROR a trait alias cannot be `default`
-    default impl foo {}
+    default impl foo {} //~ ERROR inherent impls cannot be default
     default!();
     default::foo::bar!();
     default default!(); //~ ERROR an item macro invocation cannot be `default`
@@ -53,7 +53,7 @@ extern "C" {
     //~^ ERROR trait is not supported in `extern` blocks
     default trait foo = Ord; //~ ERROR a trait alias cannot be `default`
     //~^ ERROR trait alias is not supported in `extern` blocks
-    default impl foo {}
+    default impl foo {} //~ ERROR inherent impls cannot be default
     //~^ ERROR implementation is not supported in `extern` blocks
     default!();
     default::foo::bar!();
@@ -90,7 +90,7 @@ impl S {
     //~^ ERROR trait is not supported in `trait`s or `impl`s
     default trait foo = Ord; //~ ERROR a trait alias cannot be `default`
     //~^ ERROR trait alias is not supported in `trait`s or `impl`s
-    default impl foo {}
+    default impl foo {} //~ ERROR inherent impls cannot be default
     //~^ ERROR implementation is not supported in `trait`s or `impl`s
     default!();
     default::foo::bar!();
@@ -127,7 +127,7 @@ trait T {
     //~^ ERROR trait is not supported in `trait`s or `impl`s
     default trait foo = Ord; //~ ERROR a trait alias cannot be `default`
     //~^ ERROR trait alias is not supported in `trait`s or `impl`s
-    default impl foo {}
+    default impl foo {} //~ ERROR inherent impls cannot be default
     //~^ ERROR implementation is not supported in `trait`s or `impl`s
     default!();
     default::foo::bar!();
diff --git a/tests/ui/parser/default-on-wrong-item-kind.stderr b/tests/ui/parser/default-on-wrong-item-kind.stderr
index 56641565b16..0380fcdf775 100644
--- a/tests/ui/parser/default-on-wrong-item-kind.stderr
+++ b/tests/ui/parser/default-on-wrong-item-kind.stderr
@@ -78,6 +78,16 @@ LL |     default trait foo = Ord;
    |
    = note: only associated `fn`, `const`, and `type` items can be `default`
 
+error: inherent impls cannot be default
+  --> $DIR/default-on-wrong-item-kind.rs:22:18
+   |
+LL |     default impl foo {}
+   |     -------      ^^^ inherent impl for this type
+   |     |
+   |     default because of this
+   |
+   = note: only trait implementations may be annotated with `default`
+
 error: an item macro invocation cannot be `default`
   --> $DIR/default-on-wrong-item-kind.rs:25:5
    |
@@ -275,6 +285,16 @@ LL |     default trait foo = Ord;
    |
    = help: consider moving the trait alias out to a nearby module scope
 
+error: inherent impls cannot be default
+  --> $DIR/default-on-wrong-item-kind.rs:56:18
+   |
+LL |     default impl foo {}
+   |     -------      ^^^ inherent impl for this type
+   |     |
+   |     default because of this
+   |
+   = note: only trait implementations may be annotated with `default`
+
 error: implementation is not supported in `extern` blocks
   --> $DIR/default-on-wrong-item-kind.rs:56:5
    |
@@ -489,6 +509,16 @@ LL |     default trait foo = Ord;
    |
    = help: consider moving the trait alias out to a nearby module scope
 
+error: inherent impls cannot be default
+  --> $DIR/default-on-wrong-item-kind.rs:93:18
+   |
+LL |     default impl foo {}
+   |     -------      ^^^ inherent impl for this type
+   |     |
+   |     default because of this
+   |
+   = note: only trait implementations may be annotated with `default`
+
 error: implementation is not supported in `trait`s or `impl`s
   --> $DIR/default-on-wrong-item-kind.rs:93:5
    |
@@ -703,6 +733,16 @@ LL |     default trait foo = Ord;
    |
    = help: consider moving the trait alias out to a nearby module scope
 
+error: inherent impls cannot be default
+  --> $DIR/default-on-wrong-item-kind.rs:130:18
+   |
+LL |     default impl foo {}
+   |     -------      ^^^ inherent impl for this type
+   |     |
+   |     default because of this
+   |
+   = note: only trait implementations may be annotated with `default`
+
 error: implementation is not supported in `trait`s or `impl`s
   --> $DIR/default-on-wrong-item-kind.rs:130:5
    |
@@ -759,5 +799,5 @@ LL |     default macro_rules! foo {}
    |
    = help: consider moving the macro definition out to a nearby module scope
 
-error: aborting due to 95 previous errors
+error: aborting due to 99 previous errors
 
diff --git a/tests/ui/proc-macro/attribute.rs b/tests/ui/proc-macro/attribute.rs
index 988cdcd0403..dfb26738377 100644
--- a/tests/ui/proc-macro/attribute.rs
+++ b/tests/ui/proc-macro/attribute.rs
@@ -9,46 +9,55 @@ use proc_macro::*;
 #[proc_macro_derive]
 //~^ ERROR malformed `proc_macro_derive` attribute
 //~| NOTE expected this to be a list
+//~| NOTE for more information, visit
 pub fn foo1(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive = ""]
 //~^ ERROR malformed `proc_macro_derive` attribute
 //~| NOTE expected this to be a list
+//~| NOTE for more information, visit
 pub fn foo2(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d3, a, b)]
 //~^ ERROR malformed `proc_macro_derive` attribute
 //~| NOTE the only valid argument here is `attributes`
+//~| NOTE for more information, visit
 pub fn foo3(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d4, attributes(a), b)]
 //~^ ERROR malformed `proc_macro_derive` attribute
 //~| NOTE didn't expect any arguments here
+//~| NOTE for more information, visit
 pub fn foo4(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive("a")]
 //~^ ERROR malformed `proc_macro_derive` attribute
 //~| NOTE didn't expect a literal here
+//~| NOTE for more information, visit
 pub fn foo5(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d6 = "")]
 //~^ ERROR malformed `proc_macro_derive` attribute
 //~| NOTE didn't expect any arguments here
+//~| NOTE for more information, visit
 pub fn foo6(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(m::d7)]
 //~^ ERROR malformed `proc_macro_derive` attribute
 //~| NOTE expected a valid identifier here
+//~| NOTE for more information, visit
 pub fn foo7(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d8(a))]
 //~^ ERROR malformed `proc_macro_derive` attribute
 //~| NOTE didn't expect any arguments here
+//~| NOTE for more information, visit
 pub fn foo8(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(self)]
 //~^ ERROR malformed `proc_macro_derive` attribute
 //~| NOTE expected a valid identifier here
+//~| NOTE for more information, visit
 pub fn foo9(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(PartialEq)] // OK
@@ -57,34 +66,41 @@ pub fn foo10(input: TokenStream) -> TokenStream { input }
 #[proc_macro_derive(d11, a)]
 //~^ ERROR malformed `proc_macro_derive` attribute
 //~| NOTE the only valid argument here is `attributes`
+//~| NOTE for more information, visit
 pub fn foo11(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d12, attributes)]
 //~^ ERROR malformed `proc_macro_derive` attribute
 //~| NOTE expected this to be a list
+//~| NOTE for more information, visit
 pub fn foo12(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d13, attributes("a"))]
 //~^ ERROR malformed `proc_macro_derive` attribute
 //~| NOTE expected a valid identifier here
+//~| NOTE for more information, visit
 pub fn foo13(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d14, attributes(a = ""))]
 //~^ ERROR malformed `proc_macro_derive` attribute
 //~| NOTE didn't expect any arguments here
+//~| NOTE for more information, visit
 pub fn foo14(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d15, attributes(m::a))]
 //~^ ERROR malformed `proc_macro_derive` attribute
 //~| NOTE expected a valid identifier here
+//~| NOTE for more information, visit
 pub fn foo15(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d16, attributes(a(b)))]
 //~^ ERROR malformed `proc_macro_derive` attribute
 //~| NOTE didn't expect any arguments here
+//~| NOTE for more information, visit
 pub fn foo16(input: TokenStream) -> TokenStream { input }
 
 #[proc_macro_derive(d17, attributes(self))]
 //~^ ERROR malformed `proc_macro_derive` attribute
 //~| NOTE expected a valid identifier here
+//~| NOTE for more information, visit
 pub fn foo17(input: TokenStream) -> TokenStream { input }
diff --git a/tests/ui/proc-macro/attribute.stderr b/tests/ui/proc-macro/attribute.stderr
index db59a1fdfb3..e7127c8ef1d 100644
--- a/tests/ui/proc-macro/attribute.stderr
+++ b/tests/ui/proc-macro/attribute.stderr
@@ -2,145 +2,283 @@ error[E0539]: malformed `proc_macro_derive` attribute input
   --> $DIR/attribute.rs:9:1
    |
 LL | #[proc_macro_derive]
-   | ^^^^^^^^^^^^^^^^^^^^
-   | |
-   | expected this to be a list
-   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+   | ^^^^^^^^^^^^^^^^^^^^ expected this to be a list
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL | #[proc_macro_derive(TraitName)]
+   |                    +++++++++++
+LL | #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
+   |                    ++++++++++++++++++++++++++++++++++++++++++
 
 error[E0539]: malformed `proc_macro_derive` attribute input
-  --> $DIR/attribute.rs:14:1
+  --> $DIR/attribute.rs:15:1
    |
 LL | #[proc_macro_derive = ""]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
-   | |
-   | expected this to be a list
-   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected this to be a list
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[proc_macro_derive = ""]
+LL + #[proc_macro_derive(TraitName)]
+   |
+LL - #[proc_macro_derive = ""]
+LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
+   |
 
 error[E0539]: malformed `proc_macro_derive` attribute input
-  --> $DIR/attribute.rs:19:1
+  --> $DIR/attribute.rs:21:1
    |
 LL | #[proc_macro_derive(d3, a, b)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^-^^^^^
-   | |                       |
-   | |                       the only valid argument here is `attributes`
-   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+   |                         |
+   |                         the only valid argument here is `attributes`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[proc_macro_derive(d3, a, b)]
+LL + #[proc_macro_derive(TraitName)]
+   |
+LL - #[proc_macro_derive(d3, a, b)]
+LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
+   |
 
 error[E0565]: malformed `proc_macro_derive` attribute input
-  --> $DIR/attribute.rs:24:1
+  --> $DIR/attribute.rs:27:1
    |
 LL | #[proc_macro_derive(d4, attributes(a), b)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^
-   | |                                      |
-   | |                                      didn't expect any arguments here
-   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+   |                                        |
+   |                                        didn't expect any arguments here
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[proc_macro_derive(d4, attributes(a), b)]
+LL + #[proc_macro_derive(TraitName)]
+   |
+LL - #[proc_macro_derive(d4, attributes(a), b)]
+LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
+   |
 
 error[E0565]: malformed `proc_macro_derive` attribute input
-  --> $DIR/attribute.rs:29:1
+  --> $DIR/attribute.rs:33:1
    |
 LL | #[proc_macro_derive("a")]
    | ^^^^^^^^^^^^^^^^^^^^---^^
-   | |                   |
-   | |                   didn't expect a literal here
-   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+   |                     |
+   |                     didn't expect a literal here
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[proc_macro_derive("a")]
+LL + #[proc_macro_derive(TraitName)]
+   |
+LL - #[proc_macro_derive("a")]
+LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
+   |
 
 error[E0565]: malformed `proc_macro_derive` attribute input
-  --> $DIR/attribute.rs:34:1
+  --> $DIR/attribute.rs:39:1
    |
 LL | #[proc_macro_derive(d6 = "")]
    | ^^^^^^^^^^^^^^^^^^^^^^^----^^
-   | |                      |
-   | |                      didn't expect any arguments here
-   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+   |                        |
+   |                        didn't expect any arguments here
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[proc_macro_derive(d6 = "")]
+LL + #[proc_macro_derive(TraitName)]
+   |
+LL - #[proc_macro_derive(d6 = "")]
+LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
+   |
 
 error[E0539]: malformed `proc_macro_derive` attribute input
-  --> $DIR/attribute.rs:39:1
+  --> $DIR/attribute.rs:45:1
    |
 LL | #[proc_macro_derive(m::d7)]
    | ^^^^^^^^^^^^^^^^^^^^-----^^
-   | |                   |
-   | |                   expected a valid identifier here
-   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+   |                     |
+   |                     expected a valid identifier here
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[proc_macro_derive(m::d7)]
+LL + #[proc_macro_derive(TraitName)]
+   |
+LL - #[proc_macro_derive(m::d7)]
+LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
+   |
 
 error[E0565]: malformed `proc_macro_derive` attribute input
-  --> $DIR/attribute.rs:44:1
+  --> $DIR/attribute.rs:51:1
    |
 LL | #[proc_macro_derive(d8(a))]
    | ^^^^^^^^^^^^^^^^^^^^^^---^^
-   | |                     |
-   | |                     didn't expect any arguments here
-   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+   |                       |
+   |                       didn't expect any arguments here
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[proc_macro_derive(d8(a))]
+LL + #[proc_macro_derive(TraitName)]
+   |
+LL - #[proc_macro_derive(d8(a))]
+LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
+   |
 
 error[E0539]: malformed `proc_macro_derive` attribute input
-  --> $DIR/attribute.rs:49:1
+  --> $DIR/attribute.rs:57:1
    |
 LL | #[proc_macro_derive(self)]
    | ^^^^^^^^^^^^^^^^^^^^----^^
-   | |                   |
-   | |                   expected a valid identifier here
-   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+   |                     |
+   |                     expected a valid identifier here
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[proc_macro_derive(self)]
+LL + #[proc_macro_derive(TraitName)]
+   |
+LL - #[proc_macro_derive(self)]
+LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
+   |
 
 error[E0539]: malformed `proc_macro_derive` attribute input
-  --> $DIR/attribute.rs:57:1
+  --> $DIR/attribute.rs:66:1
    |
 LL | #[proc_macro_derive(d11, a)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^-^^
-   | |                        |
-   | |                        the only valid argument here is `attributes`
-   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+   |                          |
+   |                          the only valid argument here is `attributes`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[proc_macro_derive(d11, a)]
+LL + #[proc_macro_derive(TraitName)]
+   |
+LL - #[proc_macro_derive(d11, a)]
+LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
+   |
 
 error[E0539]: malformed `proc_macro_derive` attribute input
-  --> $DIR/attribute.rs:62:1
+  --> $DIR/attribute.rs:72:1
    |
 LL | #[proc_macro_derive(d12, attributes)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^----------^^
-   | |                        |
-   | |                        expected this to be a list
-   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+   |                          |
+   |                          expected this to be a list
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[proc_macro_derive(d12, attributes)]
+LL + #[proc_macro_derive(TraitName)]
+   |
+LL - #[proc_macro_derive(d12, attributes)]
+LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
+   |
 
 error[E0539]: malformed `proc_macro_derive` attribute input
-  --> $DIR/attribute.rs:67:1
+  --> $DIR/attribute.rs:78:1
    |
 LL | #[proc_macro_derive(d13, attributes("a"))]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^^
-   | |                                   |
-   | |                                   expected a valid identifier here
-   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+   |                                     |
+   |                                     expected a valid identifier here
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[proc_macro_derive(d13, attributes("a"))]
+LL + #[proc_macro_derive(TraitName)]
+   |
+LL - #[proc_macro_derive(d13, attributes("a"))]
+LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
+   |
 
 error[E0565]: malformed `proc_macro_derive` attribute input
-  --> $DIR/attribute.rs:72:1
+  --> $DIR/attribute.rs:84:1
    |
 LL | #[proc_macro_derive(d14, attributes(a = ""))]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----^^^
-   | |                                     |
-   | |                                     didn't expect any arguments here
-   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+   |                                       |
+   |                                       didn't expect any arguments here
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[proc_macro_derive(d14, attributes(a = ""))]
+LL + #[proc_macro_derive(TraitName)]
+   |
+LL - #[proc_macro_derive(d14, attributes(a = ""))]
+LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
+   |
 
 error[E0539]: malformed `proc_macro_derive` attribute input
-  --> $DIR/attribute.rs:77:1
+  --> $DIR/attribute.rs:90:1
    |
 LL | #[proc_macro_derive(d15, attributes(m::a))]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----^^^
-   | |                                   |
-   | |                                   expected a valid identifier here
-   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+   |                                     |
+   |                                     expected a valid identifier here
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[proc_macro_derive(d15, attributes(m::a))]
+LL + #[proc_macro_derive(TraitName)]
+   |
+LL - #[proc_macro_derive(d15, attributes(m::a))]
+LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
+   |
 
 error[E0565]: malformed `proc_macro_derive` attribute input
-  --> $DIR/attribute.rs:82:1
+  --> $DIR/attribute.rs:96:1
    |
 LL | #[proc_macro_derive(d16, attributes(a(b)))]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^---^^^
-   | |                                    |
-   | |                                    didn't expect any arguments here
-   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+   |                                      |
+   |                                      didn't expect any arguments here
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[proc_macro_derive(d16, attributes(a(b)))]
+LL + #[proc_macro_derive(TraitName)]
+   |
+LL - #[proc_macro_derive(d16, attributes(a(b)))]
+LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
+   |
 
 error[E0539]: malformed `proc_macro_derive` attribute input
-  --> $DIR/attribute.rs:87:1
+  --> $DIR/attribute.rs:102:1
    |
 LL | #[proc_macro_derive(d17, attributes(self))]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^----^^^
-   | |                                   |
-   | |                                   expected a valid identifier here
-   | help: must be of the form: `#[proc_macro_derive(TraitName, /*opt*/ attributes(name1, name2, ...))]`
+   |                                     |
+   |                                     expected a valid identifier here
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[proc_macro_derive(d17, attributes(self))]
+LL + #[proc_macro_derive(TraitName)]
+   |
+LL - #[proc_macro_derive(d17, attributes(self))]
+LL + #[proc_macro_derive(TraitName, attributes(name1, name2, ...))]
+   |
 
 error: aborting due to 16 previous errors
 
diff --git a/tests/ui/proc-macro/macro-namespace-reserved-2.stderr b/tests/ui/proc-macro/macro-namespace-reserved-2.stderr
index 0471124061e..c8a7cc3ba91 100644
--- a/tests/ui/proc-macro/macro-namespace-reserved-2.stderr
+++ b/tests/ui/proc-macro/macro-namespace-reserved-2.stderr
@@ -95,14 +95,6 @@ error: expected derive macro, found macro `crate::my_macro`
    |
 LL | #[derive(crate::my_macro)]
    |          ^^^^^^^^^^^^^^^ not a derive macro
-   |
-help: remove from the surrounding `derive()`
-  --> $DIR/macro-namespace-reserved-2.rs:50:10
-   |
-LL | #[derive(crate::my_macro)]
-   |          ^^^^^^^^^^^^^^^
-   = help: add as non-Derive macro
-           `#[crate::my_macro]`
 
 error: cannot find macro `my_macro_attr` in this scope
   --> $DIR/macro-namespace-reserved-2.rs:28:5
diff --git a/tests/ui/recursion_limit/invalid_digit_type.stderr b/tests/ui/recursion_limit/invalid_digit_type.stderr
index 94442b5747f..a122262f1df 100644
--- a/tests/ui/recursion_limit/invalid_digit_type.stderr
+++ b/tests/ui/recursion_limit/invalid_digit_type.stderr
@@ -3,6 +3,8 @@ error: malformed `recursion_limit` attribute input
    |
 LL | #![recursion_limit = 123]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![recursion_limit = "N"]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute>
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/recursion_limit/invalid_macro.stderr b/tests/ui/recursion_limit/invalid_macro.stderr
index aa4894ec4d8..b4dbc9fcb13 100644
--- a/tests/ui/recursion_limit/invalid_macro.stderr
+++ b/tests/ui/recursion_limit/invalid_macro.stderr
@@ -3,6 +3,8 @@ error: malformed `recursion_limit` attribute input
    |
 LL | #![recursion_limit = foo!()]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![recursion_limit = "N"]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute>
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/recursion_limit/no-value.stderr b/tests/ui/recursion_limit/no-value.stderr
index b2e8c46c372..4a0ad04f271 100644
--- a/tests/ui/recursion_limit/no-value.stderr
+++ b/tests/ui/recursion_limit/no-value.stderr
@@ -3,6 +3,8 @@ error: malformed `recursion_limit` attribute input
    |
 LL | #![recursion_limit]
    | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![recursion_limit = "N"]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute>
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/repr/invalid_repr_list_help.stderr b/tests/ui/repr/invalid_repr_list_help.stderr
index 763ad9c2795..f9d1593275e 100644
--- a/tests/ui/repr/invalid_repr_list_help.stderr
+++ b/tests/ui/repr/invalid_repr_list_help.stderr
@@ -5,6 +5,7 @@ LL | #[repr(uwu)]
    |        ^^^
    |
    = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+   = note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html?highlight=repr#representations>
 
 error[E0552]: unrecognized representation hint
   --> $DIR/invalid_repr_list_help.rs:6:8
@@ -13,6 +14,7 @@ LL | #[repr(uwu = "a")]
    |        ^^^^^^^^^
    |
    = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+   = note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html?highlight=repr#representations>
 
 error[E0552]: unrecognized representation hint
   --> $DIR/invalid_repr_list_help.rs:9:8
@@ -21,6 +23,7 @@ LL | #[repr(uwu(4))]
    |        ^^^^^^
    |
    = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+   = note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html?highlight=repr#representations>
 
 error[E0552]: unrecognized representation hint
   --> $DIR/invalid_repr_list_help.rs:14:8
@@ -29,6 +32,7 @@ LL | #[repr(uwu, u8)]
    |        ^^^
    |
    = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+   = note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html?highlight=repr#representations>
 
 error[E0552]: unrecognized representation hint
   --> $DIR/invalid_repr_list_help.rs:19:8
@@ -37,6 +41,7 @@ LL | #[repr(uwu)]
    |        ^^^
    |
    = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+   = note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html?highlight=repr#representations>
 
 error: unknown `doc` attribute `owo`
   --> $DIR/invalid_repr_list_help.rs:20:7
diff --git a/tests/ui/repr/repr.stderr b/tests/ui/repr/repr.stderr
index 9e581332278..d4faea12517 100644
--- a/tests/ui/repr/repr.stderr
+++ b/tests/ui/repr/repr.stderr
@@ -2,28 +2,66 @@ error[E0539]: malformed `repr` attribute input
   --> $DIR/repr.rs:1:1
    |
 LL | #[repr]
-   | ^^^^^^^
-   | |
-   | expected this to be a list
-   | help: must be of the form: `#[repr(C | Rust | align(...) | packed(...) | <integer type> | transparent)]`
+   | ^^^^^^^ expected this to be a list
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html#representations>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL | #[repr(<integer type>)]
+   |       ++++++++++++++++
+LL | #[repr(C)]
+   |       +++
+LL | #[repr(Rust)]
+   |       ++++++
+LL | #[repr(align(...))]
+   |       ++++++++++++
+   = and 2 other candidates
 
 error[E0539]: malformed `repr` attribute input
   --> $DIR/repr.rs:4:1
    |
 LL | #[repr = "B"]
-   | ^^^^^^^^^^^^^
-   | |
-   | expected this to be a list
-   | help: must be of the form: `#[repr(C | Rust | align(...) | packed(...) | <integer type> | transparent)]`
+   | ^^^^^^^^^^^^^ expected this to be a list
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html#representations>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[repr = "B"]
+LL + #[repr(<integer type>)]
+   |
+LL - #[repr = "B"]
+LL + #[repr(C)]
+   |
+LL - #[repr = "B"]
+LL + #[repr(Rust)]
+   |
+LL - #[repr = "B"]
+LL + #[repr(align(...))]
+   |
+   = and 2 other candidates
 
 error[E0539]: malformed `repr` attribute input
   --> $DIR/repr.rs:7:1
    |
 LL | #[repr = "C"]
-   | ^^^^^^^^^^^^^
-   | |
-   | expected this to be a list
-   | help: must be of the form: `#[repr(C | Rust | align(...) | packed(...) | <integer type> | transparent)]`
+   | ^^^^^^^^^^^^^ expected this to be a list
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/type-layout.html#representations>
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[repr = "C"]
+LL + #[repr(<integer type>)]
+   |
+LL - #[repr = "C"]
+LL + #[repr(C)]
+   |
+LL - #[repr = "C"]
+LL + #[repr(Rust)]
+   |
+LL - #[repr = "C"]
+LL + #[repr(align(...))]
+   |
+   = and 2 other candidates
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/resolve/path-attr-in-const-block.stderr b/tests/ui/resolve/path-attr-in-const-block.stderr
index 0b5942a287d..f3ae5b60c4f 100644
--- a/tests/ui/resolve/path-attr-in-const-block.stderr
+++ b/tests/ui/resolve/path-attr-in-const-block.stderr
@@ -12,6 +12,8 @@ LL |         #![path = foo!()]
    |         |         |
    |         |         expected a string literal here
    |         help: must be of the form: `#[path = "file"]`
+   |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute>
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/span/E0539.stderr b/tests/ui/span/E0539.stderr
index 01f091a2676..34d81b73cb5 100644
--- a/tests/ui/span/E0539.stderr
+++ b/tests/ui/span/E0539.stderr
@@ -6,10 +6,14 @@ LL | #[inline(unknown)]
    |          |
    |          valid arguments are `always` or `never`
    |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute>
 help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[inline(unknown)]
-LL + #[inline(always|never)]
+LL + #[inline(always)]
+   |
+LL - #[inline(unknown)]
+LL + #[inline(never)]
    |
 LL - #[inline(unknown)]
 LL + #[inline]
diff --git a/tests/ui/specialization/defaultimpl/validation.rs b/tests/ui/specialization/defaultimpl/validation.rs
index 14771be8982..78f6099c3dd 100644
--- a/tests/ui/specialization/defaultimpl/validation.rs
+++ b/tests/ui/specialization/defaultimpl/validation.rs
@@ -4,7 +4,7 @@
 struct S;
 struct Z;
 
-default impl S {} //~ ERROR inherent impls cannot be `default`
+default impl S {} //~ ERROR inherent impls cannot be default
 
 default unsafe impl Send for S {}
 //~^ ERROR impls of auto traits cannot be default
diff --git a/tests/ui/specialization/defaultimpl/validation.stderr b/tests/ui/specialization/defaultimpl/validation.stderr
index 82a33bf9cdc..a8dfef2dcfb 100644
--- a/tests/ui/specialization/defaultimpl/validation.stderr
+++ b/tests/ui/specialization/defaultimpl/validation.stderr
@@ -1,10 +1,10 @@
-error: inherent impls cannot be `default`
+error: inherent impls cannot be default
   --> $DIR/validation.rs:7:14
    |
 LL | default impl S {}
    | -------      ^ inherent impl for this type
    | |
-   | `default` because of this
+   | default because of this
    |
    = note: only trait implementations may be annotated with `default`
 
diff --git a/tests/ui/test-attrs/test-should-panic-attr.rs b/tests/ui/test-attrs/test-should-panic-attr.rs
index af54689551c..e6de07d0094 100644
--- a/tests/ui/test-attrs/test-should-panic-attr.rs
+++ b/tests/ui/test-attrs/test-should-panic-attr.rs
@@ -10,6 +10,7 @@ fn test1() {
 #[should_panic(expected)]
 //~^ ERROR malformed `should_panic` attribute input
 //~| NOTE expected this to be of the form `expected = "..."`
+//~| NOTE for more information, visit
 fn test2() {
     panic!();
 }
@@ -18,6 +19,7 @@ fn test2() {
 #[should_panic(expect)]
 //~^ ERROR malformed `should_panic` attribute input
 //~| NOTE the only valid argument here is "expected"
+//~| NOTE for more information, visit
 fn test3() {
     panic!();
 }
@@ -26,6 +28,7 @@ fn test3() {
 #[should_panic(expected(foo, bar))]
 //~^ ERROR malformed `should_panic` attribute input
 //~| NOTE expected this to be of the form `expected = "..."`
+//~| NOTE for more information, visit
 fn test4() {
     panic!();
 }
@@ -34,6 +37,7 @@ fn test4() {
 #[should_panic(expected = "foo", bar)]
 //~^ ERROR malformed `should_panic` attribute input
 //~| NOTE expected a single argument here
+//~| NOTE for more information, visit
 fn test5() {
     panic!();
 }
diff --git a/tests/ui/test-attrs/test-should-panic-attr.stderr b/tests/ui/test-attrs/test-should-panic-attr.stderr
index 5dfc8e503e8..475a55ad0cb 100644
--- a/tests/ui/test-attrs/test-should-panic-attr.stderr
+++ b/tests/ui/test-attrs/test-should-panic-attr.stderr
@@ -6,6 +6,7 @@ LL | #[should_panic(expected)]
    |                |
    |                expected this to be of the form `expected = "..."`
    |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute>
 help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[should_panic(expected)]
@@ -18,13 +19,14 @@ LL + #[should_panic]
    |
 
 error[E0539]: malformed `should_panic` attribute input
-  --> $DIR/test-should-panic-attr.rs:18:1
+  --> $DIR/test-should-panic-attr.rs:19:1
    |
 LL | #[should_panic(expect)]
    | ^^^^^^^^^^^^^^--------^
    |               |
    |               the only valid argument here is "expected"
    |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute>
 help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[should_panic(expect)]
@@ -37,13 +39,14 @@ LL + #[should_panic]
    |
 
 error[E0539]: malformed `should_panic` attribute input
-  --> $DIR/test-should-panic-attr.rs:26:1
+  --> $DIR/test-should-panic-attr.rs:28:1
    |
 LL | #[should_panic(expected(foo, bar))]
    | ^^^^^^^^^^^^^^^------------------^^
    |                |
    |                expected this to be of the form `expected = "..."`
    |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute>
 help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[should_panic(expected(foo, bar))]
@@ -57,13 +60,14 @@ LL + #[should_panic]
    |
 
 error[E0805]: malformed `should_panic` attribute input
-  --> $DIR/test-should-panic-attr.rs:34:1
+  --> $DIR/test-should-panic-attr.rs:37:1
    |
 LL | #[should_panic(expected = "foo", bar)]
    | ^^^^^^^^^^^^^^-----------------------^
    |               |
    |               expected a single argument here
    |
+   = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute>
 help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[should_panic(expected = "foo", bar)]
diff --git a/tests/ui/trait-bounds/more_maybe_bounds.rs b/tests/ui/trait-bounds/more_maybe_bounds.rs
index 47348b0a0dd..d367dd5b299 100644
--- a/tests/ui/trait-bounds/more_maybe_bounds.rs
+++ b/tests/ui/trait-bounds/more_maybe_bounds.rs
@@ -1,7 +1,7 @@
 // FIXME(more_maybe_bounds): Even under `more_maybe_bounds` / `-Zexperimental-default-bounds`,
 // trying to relax non-default bounds should still be an error in all contexts! As you can see
-// there are places like supertrait bounds and trait object types where we currently don't perform
-// this check.
+// there are places like supertrait bounds, trait object types or associated type bounds (ATB)
+// where we currently don't perform this check.
 #![feature(auto_traits, more_maybe_bounds, negative_impls)]
 
 trait Trait1 {}
@@ -13,11 +13,15 @@ trait Trait4 where Self: Trait1 {}
 
 // FIXME: `?Trait2` should be rejected, `Trait2` isn't marked `#[lang = "default_traitN"]`.
 fn foo(_: Box<(dyn Trait3 + ?Trait2)>) {}
+
 fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
 //~^ ERROR bound modifier `?` can only be applied to default traits like `Sized`
 //~| ERROR bound modifier `?` can only be applied to default traits like `Sized`
 //~| ERROR bound modifier `?` can only be applied to default traits like `Sized`
 
+// FIXME: `?Trait1` should be rejected, `Trait1` isn't marked `#[lang = "default_traitN"]`.
+fn baz<T>() where T: Iterator<Item: ?Trait1> {}
+
 struct S;
 impl !Trait2 for S {}
 impl Trait1 for S {}
diff --git a/tests/ui/trait-bounds/more_maybe_bounds.stderr b/tests/ui/trait-bounds/more_maybe_bounds.stderr
index 09c9fc31165..8dd83fc7728 100644
--- a/tests/ui/trait-bounds/more_maybe_bounds.stderr
+++ b/tests/ui/trait-bounds/more_maybe_bounds.stderr
@@ -1,17 +1,17 @@
 error: bound modifier `?` can only be applied to default traits like `Sized`
-  --> $DIR/more_maybe_bounds.rs:16:20
+  --> $DIR/more_maybe_bounds.rs:17:20
    |
 LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
    |                    ^^^^^^^
 
 error: bound modifier `?` can only be applied to default traits like `Sized`
-  --> $DIR/more_maybe_bounds.rs:16:30
+  --> $DIR/more_maybe_bounds.rs:17:30
    |
 LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
    |                              ^^^^^^^
 
 error: bound modifier `?` can only be applied to default traits like `Sized`
-  --> $DIR/more_maybe_bounds.rs:16:40
+  --> $DIR/more_maybe_bounds.rs:17:40
    |
 LL | fn bar<T: ?Sized + ?Trait2 + ?Trait1 + ?Trait4>(_: &T) {}
    |                                        ^^^^^^^
diff --git a/tests/ui/traits/const-traits/inherent-impl.rs b/tests/ui/traits/const-traits/inherent-impl.rs
index 07b23adf9e1..5ca4c5d7863 100644
--- a/tests/ui/traits/const-traits/inherent-impl.rs
+++ b/tests/ui/traits/const-traits/inherent-impl.rs
@@ -5,9 +5,9 @@ struct S;
 trait T {}
 
 impl const S {}
-//~^ ERROR inherent impls cannot be `const`
+//~^ ERROR inherent impls cannot be const
 
 impl const dyn T {}
-//~^ ERROR inherent impls cannot be `const`
+//~^ 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 e4ec1e807b0..d828ecb6349 100644
--- a/tests/ui/traits/const-traits/inherent-impl.stderr
+++ b/tests/ui/traits/const-traits/inherent-impl.stderr
@@ -1,20 +1,20 @@
-error: inherent impls cannot be `const`
+error: inherent impls cannot be const
   --> $DIR/inherent-impl.rs:7:12
    |
 LL | impl const S {}
    |      ----- ^ inherent impl for this type
    |      |
-   |      `const` because of this
+   |      const because of this
    |
    = note: only trait implementations may be annotated with `const`
 
-error: inherent impls cannot be `const`
+error: inherent impls cannot be const
   --> $DIR/inherent-impl.rs:10:12
    |
 LL | impl const dyn T {}
    |      ----- ^^^^^ inherent impl for this type
    |      |
-   |      `const` because of this
+   |      const because of this
    |
    = note: only trait implementations may be annotated with `const`
 
diff --git a/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr b/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr
index af160a45f3e..9fad260f0be 100644
--- a/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr
+++ b/tests/ui/traits/const-traits/macro-const-trait-bound-theoretical-regression.stderr
@@ -1,15 +1,4 @@
-error: macro expansion ignores keyword `dyn` and any tokens following
-  --> $DIR/macro-const-trait-bound-theoretical-regression.rs:14:31
-   |
-LL |     (dyn $c:ident Trait) => { dyn $c Trait {} };
-   |                               ^^^
-...
-LL | demo! { dyn const Trait }
-   | ------------------------- caused by the macro expansion here
-   |
-   = note: the usage of `demo!` is likely invalid in item context
-
-error: inherent impls cannot be `const`
+error: inherent impls cannot be const
   --> $DIR/macro-const-trait-bound-theoretical-regression.rs:10:40
    |
 LL |     (impl $c:ident Trait) => { impl $c Trait {} };
@@ -18,12 +7,23 @@ LL |     (impl $c:ident Trait) => { impl $c Trait {} };
 LL | demo! { impl const Trait }
    | --------------------------
    | |            |
-   | |            `const` because of this
+   | |            const because of this
    | in this macro invocation
    |
    = note: only trait implementations may be annotated with `const`
    = note: this error originates in the macro `demo` (in Nightly builds, run with -Z macro-backtrace for more info)
 
+error: macro expansion ignores keyword `dyn` and any tokens following
+  --> $DIR/macro-const-trait-bound-theoretical-regression.rs:14:31
+   |
+LL |     (dyn $c:ident Trait) => { dyn $c Trait {} };
+   |                               ^^^
+...
+LL | demo! { dyn const Trait }
+   | ------------------------- caused by the macro expansion here
+   |
+   = note: the usage of `demo!` is likely invalid in item context
+
 error[E0658]: const trait impls are experimental
   --> $DIR/macro-const-trait-bound-theoretical-regression.rs:17:14
    |
diff --git a/tests/ui/traits/const-traits/span-bug-issue-121418.rs b/tests/ui/traits/const-traits/span-bug-issue-121418.rs
index 50a7e12f2a7..593180ac094 100644
--- a/tests/ui/traits/const-traits/span-bug-issue-121418.rs
+++ b/tests/ui/traits/const-traits/span-bug-issue-121418.rs
@@ -4,7 +4,7 @@ struct S;
 trait T {}
 
 impl const dyn T {
-    //~^ ERROR inherent impls cannot be `const`
+    //~^ ERROR inherent impls cannot be const
     pub const fn new() -> std::sync::Mutex<dyn T> {}
     //~^ ERROR mismatched types
     //~| ERROR cannot be known at compilation time
diff --git a/tests/ui/traits/const-traits/span-bug-issue-121418.stderr b/tests/ui/traits/const-traits/span-bug-issue-121418.stderr
index f31129d9cb7..0c8ca918a3e 100644
--- a/tests/ui/traits/const-traits/span-bug-issue-121418.stderr
+++ b/tests/ui/traits/const-traits/span-bug-issue-121418.stderr
@@ -1,10 +1,10 @@
-error: inherent impls cannot be `const`
+error: inherent impls cannot be const
   --> $DIR/span-bug-issue-121418.rs:6:12
    |
 LL | impl const dyn T {
    |      ----- ^^^^^ inherent impl for this type
    |      |
-   |      `const` because of this
+   |      const because of this
    |
    = note: only trait implementations may be annotated with `const`
 
diff --git a/tests/ui/traits/safety-inherent-impl.stderr b/tests/ui/traits/safety-inherent-impl.stderr
index 2513fef909e..45cdbe2b523 100644
--- a/tests/ui/traits/safety-inherent-impl.stderr
+++ b/tests/ui/traits/safety-inherent-impl.stderr
@@ -5,6 +5,8 @@ LL | unsafe impl SomeStruct {
    | ------      ^^^^^^^^^^ inherent impl for this type
    | |
    | unsafe because of this
+   |
+   = note: only trait implementations may be annotated with `unsafe`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/traits/syntax-trait-polarity.stderr b/tests/ui/traits/syntax-trait-polarity.stderr
index 1fd40fb6657..8ffcdc7d8b5 100644
--- a/tests/ui/traits/syntax-trait-polarity.stderr
+++ b/tests/ui/traits/syntax-trait-polarity.stderr
@@ -5,15 +5,8 @@ LL | impl !TestType {}
    |      -^^^^^^^^ inherent impl for this type
    |      |
    |      negative because of this
-
-error[E0198]: negative impls cannot be unsafe
-  --> $DIR/syntax-trait-polarity.rs:12:13
    |
-LL | unsafe impl !Send for TestType {}
-   | ------      -^^^^
-   | |           |
-   | |           negative because of this
-   | unsafe because of this
+   = note: only trait implementations may be annotated with `!`
 
 error: inherent impls cannot be negative
   --> $DIR/syntax-trait-polarity.rs:18:10
@@ -22,6 +15,17 @@ LL | impl<T> !TestType2<T> {}
    |         -^^^^^^^^^^^^ inherent impl for this type
    |         |
    |         negative because of this
+   |
+   = note: only trait implementations may be annotated with `!`
+
+error[E0198]: negative impls cannot be unsafe
+  --> $DIR/syntax-trait-polarity.rs:12:13
+   |
+LL | unsafe impl !Send for TestType {}
+   | ------      -^^^^
+   | |           |
+   | |           negative because of this
+   | unsafe because of this
 
 error[E0198]: negative impls cannot be unsafe
   --> $DIR/syntax-trait-polarity.rs:21:16
diff --git a/tests/ui/unpretty/exhaustive.hir.stdout b/tests/ui/unpretty/exhaustive.hir.stdout
index 9cfa65f5801..e9823c9575b 100644
--- a/tests/ui/unpretty/exhaustive.hir.stdout
+++ b/tests/ui/unpretty/exhaustive.hir.stdout
@@ -509,7 +509,7 @@ mod items {
         impl () { }
         impl <T> () { }
         impl Default for () { }
-        impl const <T> Default for () { }
+        impl <T> const Default for () { }
     }
     /// ItemKind::MacCall
     mod item_mac_call { }
diff --git a/tests/ui/unsized/relaxed-bounds-invalid-places.rs b/tests/ui/unsized/relaxed-bounds-invalid-places.rs
index b8eda1e7786..4c1f242a01c 100644
--- a/tests/ui/unsized/relaxed-bounds-invalid-places.rs
+++ b/tests/ui/unsized/relaxed-bounds-invalid-places.rs
@@ -22,6 +22,10 @@ impl<T> S1<T> {
     fn f() where T: ?Sized {} //~ ERROR this relaxed bound is not permitted here
 }
 
+// Test associated type bounds (ATB).
+// issue: <https://github.com/rust-lang/rust/issues/135229>
+struct S6<T>(T) where T: Iterator<Item: ?Sized>; //~ ERROR this relaxed bound is not permitted here
+
 trait Tr: ?Sized {} //~ ERROR relaxed bounds are not permitted in supertrait bounds
 
 // Test that relaxed `Sized` bounds are rejected in trait object types:
diff --git a/tests/ui/unsized/relaxed-bounds-invalid-places.stderr b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr
index 30285d62693..d3f0535e2f0 100644
--- a/tests/ui/unsized/relaxed-bounds-invalid-places.stderr
+++ b/tests/ui/unsized/relaxed-bounds-invalid-places.stderr
@@ -38,8 +38,16 @@ LL |     fn f() where T: ?Sized {}
    |
    = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item
 
+error: this relaxed bound is not permitted here
+  --> $DIR/relaxed-bounds-invalid-places.rs:27:41
+   |
+LL | struct S6<T>(T) where T: Iterator<Item: ?Sized>;
+   |                                         ^^^^^^
+   |
+   = note: in this context, relaxed bounds are only allowed on type parameters defined by the closest item
+
 error: relaxed bounds are not permitted in supertrait bounds
-  --> $DIR/relaxed-bounds-invalid-places.rs:25:11
+  --> $DIR/relaxed-bounds-invalid-places.rs:29:11
    |
 LL | trait Tr: ?Sized {}
    |           ^^^^^^
@@ -47,19 +55,19 @@ LL | trait Tr: ?Sized {}
    = note: traits are `?Sized` by default
 
 error: relaxed bounds are not permitted in trait object types
-  --> $DIR/relaxed-bounds-invalid-places.rs:29:20
+  --> $DIR/relaxed-bounds-invalid-places.rs:33:20
    |
 LL | type O1 = dyn Tr + ?Sized;
    |                    ^^^^^^
 
 error: relaxed bounds are not permitted in trait object types
-  --> $DIR/relaxed-bounds-invalid-places.rs:30:15
+  --> $DIR/relaxed-bounds-invalid-places.rs:34:15
    |
 LL | type O2 = dyn ?Sized + ?Sized + Tr;
    |               ^^^^^^
 
 error: relaxed bounds are not permitted in trait object types
-  --> $DIR/relaxed-bounds-invalid-places.rs:30:24
+  --> $DIR/relaxed-bounds-invalid-places.rs:34:24
    |
 LL | type O2 = dyn ?Sized + ?Sized + Tr;
    |                        ^^^^^^
@@ -76,5 +84,5 @@ error: bound modifier `?` can only be applied to `Sized`
 LL | struct S5<T>(*const T) where T: ?Trait<'static> + ?Sized;
    |                                 ^^^^^^^^^^^^^^^
 
-error: aborting due to 11 previous errors
+error: aborting due to 12 previous errors
 
diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_on_trait.fail.stderr b/tests/ui/unstable-feature-bound/unstable_feature_bound_on_trait.fail.stderr
new file mode 100644
index 00000000000..69be101a40d
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_on_trait.fail.stderr
@@ -0,0 +1,18 @@
+error: unstable feature `foo` is used without being enabled.
+  --> $DIR/unstable_feature_bound_on_trait.rs:28:5
+   |
+LL |     Foo::bar();
+   |     ^^^^^^^^^^
+   |
+   = help: The feature can be enabled by marking the current item with `#[unstable_feature_bound(foo)]`
+note: required by a bound in `Bar::bar`
+  --> $DIR/unstable_feature_bound_on_trait.rs:16:1
+   |
+LL | #[unstable_feature_bound(foo)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Bar::bar`
+...
+LL |     fn bar() {}
+   |        --- required by a bound in this associated function
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/unstable-feature-bound/unstable_feature_bound_on_trait.rs b/tests/ui/unstable-feature-bound/unstable_feature_bound_on_trait.rs
new file mode 100644
index 00000000000..0ee00d5e7fb
--- /dev/null
+++ b/tests/ui/unstable-feature-bound/unstable_feature_bound_on_trait.rs
@@ -0,0 +1,33 @@
+//@ revisions: pass fail
+//@[pass] check-pass
+
+#![allow(internal_features)]
+#![feature(staged_api)]
+#![stable(feature = "a", since = "1.1.1" )]
+
+/// Test the behaviour of marking a trait with #[unstable_feature_bound].
+/// In this testcase, even though the trait method `bar` and the `struct Foo` are
+/// both stable, #[unstable_feature_bound] is still needed at the call site of Foo::bar().
+
+#[stable(feature = "a", since = "1.1.1" )]
+struct Foo;
+
+#[unstable(feature = "foo", issue = "none" )]
+#[unstable_feature_bound(foo)]
+trait Bar {
+    #[stable(feature = "a", since = "1.1.1" )]
+    fn bar() {}
+}
+
+#[unstable_feature_bound(foo)]
+impl Bar for Foo {
+}
+
+#[cfg_attr(pass, unstable_feature_bound(foo))]
+fn moo() {
+    Foo::bar();
+    //[fail]~^ ERROR: unstable feature `foo` is used without being enabled.
+}
+
+
+fn main() {}
diff --git a/tests/ui/unstable-feature-bound/unstable_inherent_method.rs b/tests/ui/unstable-feature-bound/unstable_inherent_method.rs
index 5f3095430a8..0d6e4ebb408 100644
--- a/tests/ui/unstable-feature-bound/unstable_inherent_method.rs
+++ b/tests/ui/unstable-feature-bound/unstable_inherent_method.rs
@@ -9,14 +9,14 @@
 pub trait Trait {
     #[unstable(feature = "feat", issue = "none" )]
     #[unstable_feature_bound(foo)]
-    //~^ ERROR: attribute should be applied to `impl` or free function outside of any `impl` or trait
+    //~^ ERROR: attribute should be applied to `impl`, trait or free function
     fn foo();
 }
 
 #[stable(feature = "a", since = "1.1.1" )]
 impl Trait for u8 {
     #[unstable_feature_bound(foo)]
-    //~^ ERROR: attribute should be applied to `impl` or free function outside of any `impl` or trait
+    //~^ ERROR: attribute should be applied to `impl`, trait or free function
     fn foo() {}
 }
 
diff --git a/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr b/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr
index fa1c39db259..90cbb32df7c 100644
--- a/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr
+++ b/tests/ui/unstable-feature-bound/unstable_inherent_method.stderr
@@ -1,20 +1,20 @@
-error: attribute should be applied to `impl` or free function outside of any `impl` or trait
+error: attribute should be applied to `impl`, trait or free function
   --> $DIR/unstable_inherent_method.rs:11:5
    |
 LL |     #[unstable_feature_bound(foo)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 LL |
 LL |     fn foo();
-   |     --------- not an `impl` or free function
+   |     --------- not an `impl`, trait or free function
 
-error: attribute should be applied to `impl` or free function outside of any `impl` or trait
+error: attribute should be applied to `impl`, trait or free function
   --> $DIR/unstable_inherent_method.rs:18:5
    |
 LL |     #[unstable_feature_bound(foo)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 LL |
 LL |     fn foo() {}
-   |     ----------- not an `impl` or free function
+   |     ----------- not an `impl`, trait or free function
 
 error: aborting due to 2 previous errors
 
diff --git a/triagebot.toml b/triagebot.toml
index 71f1ed0fda3..6f6e95c5b50 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -207,6 +207,7 @@ trigger_labels = [
     "regression-from-stable-to-beta",
     "regression-from-stable-to-nightly",
     "I-unsound",
+    "I-miscompile",
 ]
 exclude_labels = [
     "P-*",