about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock19
-rw-r--r--compiler/rustc_ast_lowering/Cargo.toml2
-rw-r--r--compiler/rustc_ast_lowering/src/block.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs18
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs19
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs97
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs2
-rw-r--r--compiler/rustc_ast_passes/messages.ftl2
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs7
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs12
-rw-r--r--compiler/rustc_attr_data_structures/Cargo.toml20
-rw-r--r--compiler/rustc_attr_data_structures/src/attributes.rs79
-rw-r--r--compiler/rustc_attr_data_structures/src/lib.rs137
-rw-r--r--compiler/rustc_attr_data_structures/src/stability.rs18
-rw-r--r--compiler/rustc_attr_data_structures/src/version.rs8
-rw-r--r--compiler/rustc_attr_parsing/Cargo.toml2
-rw-r--r--compiler/rustc_attr_parsing/messages.ftl23
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs92
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/cfg.rs34
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/confusables.rs65
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/deprecation.rs214
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/mod.rs169
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/repr.rs381
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/stability.rs471
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/transparency.rs55
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/util.rs24
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs348
-rw-r--r--compiler/rustc_attr_parsing/src/lib.rs131
-rw-r--r--compiler/rustc_attr_parsing/src/parser.rs624
-rw-r--r--compiler/rustc_attr_parsing/src/session_diagnostics.rs72
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/trace.rs9
-rw-r--r--compiler/rustc_builtin_macros/Cargo.toml1
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs15
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core.rs65
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs4
-rw-r--r--compiler/rustc_codegen_gcc/example/mini_core.rs65
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/abort1.rs5
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/abort2.rs5
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/assign.rs5
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/mut_ref.rs5
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/operations.rs5
-rw-r--r--compiler/rustc_codegen_gcc/tests/run/static.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/assert_module_sources.rs12
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs5
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs125
-rw-r--r--compiler/rustc_const_eval/src/check_consts/mod.rs6
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0094.md14
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0374.md53
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0375.md47
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0376.md38
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0377.md23
-rw-r--r--compiler/rustc_errors/Cargo.toml1
-rw-r--r--compiler/rustc_errors/src/diagnostic_impls.rs7
-rw-r--r--compiler/rustc_expand/Cargo.toml1
-rw-r--r--compiler/rustc_expand/src/base.rs33
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs20
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs4
-rw-r--r--compiler/rustc_feature/src/removed.rs9
-rw-r--r--compiler/rustc_feature/src/unstable.rs8
-rw-r--r--compiler/rustc_hir/Cargo.toml1
-rw-r--r--compiler/rustc_hir/src/hir.rs196
-rw-r--r--compiler/rustc_hir/src/stable_hash_impls.rs16
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl16
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs37
-rw-r--r--compiler/rustc_hir_analysis/src/check/entry.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs25
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs170
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/mod.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect/dump.rs15
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs70
-rw-r--r--compiler/rustc_hir_pretty/Cargo.toml1
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs110
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs6
-rw-r--r--compiler/rustc_incremental/src/assert_dep_graph.rs10
-rw-r--r--compiler/rustc_incremental/src/persist/dirty_clean.rs19
-rw-r--r--compiler/rustc_lint/src/builtin.rs4
-rw-r--r--compiler/rustc_lint/src/expect.rs3
-rw-r--r--compiler/rustc_lint/src/foreign_modules.rs2
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs15
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs22
-rw-r--r--compiler/rustc_macros/src/lib.rs9
-rw-r--r--compiler/rustc_macros/src/print_attribute.rs145
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs1
-rw-r--r--compiler/rustc_middle/src/traits/specialization_graph.rs2
-rw-r--r--compiler/rustc_middle/src/ty/context.rs2
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs28
-rw-r--r--compiler/rustc_middle/src/ty/util.rs13
-rw-r--r--compiler/rustc_mir_transform/src/coverage/query.rs2
-rw-r--r--compiler/rustc_passes/messages.ftl15
-rw-r--r--compiler/rustc_passes/src/check_attr.rs929
-rw-r--r--compiler/rustc_passes/src/entry.rs2
-rw-r--r--compiler/rustc_passes/src/errors.rs48
-rw-r--r--compiler/rustc_passes/src/lib_features.rs79
-rw-r--r--compiler/rustc_passes/src/stability.rs47
-rw-r--r--compiler/rustc_privacy/src/lib.rs7
-rw-r--r--compiler/rustc_query_impl/Cargo.toml1
-rw-r--r--compiler/rustc_query_system/Cargo.toml1
-rw-r--r--compiler/rustc_query_system/src/ich/hcx.rs1
-rw-r--r--compiler/rustc_query_system/src/ich/impls_syntax.rs18
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs19
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs2
-rw-r--r--compiler/rustc_resolve/src/macros.rs3
-rw-r--r--compiler/rustc_sanitizers/Cargo.toml1
-rw-r--r--compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs4
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context.rs40
-rw-r--r--compiler/rustc_span/src/hygiene.rs6
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--compiler/rustc_symbol_mangling/Cargo.toml1
-rw-r--r--compiler/rustc_symbol_mangling/src/test.rs8
-rw-r--r--compiler/rustc_target/src/target_features.rs5
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs3
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs23
-rw-r--r--compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs21
-rw-r--r--compiler/stable_mir/src/compiler_interface.rs13
-rw-r--r--compiler/stable_mir/src/crate_def.rs17
-rw-r--r--library/alloc/src/boxed.rs5
-rw-r--r--library/core/src/ffi/va_list.rs15
-rw-r--r--library/core/src/intrinsics/mod.rs1430
-rw-r--r--library/core/src/intrinsics/simd.rs340
-rw-r--r--library/core/src/marker.rs1
-rw-r--r--library/std/src/env.rs4
-rw-r--r--library/std/src/fs/tests.rs4
m---------src/doc/book0
m---------src/doc/edition-guide0
m---------src/doc/nomicon0
m---------src/doc/reference0
-rw-r--r--src/doc/unstable-book/src/language-features/intrinsics.md14
-rw-r--r--src/librustdoc/clean/mod.rs12
-rw-r--r--src/librustdoc/clean/types.rs2
-rw-r--r--src/librustdoc/doctest/rust.rs2
-rw-r--r--src/rustdoc-json-types/lib.rs6
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/inline_always.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs42
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/utils.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/default_union_representation.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_macros.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/mod.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/four_forward_slashes.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/large_include_file.rs59
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/macro_use.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs3
-rw-r--r--src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr18
-rw-r--r--src/tools/clippy/tests/ui/must_use_unit.fixed5
-rw-r--r--src/tools/clippy/tests/ui/must_use_unit.rs5
-rw-r--r--src/tools/clippy/tests/ui/must_use_unit.stderr18
-rw-r--r--src/tools/clippy/tests/ui/must_use_unit_12320.rs11
-rw-r--r--src/tools/clippy/tests/ui/must_use_unit_12320.stderr28
-rw-r--r--src/tools/miri/src/intrinsics/simd.rs4
-rw-r--r--src/tools/miri/tests/pass/intrinsics/portable-simd.rs6
-rw-r--r--src/tools/tidy/src/issues.txt1
-rw-r--r--tests/assembly/dwarf-mixed-versions-lto.rs7
-rw-r--r--tests/assembly/rust-abi-arg-attr.rs5
-rw-r--r--tests/pretty/hir-pretty-attr.pp11
-rw-r--r--tests/pretty/hir-pretty-attr.rs7
-rw-r--r--tests/rustdoc-json/enums/discriminant/struct.rs2
-rw-r--r--tests/rustdoc-json/enums/discriminant/tuple.rs2
-rw-r--r--tests/rustdoc/const-intrinsic.rs10
-rw-r--r--tests/rustdoc/safe-intrinsic.rs10
-rw-r--r--tests/ui-fulldeps/stable-mir/check_attribute.rs44
-rw-r--r--tests/ui-fulldeps/stable-mir/check_intrinsics.rs6
-rw-r--r--tests/ui/asm/conditionally-sized-ptr-fail.rs19
-rw-r--r--tests/ui/asm/conditionally-sized-ptr-fail.stderr18
-rw-r--r--tests/ui/asm/conditionally-sized-ptr.rs12
-rw-r--r--tests/ui/attributes/arg-error-issue-121425.stderr12
-rw-r--r--tests/ui/attributes/issue-100631.stderr4
-rw-r--r--tests/ui/attributes/malformed-fn-align.rs7
-rw-r--r--tests/ui/attributes/malformed-fn-align.stderr9
-rw-r--r--tests/ui/attributes/mixed_export_name_and_no_mangle.fixed2
-rw-r--r--tests/ui/attributes/mixed_export_name_and_no_mangle.rs2
-rw-r--r--tests/ui/attributes/mixed_export_name_and_no_mangle.stderr6
-rw-r--r--tests/ui/attributes/nonterminal-expansion.rs2
-rw-r--r--tests/ui/attributes/nonterminal-expansion.stderr9
-rw-r--r--tests/ui/attributes/repr-align-in-trait-issue-132391.rs6
-rw-r--r--tests/ui/attributes/repr-align-in-trait-issue-132391.stderr9
-rw-r--r--tests/ui/attributes/rustc_confusables.stderr12
-rw-r--r--tests/ui/check-cfg/target_feature.stderr5
-rw-r--r--tests/ui/coercion/issue-26905.stderr13
-rw-r--r--tests/ui/coherence/coherence-unsafe-trait-object-impl.rs18
-rw-r--r--tests/ui/coherence/coherence-unsafe-trait-object-impl.stderr22
-rw-r--r--tests/ui/const-generics/issues/cg-in-dyn-issue-128176.rs4
-rw-r--r--tests/ui/const-generics/issues/cg-in-dyn-issue-128176.stderr19
-rw-r--r--tests/ui/deprecation/deprecation-sanity.rs8
-rw-r--r--tests/ui/deprecation/deprecation-sanity.stderr32
-rw-r--r--tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs2
-rw-r--r--tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr10
-rw-r--r--tests/ui/deriving/deriving-coerce-pointee-neg.rs23
-rw-r--r--tests/ui/deriving/deriving-coerce-pointee-neg.stderr54
-rw-r--r--tests/ui/dropck/dropck-after-failed-type-lowering.rs14
-rw-r--r--tests/ui/dropck/dropck-after-failed-type-lowering.stderr19
-rw-r--r--tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr20
-rw-r--r--tests/ui/dyn-compatibility/associated-consts.rs6
-rw-r--r--tests/ui/dyn-compatibility/associated-consts.stderr (renamed from tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr)27
-rw-r--r--tests/ui/dyn-compatibility/generics.rs15
-rw-r--r--tests/ui/dyn-compatibility/generics.stderr85
-rw-r--r--tests/ui/dyn-compatibility/mentions-Self.curr.stderr16
-rw-r--r--tests/ui/dyn-compatibility/mentions-Self.rs8
-rw-r--r--tests/ui/dyn-compatibility/mentions-Self.stderr69
-rw-r--r--tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr28
-rw-r--r--tests/ui/dyn-compatibility/no-static.rs8
-rw-r--r--tests/ui/dyn-compatibility/no-static.stderr76
-rw-r--r--tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr19
-rw-r--r--tests/ui/dyn-compatibility/sized-2.rs6
-rw-r--r--tests/ui/dyn-compatibility/sized-2.stderr (renamed from tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr)33
-rw-r--r--tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr19
-rw-r--r--tests/ui/dyn-compatibility/sized.rs6
-rw-r--r--tests/ui/dyn-compatibility/sized.stderr34
-rw-r--r--tests/ui/dyn-compatibility/taint-const-eval.dyn_compatible_for_dispatch.stderr27
-rw-r--r--tests/ui/dyn-compatibility/taint-const-eval.rs8
-rw-r--r--tests/ui/dyn-compatibility/taint-const-eval.stderr74
-rw-r--r--tests/ui/error-codes/E0084.stderr4
-rw-r--r--tests/ui/error-codes/E0094.rs7
-rw-r--r--tests/ui/error-codes/E0094.stderr4
-rw-r--r--tests/ui/error-codes/E0308.rs7
-rw-r--r--tests/ui/error-codes/E0308.stderr4
-rw-r--r--tests/ui/error-codes/E0374.stderr2
-rw-r--r--tests/ui/error-codes/E0375.stderr13
-rw-r--r--tests/ui/error-codes/E0376.rs10
-rw-r--r--tests/ui/error-codes/E0376.stderr9
-rw-r--r--tests/ui/error-codes/E0565.stderr4
-rw-r--r--tests/ui/error-codes/E0789.rs2
-rw-r--r--tests/ui/error-codes/E0789.stderr10
-rw-r--r--tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.rs4
-rw-r--r--tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr12
-rw-r--r--tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.rs41
-rw-r--r--tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr88
-rw-r--r--tests/ui/feature-gates/feature-gate-fn_align.rs2
-rw-r--r--tests/ui/feature-gates/feature-gate-fn_align.stderr19
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr30
-rw-r--r--tests/ui/internal/internal-unstable.rs4
-rw-r--r--tests/ui/internal/internal-unstable.stderr14
-rw-r--r--tests/ui/intrinsics/always-gets-overridden.rs4
-rw-r--r--tests/ui/invalid_dispatch_from_dyn_impls.rs14
-rw-r--r--tests/ui/invalid_dispatch_from_dyn_impls.stderr28
-rw-r--r--tests/ui/issues/issue-43988.stderr32
-rw-r--r--tests/ui/kindck/kindck-inherited-copy-bound.rs12
-rw-r--r--tests/ui/kindck/kindck-inherited-copy-bound.stderr (renamed from tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr)29
-rw-r--r--tests/ui/repr/16-bit-repr-c-enum.rs5
-rw-r--r--tests/ui/repr/invalid_repr_list_help.stderr16
-rw-r--r--tests/ui/repr/issue-83505-repr-simd.stderr4
-rw-r--r--tests/ui/repr/malformed-repr-hints.stderr24
-rw-r--r--tests/ui/repr/repr-align-assign.fixed2
-rw-r--r--tests/ui/repr/repr-align-assign.rs2
-rw-r--r--tests/ui/repr/repr-align-assign.stderr20
-rw-r--r--tests/ui/repr/repr-align.rs8
-rw-r--r--tests/ui/repr/repr-align.stderr78
-rw-r--r--tests/ui/repr/repr-transparent.stderr4
-rw-r--r--tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/downcast-unsafe-trait-objects.rs23
-rw-r--r--tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/manual-self-impl-for-unsafe-obj.current.stderr15
-rw-r--r--tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/manual-self-impl-for-unsafe-obj.next.stderr15
-rw-r--r--tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/manual-self-impl-for-unsafe-obj.rs69
-rw-r--r--tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/static-dispatch-unsafe-object.rs37
-rw-r--r--tests/ui/rust-2021/ice-return-unsized-can-impl-2.rs4
-rw-r--r--tests/ui/rust-2021/ice-return-unsized-can-impl-2.stderr4
-rw-r--r--tests/ui/rust-2021/ice-return-unsized-can-impl.rs1
-rw-r--r--tests/ui/rust-2021/ice-return-unsized-can-impl.stderr4
-rw-r--r--tests/ui/rust-2021/ice-unsized-fn-params-2.rs2
-rw-r--r--tests/ui/rust-2021/ice-unsized-fn-params.rs1
-rw-r--r--tests/ui/rust-2021/ice-unsized-fn-params.stderr8
-rw-r--r--tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr23
-rw-r--r--tests/ui/self/arbitrary-self-types-dyn-incompatible.rs9
-rw-r--r--tests/ui/self/arbitrary-self-types-dyn-incompatible.stderr42
-rw-r--r--tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.rs2
-rw-r--r--tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.stderr13
-rw-r--r--tests/ui/self/dispatch-from-dyn-zst-transmute.rs2
-rw-r--r--tests/ui/self/dispatch-from-dyn-zst-transmute.stderr13
-rw-r--r--tests/ui/simd/intrinsic/generic-elements.rs20
-rw-r--r--tests/ui/simd/intrinsic/generic-elements.stderr54
-rw-r--r--tests/ui/simd/monomorphize-shuffle-index.generic.stderr10
-rw-r--r--tests/ui/simd/monomorphize-shuffle-index.rs6
-rw-r--r--tests/ui/stability-attribute/stability-attribute-sanity.rs8
-rw-r--r--tests/ui/stability-attribute/stability-attribute-sanity.stderr32
-rw-r--r--tests/ui/suggestions/issue-104328.rs12
-rw-r--r--tests/ui/suggestions/issue-104328.stderr17
-rw-r--r--tests/ui/target-feature/feature-hierarchy.rs5
-rw-r--r--tests/ui/traits/issue-78372.stderr4
-rw-r--r--tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.rs18
-rw-r--r--tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr54
-rw-r--r--tests/ui/wf/wf-convert-dyn-incompat-trait-obj.rs18
-rw-r--r--tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr54
-rw-r--r--tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs29
-rw-r--r--tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr60
302 files changed, 5362 insertions, 5161 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 1dc403904ce..fb4cf235c6f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3207,6 +3207,7 @@ dependencies = [
  "rustc_abi",
  "rustc_ast",
  "rustc_ast_pretty",
+ "rustc_attr_parsing",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_feature",
@@ -3215,6 +3216,7 @@ dependencies = [
  "rustc_index",
  "rustc_macros",
  "rustc_middle",
+ "rustc_parse",
  "rustc_session",
  "rustc_span",
  "rustc_target",
@@ -3263,14 +3265,10 @@ dependencies = [
  "rustc_ast",
  "rustc_ast_pretty",
  "rustc_data_structures",
- "rustc_errors",
- "rustc_feature",
- "rustc_fluent_macro",
- "rustc_lexer",
  "rustc_macros",
  "rustc_serialize",
- "rustc_session",
  "rustc_span",
+ "thin-vec",
 ]
 
 [[package]]
@@ -3285,11 +3283,13 @@ dependencies = [
  "rustc_errors",
  "rustc_feature",
  "rustc_fluent_macro",
+ "rustc_hir",
  "rustc_lexer",
  "rustc_macros",
  "rustc_serialize",
  "rustc_session",
  "rustc_span",
+ "thin-vec",
 ]
 
 [[package]]
@@ -3342,6 +3342,7 @@ dependencies = [
  "rustc_expand",
  "rustc_feature",
  "rustc_fluent_macro",
+ "rustc_hir",
  "rustc_index",
  "rustc_lexer",
  "rustc_lint_defs",
@@ -3598,6 +3599,7 @@ dependencies = [
  "rustc_abi",
  "rustc_ast",
  "rustc_ast_pretty",
+ "rustc_attr_data_structures",
  "rustc_data_structures",
  "rustc_error_codes",
  "rustc_error_messages",
@@ -3632,6 +3634,7 @@ dependencies = [
  "rustc_errors",
  "rustc_feature",
  "rustc_fluent_macro",
+ "rustc_hir",
  "rustc_lexer",
  "rustc_lint_defs",
  "rustc_macros",
@@ -3690,6 +3693,7 @@ dependencies = [
  "rustc_abi",
  "rustc_arena",
  "rustc_ast",
+ "rustc_attr_data_structures",
  "rustc_data_structures",
  "rustc_hashes",
  "rustc_index",
@@ -3737,6 +3741,7 @@ dependencies = [
  "rustc_abi",
  "rustc_ast",
  "rustc_ast_pretty",
+ "rustc_attr_parsing",
  "rustc_hir",
  "rustc_span",
 ]
@@ -4244,6 +4249,7 @@ name = "rustc_query_impl"
 version = "0.0.0"
 dependencies = [
  "measureme",
+ "rustc_attr_data_structures",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_hashes",
@@ -4266,6 +4272,7 @@ dependencies = [
  "rustc-rayon-core",
  "rustc_abi",
  "rustc_ast",
+ "rustc_attr_data_structures",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_feature",
@@ -4316,6 +4323,7 @@ version = "0.0.0"
 dependencies = [
  "bitflags",
  "rustc_abi",
+ "rustc_ast",
  "rustc_data_structures",
  "rustc_hir",
  "rustc_middle",
@@ -4412,6 +4420,7 @@ dependencies = [
  "punycode",
  "rustc-demangle",
  "rustc_abi",
+ "rustc_ast",
  "rustc_data_structures",
  "rustc_errors",
  "rustc_hashes",
diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml
index 3215ce6b0cb..2ec4f4b0555 100644
--- a/compiler/rustc_ast_lowering/Cargo.toml
+++ b/compiler/rustc_ast_lowering/Cargo.toml
@@ -11,6 +11,7 @@ doctest = false
 rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
+rustc_attr_parsing = { path = "../rustc_attr_parsing" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_feature = { path = "../rustc_feature" }
@@ -19,6 +20,7 @@ rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_middle = { path = "../rustc_middle" }
+rustc_parse = { path = "../rustc_parse" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs
index 88ce6f80e10..1d9ca6bb9c8 100644
--- a/compiler/rustc_ast_lowering/src/block.rs
+++ b/compiler/rustc_ast_lowering/src/block.rs
@@ -108,7 +108,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         };
         let span = self.lower_span(l.span);
         let source = hir::LocalSource::Normal;
-        self.lower_attrs(hir_id, &l.attrs);
+        self.lower_attrs(hir_id, &l.attrs, l.span);
         self.arena.alloc(hir::LetStmt { hir_id, ty, pat, init, els, span, source })
     }
 
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index af53c7ec215..efbd1711daa 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -77,9 +77,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         self.attrs.insert(
                             ex.hir_id.local_id,
                             &*self.arena.alloc_from_iter(
-                                e.attrs
-                                    .iter()
-                                    .map(|a| self.lower_attr(a))
+                                self.lower_attrs_vec(&e.attrs, e.span)
+                                    .into_iter()
                                     .chain(old_attrs.iter().cloned()),
                             ),
                         );
@@ -98,7 +97,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             }
 
             let expr_hir_id = self.lower_node_id(e.id);
-            self.lower_attrs(expr_hir_id, &e.attrs);
+            self.lower_attrs(expr_hir_id, &e.attrs, e.span);
 
             let kind = match &e.kind {
                 ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)),
@@ -670,7 +669,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let guard = arm.guard.as_ref().map(|cond| self.lower_expr(cond));
         let hir_id = self.next_id();
         let span = self.lower_span(arm.span);
-        self.lower_attrs(hir_id, &arm.attrs);
+        self.lower_attrs(hir_id, &arm.attrs, arm.span);
         let is_never_pattern = pat.is_never_pattern();
         let body = if let Some(body) = &arm.body
             && !is_never_pattern
@@ -839,6 +838,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     style: AttrStyle::Outer,
                     span: unstable_span,
                 }],
+                span,
             );
         }
     }
@@ -1673,7 +1673,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
     fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> {
         let hir_id = self.lower_node_id(f.id);
-        self.lower_attrs(hir_id, &f.attrs);
+        self.lower_attrs(hir_id, &f.attrs, f.span);
         hir::ExprField {
             hir_id,
             ident: self.lower_ident(f.ident),
@@ -1936,7 +1936,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         //
         // Also, add the attributes to the outer returned expr node.
         let expr = self.expr_drop_temps_mut(for_span, match_expr);
-        self.lower_attrs(expr.hir_id, &e.attrs);
+        self.lower_attrs(expr.hir_id, &e.attrs, e.span);
         expr
     }
 
@@ -1993,7 +1993,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             let val_ident = Ident::with_dummy_span(sym::val);
             let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident);
             let val_expr = self.expr_ident(span, val_ident, val_pat_nid);
-            self.lower_attrs(val_expr.hir_id, &attrs);
+            self.lower_attrs(val_expr.hir_id, &attrs, span);
             let continue_pat = self.pat_cf_continue(unstable_span, val_pat);
             self.arm(continue_pat, val_expr)
         };
@@ -2024,7 +2024,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 let ret_expr = self.checked_return(Some(from_residual_expr));
                 self.arena.alloc(self.expr(try_span, ret_expr))
             };
-            self.lower_attrs(ret_expr.hir_id, &attrs);
+            self.lower_attrs(ret_expr.hir_id, &attrs, ret_expr.span);
 
             let break_pat = self.pat_cf_break(try_span, residual_local);
             self.arm(break_pat, ret_expr)
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 1d3db64b47e..a4fc4b3e3a1 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -11,7 +11,7 @@ use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::span_bug;
 use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
 use rustc_span::edit_distance::find_best_match_for_name;
-use rustc_span::{DesugaringKind, Ident, Span, Symbol, kw, sym};
+use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym};
 use smallvec::{SmallVec, smallvec};
 use thin_vec::ThinVec;
 use tracing::instrument;
@@ -93,7 +93,8 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
         debug_assert_eq!(self.resolver.node_id_to_def_id[&CRATE_NODE_ID], CRATE_DEF_ID);
         self.with_lctx(CRATE_NODE_ID, |lctx| {
             let module = lctx.lower_mod(&c.items, &c.spans);
-            lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs);
+            // FIXME(jdonszelman): is dummy span ever a problem here?
+            lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs, DUMMY_SP);
             hir::OwnerNode::Crate(module)
         })
     }
@@ -157,7 +158,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let mut ident = i.ident;
         let vis_span = self.lower_span(i.vis.span);
         let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
-        let attrs = self.lower_attrs(hir_id, &i.attrs);
+        let attrs = self.lower_attrs(hir_id, &i.attrs, i.span);
         let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, vis_span, &i.kind);
         let item = hir::Item {
             owner_id: hir_id.expect_owner(),
@@ -620,7 +621,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> {
         let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
         let owner_id = hir_id.expect_owner();
-        let attrs = self.lower_attrs(hir_id, &i.attrs);
+        let attrs = self.lower_attrs(hir_id, &i.attrs, i.span);
         let item = hir::ForeignItem {
             owner_id,
             ident: self.lower_ident(i.ident),
@@ -678,7 +679,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
     fn lower_variant(&mut self, v: &Variant) -> hir::Variant<'hir> {
         let hir_id = self.lower_node_id(v.id);
-        self.lower_attrs(hir_id, &v.attrs);
+        self.lower_attrs(hir_id, &v.attrs, v.span);
         hir::Variant {
             hir_id,
             def_id: self.local_def_id(v.id),
@@ -740,7 +741,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     ) -> hir::FieldDef<'hir> {
         let ty = self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy));
         let hir_id = self.lower_node_id(f.id);
-        self.lower_attrs(hir_id, &f.attrs);
+        self.lower_attrs(hir_id, &f.attrs, f.span);
         hir::FieldDef {
             span: self.lower_span(f.span),
             hir_id,
@@ -759,7 +760,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
     fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> {
         let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
-        let attrs = self.lower_attrs(hir_id, &i.attrs);
+        let attrs = self.lower_attrs(hir_id, &i.attrs, i.span);
         let trait_item_def_id = hir_id.expect_owner();
 
         let (generics, kind, has_default) = match &i.kind {
@@ -895,7 +896,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let has_value = true;
         let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value);
         let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id);
-        let attrs = self.lower_attrs(hir_id, &i.attrs);
+        let attrs = self.lower_attrs(hir_id, &i.attrs, i.span);
 
         let (generics, kind) = match &i.kind {
             AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics(
@@ -1056,7 +1057,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
 
     fn lower_param(&mut self, param: &Param) -> hir::Param<'hir> {
         let hir_id = self.lower_node_id(param.id);
-        self.lower_attrs(hir_id, &param.attrs);
+        self.lower_attrs(hir_id, &param.attrs, param.span);
         hir::Param {
             hir_id,
             pat: self.lower_pat(&param.pat),
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index b865cbedbbb..1c69937eed0 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -45,6 +45,7 @@ use std::sync::Arc;
 
 use rustc_ast::node_id::NodeMap;
 use rustc_ast::{self as ast, *};
+use rustc_attr_parsing::{AttributeParser, OmitDoc};
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -60,7 +61,8 @@ use rustc_macros::extension;
 use rustc_middle::span_bug;
 use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
 use rustc_session::parse::{add_feature_diagnostics, feature_err};
-use rustc_span::{DUMMY_SP, DesugaringKind, Ident, Span, Symbol, kw, sym};
+use rustc_span::symbol::{Ident, Symbol, kw, sym};
+use rustc_span::{DUMMY_SP, DesugaringKind, Span};
 use smallvec::{SmallVec, smallvec};
 use thin_vec::ThinVec;
 use tracing::{debug, instrument, trace};
@@ -137,10 +139,13 @@ struct LoweringContext<'a, 'hir> {
     allow_async_iterator: Arc<[Symbol]>,
     allow_for_await: Arc<[Symbol]>,
     allow_async_fn_traits: Arc<[Symbol]>,
+
+    attribute_parser: AttributeParser<'hir>,
 }
 
 impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn new(tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering) -> Self {
+        let registered_tools = tcx.registered_tools(()).iter().map(|x| x.name).collect();
         Self {
             // Pseudo-globals.
             tcx,
@@ -181,6 +186,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             // FIXME(gen_blocks): how does `closure_track_caller`/`async_fn_track_caller`
             // interact with `gen`/`async gen` blocks
             allow_async_iterator: [sym::gen_future, sym::async_iterator].into(),
+
+            attribute_parser: AttributeParser::new(tcx.sess, tcx.features(), registered_tools),
         }
     }
 
@@ -216,7 +223,6 @@ impl ResolverAstLowering {
         None
     }
 
-    /// Obtains resolution for a `NodeId` with a single resolution.
     fn get_partial_res(&self, id: NodeId) -> Option<PartialRes> {
         self.partial_res_map.get(&id).copied()
     }
@@ -855,45 +861,38 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         ret
     }
 
-    fn lower_attrs(&mut self, id: HirId, attrs: &[Attribute]) -> &'hir [hir::Attribute] {
+    fn lower_attrs(
+        &mut self,
+        id: HirId,
+        attrs: &[Attribute],
+        target_span: Span,
+    ) -> &'hir [hir::Attribute] {
         if attrs.is_empty() {
             &[]
         } else {
+            let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span));
+
             debug_assert_eq!(id.owner, self.current_hir_id_owner);
-            let ret = self.arena.alloc_from_iter(attrs.iter().map(|a| self.lower_attr(a)));
-            debug_assert!(!ret.is_empty());
-            self.attrs.insert(id.local_id, ret);
-            ret
+            let ret = self.arena.alloc_from_iter(lowered_attrs);
+
+            // this is possible if an item contained syntactical attribute,
+            // but none of them parse succesfully or all of them were ignored
+            // for not being built-in attributes at all. They could be remaining
+            // unexpanded attributes used as markers in proc-macro derives for example.
+            // This will have emitted some diagnostics for the misparse, but will then
+            // not emit the attribute making the list empty.
+            if ret.is_empty() {
+                &[]
+            } else {
+                self.attrs.insert(id.local_id, ret);
+                ret
+            }
         }
     }
 
-    fn lower_attr(&self, attr: &Attribute) -> hir::Attribute {
-        // Note that we explicitly do not walk the path. Since we don't really
-        // lower attributes (we use the AST version) there is nowhere to keep
-        // the `HirId`s. We don't actually need HIR version of attributes anyway.
-        // Tokens are also not needed after macro expansion and parsing.
-        let kind = match attr.kind {
-            AttrKind::Normal(ref normal) => hir::AttrKind::Normal(Box::new(hir::AttrItem {
-                unsafety: self.lower_safety(normal.item.unsafety, hir::Safety::Safe),
-                path: hir::AttrPath {
-                    segments: normal
-                        .item
-                        .path
-                        .segments
-                        .iter()
-                        .map(|i| i.ident)
-                        .collect::<Vec<_>>()
-                        .into_boxed_slice(),
-                    span: normal.item.path.span,
-                },
-                args: self.lower_attr_args(&normal.item.args),
-            })),
-            AttrKind::DocComment(comment_kind, data) => {
-                hir::AttrKind::DocComment(comment_kind, data)
-            }
-        };
-
-        hir::Attribute { kind, id: attr.id, style: attr.style, span: self.lower_span(attr.span) }
+    fn lower_attrs_vec(&self, attrs: &[Attribute], target_span: Span) -> Vec<hir::Attribute> {
+        self.attribute_parser
+            .parse_attribute_list(attrs, target_span, OmitDoc::Lower, |s| self.lower_span(s))
     }
 
     fn alias_attrs(&mut self, id: HirId, target_id: HirId) {
@@ -905,34 +904,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         }
     }
 
-    fn lower_attr_args(&self, args: &AttrArgs) -> hir::AttrArgs {
-        match args {
-            AttrArgs::Empty => hir::AttrArgs::Empty,
-            AttrArgs::Delimited(args) => hir::AttrArgs::Delimited(self.lower_delim_args(args)),
-            // This is an inert key-value attribute - it will never be visible to macros
-            // after it gets lowered to HIR. Therefore, we can extract literals to handle
-            // nonterminals in `#[doc]` (e.g. `#[doc = $e]`).
-            &AttrArgs::Eq { eq_span, ref expr } => {
-                // In valid code the value always ends up as a single literal. Otherwise, a dummy
-                // literal suffices because the error is handled elsewhere.
-                let lit = if let ExprKind::Lit(token_lit) = expr.kind
-                    && let Ok(lit) = MetaItemLit::from_token_lit(token_lit, expr.span)
-                {
-                    lit
-                } else {
-                    let guar = self.dcx().has_errors().unwrap();
-                    MetaItemLit {
-                        symbol: kw::Empty,
-                        suffix: None,
-                        kind: LitKind::Err(guar),
-                        span: DUMMY_SP,
-                    }
-                };
-                hir::AttrArgs::Eq { eq_span, expr: lit }
-            }
-        }
-    }
-
     fn lower_delim_args(&self, args: &DelimArgs) -> DelimArgs {
         DelimArgs { dspan: args.dspan, delim: args.delim, tokens: args.tokens.flattened() }
     }
@@ -1845,7 +1816,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let (name, kind) = self.lower_generic_param_kind(param, source);
 
         let hir_id = self.lower_node_id(param.id);
-        self.lower_attrs(hir_id, &param.attrs);
+        self.lower_attrs(hir_id, &param.attrs, param.span());
         hir::GenericParam {
             hir_id,
             def_id: self.local_def_id(param.id),
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index e1f3afbcf59..2dcfe7c745d 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -93,7 +93,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
                         let fs = self.arena.alloc_from_iter(fields.iter().map(|f| {
                             let hir_id = self.lower_node_id(f.id);
-                            self.lower_attrs(hir_id, &f.attrs);
+                            self.lower_attrs(hir_id, &f.attrs, f.span);
 
                             hir::PatField {
                                 hir_id,
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 5a0ec865f9d..25944392a52 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -207,8 +207,6 @@ ast_passes_precise_capturing_duplicated = duplicate `use<...>` precise capturing
 
 ast_passes_precise_capturing_not_allowed_here = `use<...>` precise capturing syntax not allowed in {$loc}
 
-ast_passes_stability_outside_std = stability attributes may not be used outside of the standard library
-
 ast_passes_static_without_body =
     free static item without body
     .suggestion = provide a definition for the static
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 6eb9bb1c0da..9f0d2325475 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -733,13 +733,6 @@ pub(crate) struct AssociatedSuggestion2 {
 }
 
 #[derive(Diagnostic)]
-#[diag(ast_passes_stability_outside_std, code = E0734)]
-pub(crate) struct StabilityOutsideStd {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(ast_passes_feature_on_non_nightly, code = E0554)]
 pub(crate) struct FeatureOnNonNightly {
     #[primary_span]
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index e5d8013058f..0f80e49320e 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -178,18 +178,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 );
             }
         }
-
-        // Emit errors for non-staged-api crates.
-        if !self.features.staged_api() {
-            if attr.has_name(sym::unstable)
-                || attr.has_name(sym::stable)
-                || attr.has_name(sym::rustc_const_unstable)
-                || attr.has_name(sym::rustc_const_stable)
-                || attr.has_name(sym::rustc_default_body_unstable)
-            {
-                self.sess.dcx().emit_err(errors::StabilityOutsideStd { span: attr.span });
-            }
-        }
     }
 
     fn visit_item(&mut self, i: &'a ast::Item) {
diff --git a/compiler/rustc_attr_data_structures/Cargo.toml b/compiler/rustc_attr_data_structures/Cargo.toml
index 19d0d5a306d..b18923c337f 100644
--- a/compiler/rustc_attr_data_structures/Cargo.toml
+++ b/compiler/rustc_attr_data_structures/Cargo.toml
@@ -5,16 +5,12 @@ edition = "2024"
 
 [dependencies]
 # tidy-alphabetical-start
-rustc_abi = { path = "../rustc_abi" }
-rustc_ast = { path = "../rustc_ast" }
-rustc_ast_pretty = { path = "../rustc_ast_pretty" }
-rustc_data_structures = { path = "../rustc_data_structures" }
-rustc_errors = { path = "../rustc_errors" }
-rustc_feature = { path = "../rustc_feature" }
-rustc_fluent_macro = { path = "../rustc_fluent_macro" }
-rustc_lexer = { path = "../rustc_lexer" }
-rustc_macros = { path = "../rustc_macros" }
-rustc_serialize = { path = "../rustc_serialize" }
-rustc_session = { path = "../rustc_session" }
-rustc_span = { path = "../rustc_span" }
+rustc_abi = {path = "../rustc_abi"}
+rustc_ast = {path = "../rustc_ast"}
+rustc_ast_pretty = {path = "../rustc_ast_pretty"}
+rustc_data_structures = {path = "../rustc_data_structures"}
+rustc_macros = {path = "../rustc_macros"}
+rustc_serialize = {path = "../rustc_serialize"}
+rustc_span = {path = "../rustc_span"}
+thin-vec = "0.2.12"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index b4027a096c5..9ac8de0227d 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -1,9 +1,12 @@
 use rustc_abi::Align;
-use rustc_ast as ast;
-use rustc_macros::{Decodable, Encodable, HashStable_Generic};
+use rustc_ast::token::CommentKind;
+use rustc_ast::{self as ast, AttrStyle};
+use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute};
+use rustc_span::hygiene::Transparency;
 use rustc_span::{Span, Symbol};
+use thin_vec::ThinVec;
 
-use crate::RustcVersion;
+use crate::{DefaultBodyStability, PartialConstStability, PrintAttribute, RustcVersion, Stability};
 
 #[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum InlineAttr {
@@ -54,7 +57,7 @@ impl OptimizeAttr {
     }
 }
 
-#[derive(Clone, Debug, Encodable, Decodable)]
+#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic, PrintAttribute)]
 pub enum DiagnosticAttribute {
     // tidy-alphabetical-start
     DoNotRecommend,
@@ -62,7 +65,7 @@ pub enum DiagnosticAttribute {
     // tidy-alphabetical-end
 }
 
-#[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone)]
+#[derive(PartialEq, Debug, Encodable, Decodable, Copy, Clone, HashStable_Generic, PrintAttribute)]
 pub enum ReprAttr {
     ReprInt(IntType),
     ReprRust,
@@ -71,6 +74,8 @@ pub enum ReprAttr {
     ReprSimd,
     ReprTransparent,
     ReprAlign(Align),
+    // this one is just so we can emit a lint for it
+    ReprEmpty,
 }
 pub use ReprAttr::*;
 
@@ -80,13 +85,13 @@ pub enum TransparencyError {
 }
 
 #[derive(Eq, PartialEq, Debug, Copy, Clone)]
-#[derive(Encodable, Decodable)]
+#[derive(Encodable, Decodable, HashStable_Generic, PrintAttribute)]
 pub enum IntType {
     SignedInt(ast::IntTy),
     UnsignedInt(ast::UintTy),
 }
 
-#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)]
+#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)]
 pub struct Deprecation {
     pub since: DeprecatedSince,
     /// The note to issue a reason.
@@ -98,7 +103,7 @@ pub struct Deprecation {
 }
 
 /// Release in which an API is deprecated.
-#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic)]
+#[derive(Copy, Debug, Encodable, Decodable, Clone, HashStable_Generic, PrintAttribute)]
 pub enum DeprecatedSince {
     RustcVersion(RustcVersion),
     /// Deprecated in the future ("to be determined").
@@ -132,3 +137,61 @@ impl Deprecation {
         matches!(self.since, DeprecatedSince::RustcVersion(_))
     }
 }
+
+/// Attributes represent parsed, *built in*, inert attributes. That means,
+/// attributes that are not actually ever expanded.
+/// For more information on this, see the module docs on the rustc_attr_parsing crate.
+/// They're instead used as markers, to guide the compilation process in various way in most every stage of the compiler.
+/// These are kept around after the AST, into the HIR and further on.
+///
+/// The word parsed could be a little misleading here, because the parser already parses
+/// attributes early on. However, the result, an [`ast::Attribute`]
+/// is only parsed at a high level, still containing a token stream in many cases. That is
+/// because the structure of the contents varies from attribute to attribute.
+/// With a parsed attribute I mean that each attribute is processed individually into a
+/// final structure, which on-site (the place where the attribute is useful for, think the
+/// the place where `must_use` is checked) little to no extra parsing or validating needs to
+/// happen.
+///
+/// For more docs, look in [`rustc_attr`](https://doc.rust-lang.org/stable/nightly-rustc/rustc_attr/index.html)
+#[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
+pub enum AttributeKind {
+    // tidy-alphabetical-start
+    AllowConstFnUnstable(ThinVec<Symbol>),
+    AllowInternalUnstable(ThinVec<(Symbol, Span)>),
+    BodyStability {
+        stability: DefaultBodyStability,
+        /// Span of the `#[rustc_default_body_unstable(...)]` attribute
+        span: Span,
+    },
+    Confusables {
+        symbols: ThinVec<Symbol>,
+        // FIXME(jdonszelmann): remove when target validation code is moved
+        first_span: Span,
+    },
+    ConstStability {
+        stability: PartialConstStability,
+        /// Span of the `#[rustc_const_stable(...)]` or `#[rustc_const_unstable(...)]` attribute
+        span: Span,
+    },
+    ConstStabilityIndirect,
+    Deprecation {
+        deprecation: Deprecation,
+        span: Span,
+    },
+    Diagnostic(DiagnosticAttribute),
+    DocComment {
+        style: AttrStyle,
+        kind: CommentKind,
+        span: Span,
+        comment: Symbol,
+    },
+    MacroTransparency(Transparency),
+    Repr(ThinVec<(ReprAttr, Span)>),
+    Stability {
+        stability: Stability,
+        /// Span of the `#[stable(...)]` or `#[unstable(...)]` attribute
+        span: Span,
+    },
+    // tidy-alphabetical-end
+}
diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs
index 4f204aeab64..e4bb459e6df 100644
--- a/compiler/rustc_attr_data_structures/src/lib.rs
+++ b/compiler/rustc_attr_data_structures/src/lib.rs
@@ -10,7 +10,142 @@ mod attributes;
 mod stability;
 mod version;
 
+use std::num::NonZero;
+
 pub use attributes::*;
-pub(crate) use rustc_session::HashStableContext;
+use rustc_abi::Align;
+use rustc_ast::token::CommentKind;
+use rustc_ast::{AttrStyle, IntTy, UintTy};
+use rustc_ast_pretty::pp::Printer;
+use rustc_span::hygiene::Transparency;
+use rustc_span::{Span, Symbol};
 pub use stability::*;
+use thin_vec::ThinVec;
 pub use version::*;
+
+/// Requirements for a `StableHashingContext` to be used in this crate.
+/// This is a hack to allow using the `HashStable_Generic` derive macro
+/// instead of implementing everything in `rustc_middle`.
+pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStableContext {}
+
+/// This trait is used to print attributes in `rustc_hir_pretty`.
+///
+/// For structs and enums it can be derived using [`rustc_macros::PrintAttribute`].
+/// The output will look a lot like a `Debug` implementation, but fields of several types
+/// like [`Span`]s and empty tuples, are gracefully skipped so they don't clutter the
+/// representation much.
+pub trait PrintAttribute {
+    fn print_something(&self) -> bool;
+    fn print_attribute(&self, p: &mut Printer);
+}
+
+impl<T: PrintAttribute> PrintAttribute for &T {
+    fn print_something(&self) -> bool {
+        T::print_something(self)
+    }
+
+    fn print_attribute(&self, p: &mut Printer) {
+        T::print_attribute(self, p)
+    }
+}
+impl<T: PrintAttribute> PrintAttribute for Option<T> {
+    fn print_something(&self) -> bool {
+        self.as_ref().is_some_and(|x| x.print_something())
+    }
+    fn print_attribute(&self, p: &mut Printer) {
+        if let Some(i) = self {
+            T::print_attribute(i, p)
+        }
+    }
+}
+impl<T: PrintAttribute> PrintAttribute for ThinVec<T> {
+    fn print_something(&self) -> bool {
+        self.is_empty() || self[0].print_something()
+    }
+    fn print_attribute(&self, p: &mut Printer) {
+        let mut last_printed = false;
+        p.word("[");
+        for i in self {
+            if last_printed {
+                p.word_space(",");
+            }
+            i.print_attribute(p);
+            last_printed = i.print_something();
+        }
+        p.word("]");
+    }
+}
+macro_rules! print_skip {
+    ($($t: ty),* $(,)?) => {$(
+        impl PrintAttribute for $t {
+            fn print_something(&self) -> bool { false }
+            fn print_attribute(&self, _: &mut Printer) { }
+        })*
+    };
+}
+
+macro_rules! print_disp {
+    ($($t: ty),* $(,)?) => {$(
+        impl PrintAttribute for $t {
+            fn print_something(&self) -> bool { true }
+            fn print_attribute(&self, p: &mut Printer) {
+                p.word(format!("{}", self));
+            }
+        }
+    )*};
+}
+macro_rules! print_debug {
+    ($($t: ty),* $(,)?) => {$(
+        impl PrintAttribute for $t {
+            fn print_something(&self) -> bool { true }
+            fn print_attribute(&self, p: &mut Printer) {
+                p.word(format!("{:?}", self));
+            }
+        }
+    )*};
+}
+
+macro_rules! print_tup {
+    (num_print_something $($ts: ident)*) => { 0 $(+ $ts.print_something() as usize)* };
+    () => {};
+    ($t: ident $($ts: ident)*) => {
+        #[allow(non_snake_case, unused)]
+        impl<$t: PrintAttribute, $($ts: PrintAttribute),*> PrintAttribute for ($t, $($ts),*) {
+            fn print_something(&self) -> bool {
+                let ($t, $($ts),*) = self;
+                print_tup!(num_print_something $t $($ts)*) != 0
+            }
+
+            fn print_attribute(&self, p: &mut Printer) {
+                let ($t, $($ts),*) = self;
+                let parens = print_tup!(num_print_something $t $($ts)*) > 1;
+                if parens {
+                    p.word("(");
+                }
+
+                let mut printed_anything = $t.print_something();
+
+                $t.print_attribute(p);
+
+                $(
+                    if printed_anything && $ts.print_something() {
+                        p.word_space(",");
+                        printed_anything = true;
+                    }
+                    $ts.print_attribute(p);
+                )*
+
+                if parens {
+                    p.word(")");
+                }
+            }
+        }
+
+        print_tup!($($ts)*);
+    };
+}
+
+print_tup!(A B C D E F G H);
+print_skip!(Span, ());
+print_disp!(Symbol, u16, bool, NonZero<u32>);
+print_debug!(UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency);
diff --git a/compiler/rustc_attr_data_structures/src/stability.rs b/compiler/rustc_attr_data_structures/src/stability.rs
index c2213fc9ed8..c0ca08a60f8 100644
--- a/compiler/rustc_attr_data_structures/src/stability.rs
+++ b/compiler/rustc_attr_data_structures/src/stability.rs
@@ -1,9 +1,9 @@
 use std::num::NonZero;
 
-use rustc_macros::{Decodable, Encodable, HashStable_Generic};
+use rustc_macros::{Decodable, Encodable, HashStable_Generic, PrintAttribute};
 use rustc_span::{Symbol, sym};
 
-use crate::RustcVersion;
+use crate::{PrintAttribute, RustcVersion};
 
 /// The version placeholder that recently stabilized features contain inside the
 /// `since` field of the `#[stable]` attribute.
@@ -21,7 +21,7 @@ pub const VERSION_PLACEHOLDER: &str = concat!("CURRENT_RUSTC_VERSIO", "N");
 /// - `#[stable]`
 /// - `#[unstable]`
 #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
-#[derive(HashStable_Generic)]
+#[derive(HashStable_Generic, PrintAttribute)]
 pub struct Stability {
     pub level: StabilityLevel,
     pub feature: Symbol,
@@ -43,7 +43,7 @@ impl Stability {
 
 /// Represents the `#[rustc_const_unstable]` and `#[rustc_const_stable]` attributes.
 #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
-#[derive(HashStable_Generic)]
+#[derive(HashStable_Generic, PrintAttribute)]
 pub struct ConstStability {
     pub level: StabilityLevel,
     pub feature: Symbol,
@@ -83,7 +83,7 @@ impl ConstStability {
 /// Excludes `const_stable_indirect`. This is necessary because when `-Zforce-unstable-if-unmarked`
 /// is set, we need to encode standalone `#[rustc_const_stable_indirect]` attributes
 #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
-#[derive(HashStable_Generic)]
+#[derive(HashStable_Generic, PrintAttribute)]
 pub struct PartialConstStability {
     pub level: StabilityLevel,
     pub feature: Symbol,
@@ -103,7 +103,7 @@ impl PartialConstStability {
 
 /// The available stability levels.
 #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
-#[derive(HashStable_Generic)]
+#[derive(HashStable_Generic, PrintAttribute)]
 pub enum StabilityLevel {
     /// `#[unstable]`
     Unstable {
@@ -145,7 +145,7 @@ pub enum StabilityLevel {
 
 /// Rust release in which a feature is stabilized.
 #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, PartialOrd, Ord, Hash)]
-#[derive(HashStable_Generic)]
+#[derive(HashStable_Generic, PrintAttribute)]
 pub enum StableSince {
     /// also stores the original symbol for printing
     Version(RustcVersion),
@@ -171,7 +171,7 @@ impl StabilityLevel {
 }
 
 #[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)]
-#[derive(HashStable_Generic)]
+#[derive(HashStable_Generic, PrintAttribute)]
 pub enum UnstableReason {
     None,
     Default,
@@ -180,7 +180,7 @@ pub enum UnstableReason {
 
 /// Represents the `#[rustc_default_body_unstable]` attribute.
 #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, Hash)]
-#[derive(HashStable_Generic)]
+#[derive(HashStable_Generic, PrintAttribute)]
 pub struct DefaultBodyStability {
     pub level: StabilityLevel,
     pub feature: Symbol,
diff --git a/compiler/rustc_attr_data_structures/src/version.rs b/compiler/rustc_attr_data_structures/src/version.rs
index 6be875ad4be..69b0e041d81 100644
--- a/compiler/rustc_attr_data_structures/src/version.rs
+++ b/compiler/rustc_attr_data_structures/src/version.rs
@@ -1,9 +1,13 @@
 use std::fmt::{self, Display};
 
-use rustc_macros::{Decodable, Encodable, HashStable_Generic, current_rustc_version};
+use rustc_macros::{
+    Decodable, Encodable, HashStable_Generic, PrintAttribute, current_rustc_version,
+};
+
+use crate::PrintAttribute;
 
 #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[derive(HashStable_Generic)]
+#[derive(HashStable_Generic, PrintAttribute)]
 pub struct RustcVersion {
     pub major: u16,
     pub minor: u16,
diff --git a/compiler/rustc_attr_parsing/Cargo.toml b/compiler/rustc_attr_parsing/Cargo.toml
index f681e9397d9..c335eeb5f71 100644
--- a/compiler/rustc_attr_parsing/Cargo.toml
+++ b/compiler/rustc_attr_parsing/Cargo.toml
@@ -13,9 +13,11 @@ rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_feature = { path = "../rustc_feature" }
 rustc_fluent_macro = { path = "../rustc_fluent_macro" }
+rustc_hir = { path = "../rustc_hir" }
 rustc_lexer = { path = "../rustc_lexer" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
+thin-vec = "0.2.12"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl
index faa2865cb91..45174c9582d 100644
--- a/compiler/rustc_attr_parsing/messages.ftl
+++ b/compiler/rustc_attr_parsing/messages.ftl
@@ -6,6 +6,8 @@ attr_parsing_deprecated_item_suggestion =
     .help = add `#![feature(deprecated_suggestion)]` to the crate root
     .note = see #94785 for more details
 
+attr_parsing_empty_confusables =
+    expected at least one confusable name
 attr_parsing_expected_one_cfg_pattern =
     expected 1 cfg-pattern
 
@@ -21,8 +23,8 @@ attr_parsing_expects_feature_list =
 attr_parsing_expects_features =
     `{$name}` expects feature names
 
-attr_parsing_incorrect_meta_item =
-    incorrect meta item
+attr_parsing_incorrect_meta_item = expected a quoted string literal
+attr_parsing_incorrect_meta_item_suggestion = consider surrounding this with quotes
 
 attr_parsing_incorrect_repr_format_align_one_arg =
     incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
@@ -88,18 +90,20 @@ attr_parsing_multiple_stability_levels =
 attr_parsing_non_ident_feature =
     'feature' is not an identifier
 
+attr_parsing_repr_ident =
+    meta item in `repr` must be an identifier
+
 attr_parsing_rustc_allowed_unstable_pairing =
     `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute
 
-attr_parsing_rustc_const_stable_indirect_pairing =
-    `const_stable_indirect` attribute does not make sense on `rustc_const_stable` function, its behavior is already implied
-
 attr_parsing_rustc_promotable_pairing =
     `rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute
 
 attr_parsing_soft_no_args =
     `soft` should not have any arguments
 
+attr_parsing_stability_outside_std = stability attributes may not be used outside of the standard library
+
 attr_parsing_unknown_meta_item =
     unknown meta item '{$item}'
     .label = expected one of {$expected}
@@ -107,6 +111,10 @@ attr_parsing_unknown_meta_item =
 attr_parsing_unknown_version_literal =
     unknown version literal format, assuming it refers to a future version
 
+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`
+
 attr_parsing_unstable_cfg_target_compact =
     compact `cfg(target(..))` is experimental and subject to change
 
@@ -122,3 +130,8 @@ attr_parsing_unsupported_literal_generic =
     unsupported literal
 attr_parsing_unsupported_literal_suggestion =
     consider removing the prefix
+
+attr_parsing_unused_multiple =
+    multiple `{$name}` attributes
+    .suggestion = remove this attribute
+    .note = attribute also specified here
diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
index 13d246b08a8..d37ede86cfd 100644
--- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
@@ -1,49 +1,67 @@
-use rustc_ast::attr::{AttributeExt, filter_by_name};
-use rustc_session::Session;
-use rustc_span::{Symbol, sym};
+use std::iter;
 
+use rustc_attr_data_structures::AttributeKind;
+use rustc_span::{Span, Symbol, sym};
+
+use super::{CombineAttributeParser, ConvertFn};
+use crate::context::AcceptContext;
+use crate::parser::ArgParser;
 use crate::session_diagnostics;
 
-pub fn allow_internal_unstable(
-    sess: &Session,
-    attrs: &[impl AttributeExt],
-) -> impl Iterator<Item = Symbol> {
-    allow_unstable(sess, attrs, sym::allow_internal_unstable)
+pub(crate) struct AllowInternalUnstableParser;
+impl CombineAttributeParser for AllowInternalUnstableParser {
+    const PATH: &'static [rustc_span::Symbol] = &[sym::allow_internal_unstable];
+    type Item = (Symbol, Span);
+    const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowInternalUnstable;
+
+    fn extend<'a>(
+        cx: &'a AcceptContext<'a>,
+        args: &'a ArgParser<'a>,
+    ) -> impl IntoIterator<Item = Self::Item> + 'a {
+        parse_unstable(cx, args, Self::PATH[0]).into_iter().zip(iter::repeat(cx.attr_span))
+    }
 }
 
-pub fn rustc_allow_const_fn_unstable(
-    sess: &Session,
-    attrs: &[impl AttributeExt],
-) -> impl Iterator<Item = Symbol> {
-    allow_unstable(sess, attrs, sym::rustc_allow_const_fn_unstable)
+pub(crate) struct AllowConstFnUnstableParser;
+impl CombineAttributeParser for AllowConstFnUnstableParser {
+    const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_allow_const_fn_unstable];
+    type Item = Symbol;
+    const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowConstFnUnstable;
+
+    fn extend<'a>(
+        cx: &'a AcceptContext<'a>,
+        args: &'a ArgParser<'a>,
+    ) -> impl IntoIterator<Item = Self::Item> + 'a {
+        parse_unstable(cx, args, Self::PATH[0])
+    }
 }
 
-fn allow_unstable(
-    sess: &Session,
-    attrs: &[impl AttributeExt],
+fn parse_unstable<'a>(
+    cx: &AcceptContext<'_>,
+    args: &'a ArgParser<'a>,
     symbol: Symbol,
-) -> impl Iterator<Item = Symbol> {
-    let attrs = filter_by_name(attrs, symbol);
-    let list = attrs
-        .filter_map(move |attr| {
-            attr.meta_item_list().or_else(|| {
-                sess.dcx().emit_err(session_diagnostics::ExpectsFeatureList {
-                    span: attr.span(),
-                    name: symbol.to_ident_string(),
-                });
-                None
-            })
-        })
-        .flatten();
-
-    list.into_iter().filter_map(move |it| {
-        let name = it.ident().map(|ident| ident.name);
-        if name.is_none() {
-            sess.dcx().emit_err(session_diagnostics::ExpectsFeatures {
-                span: it.span(),
+) -> impl IntoIterator<Item = Symbol> {
+    let mut res = Vec::new();
+
+    let Some(list) = args.list() else {
+        cx.emit_err(session_diagnostics::ExpectsFeatureList {
+            span: cx.attr_span,
+            name: symbol.to_ident_string(),
+        });
+        return res;
+    };
+
+    for param in list.mixed() {
+        let param_span = param.span();
+        if let Some(ident) = param.meta_item().and_then(|i| i.word_without_args()) {
+            res.push(ident.name);
+        } else {
+            cx.emit_err(session_diagnostics::ExpectsFeatures {
+                span: param_span,
                 name: symbol.to_ident_string(),
             });
         }
-        name
-    })
+    }
+
+    res
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
index bb9aaaa2fea..0d6d521b40c 100644
--- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
@@ -1,6 +1,4 @@
-//! Parsing and validation of builtin attributes
-
-use rustc_ast::{self as ast, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId};
+use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NodeId};
 use rustc_ast_pretty::pprust;
 use rustc_attr_data_structures::RustcVersion;
 use rustc_feature::{Features, GatedCfg, find_gated_cfg};
@@ -9,10 +7,11 @@ use rustc_session::config::ExpectedValues;
 use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::lint::builtin::UNEXPECTED_CFGS;
 use rustc_session::parse::feature_err;
-use rustc_span::{Span, Symbol, kw, sym};
+use rustc_span::symbol::kw;
+use rustc_span::{Span, Symbol, sym};
 
-use crate::util::UnsupportedLiteralReason;
-use crate::{fluent_generated, parse_version, session_diagnostics};
+use crate::session_diagnostics::{self, UnsupportedLiteralReason};
+use crate::{fluent_generated, parse_version};
 
 #[derive(Clone, Debug)]
 pub struct Condition {
@@ -25,7 +24,7 @@ pub struct Condition {
 
 /// Tests if a cfg-pattern matches the cfg set
 pub fn cfg_matches(
-    cfg: &ast::MetaItemInner,
+    cfg: &MetaItemInner,
     sess: &Session,
     lint_node_id: NodeId,
     features: Option<&Features>,
@@ -80,7 +79,7 @@ fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Fea
 /// Evaluate a cfg-like condition (with `any` and `all`), using `eval` to
 /// evaluate individual items.
 pub fn eval_condition(
-    cfg: &ast::MetaItemInner,
+    cfg: &MetaItemInner,
     sess: &Session,
     features: Option<&Features>,
     eval: &mut impl FnMut(Condition) -> bool,
@@ -88,8 +87,8 @@ pub fn eval_condition(
     let dcx = sess.dcx();
 
     let cfg = match cfg {
-        ast::MetaItemInner::MetaItem(meta_item) => meta_item,
-        ast::MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => {
+        MetaItemInner::MetaItem(meta_item) => meta_item,
+        MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => {
             if let Some(features) = features {
                 // we can't use `try_gate_cfg` as symbols don't differentiate between `r#true`
                 // and `true`, and we want to keep the former working without feature gate
@@ -118,7 +117,7 @@ pub fn eval_condition(
     };
 
     match &cfg.kind {
-        ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => {
+        MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => {
             try_gate_cfg(sym::version, cfg.span, sess, features);
             let (min_version, span) = match &mis[..] {
                 [MetaItemInner::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => {
@@ -150,7 +149,7 @@ pub fn eval_condition(
                 RustcVersion::CURRENT >= min_version
             }
         }
-        ast::MetaItemKind::List(mis) => {
+        MetaItemKind::List(mis) => {
             for mi in mis.iter() {
                 if mi.meta_item_or_bool().is_none() {
                     dcx.emit_err(session_diagnostics::UnsupportedLiteral {
@@ -209,12 +208,7 @@ pub fn eval_condition(
                             seg.ident.name = Symbol::intern(&format!("target_{}", seg.ident.name));
                         }
 
-                        res & eval_condition(
-                            &ast::MetaItemInner::MetaItem(mi),
-                            sess,
-                            features,
-                            eval,
-                        )
+                        res & eval_condition(&MetaItemInner::MetaItem(mi), sess, features, eval)
                     })
                 }
                 _ => {
@@ -226,7 +220,7 @@ pub fn eval_condition(
                 }
             }
         }
-        ast::MetaItemKind::Word | MetaItemKind::NameValue(..) if cfg.path.segments.len() != 1 => {
+        MetaItemKind::Word | MetaItemKind::NameValue(..) if cfg.path.segments.len() != 1 => {
             dcx.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span });
             true
         }
@@ -239,7 +233,7 @@ pub fn eval_condition(
             });
             true
         }
-        ast::MetaItemKind::Word | ast::MetaItemKind::NameValue(..) => {
+        MetaItemKind::Word | MetaItemKind::NameValue(..) => {
             let ident = cfg.ident().expect("multi-segment cfg predicate");
             eval(Condition {
                 name: ident.name,
diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs
index 2ced759fd88..6cff952fcf2 100644
--- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs
@@ -1,21 +1,58 @@
-//! Parsing and validation of builtin attributes
+use rustc_attr_data_structures::AttributeKind;
+use rustc_span::{Span, Symbol, sym};
+use thin_vec::ThinVec;
 
-use rustc_ast::MetaItemInner;
-use rustc_ast::attr::AttributeExt;
-use rustc_span::Symbol;
+use super::{AcceptMapping, AttributeParser};
+use crate::context::FinalizeContext;
+use crate::session_diagnostics;
 
-/// Read the content of a `rustc_confusables` attribute, and return the list of candidate names.
-pub fn parse_confusables(attr: &impl AttributeExt) -> Option<Vec<Symbol>> {
-    let metas = attr.meta_item_list()?;
+#[derive(Default)]
+pub(crate) struct ConfusablesParser {
+    confusables: ThinVec<Symbol>,
+    first_span: Option<Span>,
+}
+
+impl AttributeParser for ConfusablesParser {
+    const ATTRIBUTES: AcceptMapping<Self> = &[(&[sym::rustc_confusables], |this, cx, args| {
+        let Some(list) = args.list() else {
+            // FIXME(jdonszelmann): error when not a list? Bring validation code here.
+            //       NOTE: currently subsequent attributes are silently ignored using
+            //       tcx.get_attr().
+            return;
+        };
+
+        if list.is_empty() {
+            cx.emit_err(session_diagnostics::EmptyConfusables { span: cx.attr_span });
+        }
+
+        for param in list.mixed() {
+            let span = param.span();
 
-    let mut candidates = Vec::new();
+            let Some(lit) = param.lit() else {
+                cx.emit_err(session_diagnostics::IncorrectMetaItem {
+                    span,
+                    suggestion: Some(session_diagnostics::IncorrectMetaItemSuggestion {
+                        lo: span.shrink_to_lo(),
+                        hi: span.shrink_to_hi(),
+                    }),
+                });
+                continue;
+            };
 
-    for meta in metas {
-        let MetaItemInner::Lit(meta_lit) = meta else {
+            this.confusables.push(lit.symbol);
+        }
+
+        this.first_span.get_or_insert(cx.attr_span);
+    })];
+
+    fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
+        if self.confusables.is_empty() {
             return None;
-        };
-        candidates.push(meta_lit.symbol);
-    }
+        }
 
-    Some(candidates)
+        Some(AttributeKind::Confusables {
+            symbols: self.confusables,
+            first_span: self.first_span.unwrap(),
+        })
+    }
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
index d7415a7198f..7d1417446b2 100644
--- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
@@ -1,121 +1,122 @@
-//! Parsing and validation of builtin attributes
-
-use rustc_ast::attr::AttributeExt;
-use rustc_ast::{MetaItem, MetaItemInner};
-use rustc_ast_pretty::pprust;
-use rustc_attr_data_structures::{DeprecatedSince, Deprecation};
-use rustc_feature::Features;
-use rustc_session::Session;
+use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation};
+use rustc_span::symbol::Ident;
 use rustc_span::{Span, Symbol, sym};
 
-use super::util::UnsupportedLiteralReason;
-use crate::{parse_version, session_diagnostics};
+use super::SingleAttributeParser;
+use super::util::parse_version;
+use crate::context::AcceptContext;
+use crate::parser::ArgParser;
+use crate::session_diagnostics;
+use crate::session_diagnostics::UnsupportedLiteralReason;
 
-/// Finds the deprecation attribute. `None` if none exists.
-pub fn find_deprecation(
-    sess: &Session,
-    features: &Features,
-    attrs: &[impl AttributeExt],
-) -> Option<(Deprecation, Span)> {
-    let mut depr: Option<(Deprecation, Span)> = None;
-    let is_rustc = features.staged_api();
+pub(crate) struct DeprecationParser;
 
-    'outer: for attr in attrs {
-        if !attr.has_name(sym::deprecated) {
-            continue;
+fn get(
+    cx: &AcceptContext<'_>,
+    ident: Ident,
+    param_span: Span,
+    arg: &ArgParser<'_>,
+    item: &Option<Symbol>,
+) -> Option<Symbol> {
+    if item.is_some() {
+        cx.emit_err(session_diagnostics::MultipleItem {
+            span: param_span,
+            item: ident.to_string(),
+        });
+        return None;
+    }
+    if let Some(v) = arg.name_value() {
+        if let Some(value_str) = v.value_as_str() {
+            Some(value_str)
+        } else {
+            let lit = v.value_as_lit();
+            cx.emit_err(session_diagnostics::UnsupportedLiteral {
+                span: v.value_span,
+                reason: UnsupportedLiteralReason::DeprecatedString,
+                is_bytestr: lit.kind.is_bytestr(),
+                start_point_span: cx.sess().source_map().start_point(lit.span),
+            });
+            None
         }
+    } else {
+        // FIXME(jdonszelmann): suggestion?
+        cx.emit_err(session_diagnostics::IncorrectMetaItem { span: param_span, suggestion: None });
+        None
+    }
+}
+
+impl SingleAttributeParser for DeprecationParser {
+    const PATH: &'static [rustc_span::Symbol] = &[sym::deprecated];
+
+    fn on_duplicate(cx: &AcceptContext<'_>, first_span: rustc_span::Span) {
+        // FIXME(jdonszelmann): merge with errors from check_attrs.rs
+        cx.emit_err(session_diagnostics::UnusedMultiple {
+            this: cx.attr_span,
+            other: first_span,
+            name: sym::deprecated,
+        });
+    }
+
+    fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        let features = cx.features();
 
         let mut since = None;
         let mut note = None;
         let mut suggestion = None;
 
-        if attr.is_doc_comment() {
-            continue;
-        } else if attr.is_word() {
-        } else if let Some(value) = attr.value_str() {
-            note = Some(value)
-        } else if let Some(list) = attr.meta_item_list() {
-            let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
-                if item.is_some() {
-                    sess.dcx().emit_err(session_diagnostics::MultipleItem {
-                        span: meta.span,
-                        item: pprust::path_to_string(&meta.path),
+        let is_rustc = features.staged_api();
+
+        if let Some(value) = args.name_value()
+            && let Some(value_str) = value.value_as_str()
+        {
+            note = Some(value_str)
+        } else if let Some(list) = args.list() {
+            for param in list.mixed() {
+                let param_span = param.span();
+                let Some(param) = param.meta_item() else {
+                    cx.emit_err(session_diagnostics::UnsupportedLiteral {
+                        span: param_span,
+                        reason: UnsupportedLiteralReason::DeprecatedKvPair,
+                        is_bytestr: false,
+                        start_point_span: cx.sess().source_map().start_point(param_span),
                     });
-                    return false;
-                }
-                if let Some(v) = meta.value_str() {
-                    *item = Some(v);
-                    true
-                } else {
-                    if let Some(lit) = meta.name_value_literal() {
-                        sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral {
-                            span: lit.span,
-                            reason: UnsupportedLiteralReason::DeprecatedString,
-                            is_bytestr: lit.kind.is_bytestr(),
-                            start_point_span: sess.source_map().start_point(lit.span),
-                        });
-                    } else {
-                        sess.dcx()
-                            .emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span });
-                    }
-                    false
-                }
-            };
+                    return None;
+                };
 
-            for meta in &list {
-                match meta {
-                    MetaItemInner::MetaItem(mi) => match mi.name_or_empty() {
-                        sym::since => {
-                            if !get(mi, &mut since) {
-                                continue 'outer;
-                            }
-                        }
-                        sym::note => {
-                            if !get(mi, &mut note) {
-                                continue 'outer;
-                            }
-                        }
-                        sym::suggestion => {
-                            if !features.deprecated_suggestion() {
-                                sess.dcx().emit_err(
-                                    session_diagnostics::DeprecatedItemSuggestion {
-                                        span: mi.span,
-                                        is_nightly: sess.is_nightly_build(),
-                                        details: (),
-                                    },
-                                );
-                            }
+                let (ident, arg) = param.word_or_empty();
 
-                            if !get(mi, &mut suggestion) {
-                                continue 'outer;
-                            }
-                        }
-                        _ => {
-                            sess.dcx().emit_err(session_diagnostics::UnknownMetaItem {
-                                span: meta.span(),
-                                item: pprust::path_to_string(&mi.path),
-                                expected: if features.deprecated_suggestion() {
-                                    &["since", "note", "suggestion"]
-                                } else {
-                                    &["since", "note"]
-                                },
+                match ident.name {
+                    sym::since => {
+                        since = Some(get(cx, ident, param_span, arg, &since)?);
+                    }
+                    sym::note => {
+                        note = Some(get(cx, ident, param_span, arg, &note)?);
+                    }
+                    sym::suggestion => {
+                        if !features.deprecated_suggestion() {
+                            cx.emit_err(session_diagnostics::DeprecatedItemSuggestion {
+                                span: param_span,
+                                is_nightly: cx.sess().is_nightly_build(),
+                                details: (),
                             });
-                            continue 'outer;
                         }
-                    },
-                    MetaItemInner::Lit(lit) => {
-                        sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral {
-                            span: lit.span,
-                            reason: UnsupportedLiteralReason::DeprecatedKvPair,
-                            is_bytestr: false,
-                            start_point_span: sess.source_map().start_point(lit.span),
+
+                        suggestion = Some(get(cx, ident, param_span, arg, &suggestion)?);
+                    }
+                    _ => {
+                        cx.emit_err(session_diagnostics::UnknownMetaItem {
+                            span: param_span,
+                            item: ident.to_string(),
+                            expected: if features.deprecated_suggestion() {
+                                &["since", "note", "suggestion"]
+                            } else {
+                                &["since", "note"]
+                            },
                         });
-                        continue 'outer;
+                        return None;
                     }
                 }
             }
-        } else {
-            continue;
         }
 
         let since = if let Some(since) = since {
@@ -126,23 +127,24 @@ pub fn find_deprecation(
             } else if let Some(version) = parse_version(since) {
                 DeprecatedSince::RustcVersion(version)
             } else {
-                sess.dcx().emit_err(session_diagnostics::InvalidSince { span: attr.span() });
+                cx.emit_err(session_diagnostics::InvalidSince { span: cx.attr_span });
                 DeprecatedSince::Err
             }
         } else if is_rustc {
-            sess.dcx().emit_err(session_diagnostics::MissingSince { span: attr.span() });
+            cx.emit_err(session_diagnostics::MissingSince { span: cx.attr_span });
             DeprecatedSince::Err
         } else {
             DeprecatedSince::Unspecified
         };
 
         if is_rustc && note.is_none() {
-            sess.dcx().emit_err(session_diagnostics::MissingNote { span: attr.span() });
-            continue;
+            cx.emit_err(session_diagnostics::MissingNote { span: cx.attr_span });
+            return None;
         }
 
-        depr = Some((Deprecation { since, note, suggestion }, attr.span()));
+        Some(AttributeKind::Deprecation {
+            deprecation: Deprecation { since, note, suggestion },
+            span: cx.attr_span,
+        })
     }
-
-    depr
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index a78e0b54b64..6ecd6b4d7db 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -1,17 +1,152 @@
-mod allow_unstable;
-mod cfg;
-mod confusables;
-mod deprecation;
-mod repr;
-mod stability;
-mod transparency;
-
-pub mod util;
-
-pub use allow_unstable::*;
-pub use cfg::*;
-pub use confusables::*;
-pub use deprecation::*;
-pub use repr::*;
-pub use stability::*;
-pub use transparency::*;
+//! This module defines traits for attribute parsers, little state machines that recognize and parse
+//! attributes out of a longer list of attributes. The main trait is called [`AttributeParser`].
+//! You can find more docs about [`AttributeParser`]s on the trait itself.
+//! However, for many types of attributes, implementing [`AttributeParser`] is not necessary.
+//! It allows for a lot of flexibility you might not want.
+//!
+//! Specifically, you might not care about managing the state of your [`AttributeParser`]
+//! state machine yourself. In this case you can choose to implement:
+//!
+//! - [`SingleAttributeParser`]: makes it easy to implement an attribute which should error if it
+//! appears more than once in a list of attributes
+//! - [`CombineAttributeParser`]: makes it easy to implement an attribute which should combine the
+//! contents of attributes, if an attribute appear multiple times in a list
+//!
+//! Attributes should be added to [`ATTRIBUTE_MAPPING`](crate::context::ATTRIBUTE_MAPPING) to be parsed.
+
+use std::marker::PhantomData;
+
+use rustc_attr_data_structures::AttributeKind;
+use rustc_span::Span;
+use thin_vec::ThinVec;
+
+use crate::context::{AcceptContext, FinalizeContext};
+use crate::parser::ArgParser;
+
+pub(crate) mod allow_unstable;
+pub(crate) mod cfg;
+pub(crate) mod confusables;
+pub(crate) mod deprecation;
+pub(crate) mod repr;
+pub(crate) mod stability;
+pub(crate) mod transparency;
+pub(crate) mod util;
+
+type AcceptFn<T> = fn(&mut T, &AcceptContext<'_>, &ArgParser<'_>);
+type AcceptMapping<T> = &'static [(&'static [rustc_span::Symbol], AcceptFn<T>)];
+
+/// An [`AttributeParser`] is a type which searches for syntactic attributes.
+///
+/// Parsers are often tiny state machines that gets to see all syntactical attributes on an item.
+/// [`Default::default`] creates a fresh instance that sits in some kind of initial state, usually that the
+/// attribute it is looking for was not yet seen.
+///
+/// Then, it defines what paths this group will accept in [`AttributeParser::ATTRIBUTES`].
+/// These are listed as pairs, of symbols and function pointers. The function pointer will
+/// be called when that attribute is found on an item, which can influence the state of the little
+/// state machine.
+///
+/// Finally, after all attributes on an item have been seen, and possibly been accepted,
+/// the [`finalize`](AttributeParser::finalize) functions for all attribute parsers are called. Each can then report
+/// whether it has seen the attribute it has been looking for.
+///
+/// The state machine is automatically reset to parse attributes on the next item.
+pub(crate) trait AttributeParser: Default + 'static {
+    /// The symbols for the attributes that this parser is interested in.
+    ///
+    /// If an attribute has this symbol, the `accept` function will be called on it.
+    const ATTRIBUTES: AcceptMapping<Self>;
+
+    /// The parser has gotten a chance to accept the attributes on an item,
+    /// here it can produce an attribute.
+    fn finalize(self, cx: &FinalizeContext<'_>) -> Option<AttributeKind>;
+}
+
+/// Alternative to [`AttributeParser`] that automatically handles state management.
+/// A slightly simpler and more restricted way to convert attributes.
+/// Assumes that an attribute can only appear a single time on an item,
+/// and errors when it sees more.
+///
+/// [`Single<T> where T: SingleAttributeParser`](Single) implements [`AttributeParser`].
+///
+/// [`SingleAttributeParser`] can only convert attributes one-to-one, and cannot combine multiple
+/// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example.
+pub(crate) trait SingleAttributeParser: 'static {
+    const PATH: &'static [rustc_span::Symbol];
+
+    /// Caled when a duplicate attribute is found.
+    ///
+    /// `first_span` is the span of the first occurrence of this attribute.
+    // FIXME(jdonszelmann): default error
+    fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span);
+
+    /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`]
+    fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind>;
+}
+
+pub(crate) struct Single<T: SingleAttributeParser>(PhantomData<T>, Option<(AttributeKind, Span)>);
+
+impl<T: SingleAttributeParser> Default for Single<T> {
+    fn default() -> Self {
+        Self(Default::default(), Default::default())
+    }
+}
+
+impl<T: SingleAttributeParser> AttributeParser for Single<T> {
+    const ATTRIBUTES: AcceptMapping<Self> = &[(T::PATH, |group: &mut Single<T>, cx, args| {
+        if let Some((_, s)) = group.1 {
+            T::on_duplicate(cx, s);
+            return;
+        }
+
+        if let Some(pa) = T::convert(cx, args) {
+            group.1 = Some((pa, cx.attr_span));
+        }
+    })];
+
+    fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
+        Some(self.1?.0)
+    }
+}
+
+type ConvertFn<E> = fn(ThinVec<E>) -> AttributeKind;
+
+/// Alternative to [`AttributeParser`] that automatically handles state management.
+/// If multiple attributes appear on an element, combines the values of each into a
+/// [`ThinVec`].
+/// [`Combine<T> where T: CombineAttributeParser`](Combine) implements [`AttributeParser`].
+///
+/// [`CombineAttributeParser`] can only convert a single kind of attribute, and cannot combine multiple
+/// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example.
+pub(crate) trait CombineAttributeParser: 'static {
+    const PATH: &'static [rustc_span::Symbol];
+
+    type Item;
+    const CONVERT: ConvertFn<Self::Item>;
+
+    /// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`]
+    fn extend<'a>(
+        cx: &'a AcceptContext<'a>,
+        args: &'a ArgParser<'a>,
+    ) -> impl IntoIterator<Item = Self::Item> + 'a;
+}
+
+pub(crate) struct Combine<T: CombineAttributeParser>(
+    PhantomData<T>,
+    ThinVec<<T as CombineAttributeParser>::Item>,
+);
+
+impl<T: CombineAttributeParser> Default for Combine<T> {
+    fn default() -> Self {
+        Self(Default::default(), Default::default())
+    }
+}
+
+impl<T: CombineAttributeParser> AttributeParser for Combine<T> {
+    const ATTRIBUTES: AcceptMapping<Self> =
+        &[(T::PATH, |group: &mut Combine<T>, cx, args| group.1.extend(T::extend(cx, args)))];
+
+    fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
+        if self.1.is_empty() { None } else { Some(T::CONVERT(self.1)) }
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs
index 28c381160b8..26ca637faec 100644
--- a/compiler/rustc_attr_parsing/src/attributes/repr.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs
@@ -1,15 +1,13 @@
-//! Parsing and validation of builtin attributes
-
 use rustc_abi::Align;
-use rustc_ast::attr::AttributeExt;
-use rustc_ast::{self as ast, MetaItemKind};
-use rustc_attr_data_structures::IntType;
-use rustc_attr_data_structures::ReprAttr::*;
-use rustc_session::Session;
-use rustc_span::{Symbol, sym};
+use rustc_ast::{IntTy, LitIntType, LitKind, UintTy};
+use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr};
+use rustc_span::{Span, Symbol, sym};
 
-use crate::ReprAttr;
-use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
+use super::{CombineAttributeParser, ConvertFn};
+use crate::context::AcceptContext;
+use crate::parser::{ArgParser, MetaItemListParser, MetaItemParser};
+use crate::session_diagnostics;
+use crate::session_diagnostics::IncorrectReprFormatGenericCause;
 
 /// Parse #[repr(...)] forms.
 ///
@@ -18,185 +16,216 @@ use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
 /// the same discriminant size that the corresponding C enum would or C
 /// structure layout, `packed` to remove padding, and `transparent` to delegate representation
 /// concerns to the only non-ZST field.
-pub fn find_repr_attrs(sess: &Session, attr: &impl AttributeExt) -> Vec<ReprAttr> {
-    if attr.has_name(sym::repr) { parse_repr_attr(sess, attr) } else { Vec::new() }
-}
+// FIXME(jdonszelmann): is a vec the right representation here even? isn't it just a struct?
+pub(crate) struct ReprParser;
 
-pub fn parse_repr_attr(sess: &Session, attr: &impl AttributeExt) -> Vec<ReprAttr> {
-    assert!(attr.has_name(sym::repr), "expected `#[repr(..)]`, found: {attr:?}");
-    let mut acc = Vec::new();
-    let dcx = sess.dcx();
-
-    if let Some(items) = attr.meta_item_list() {
-        for item in items {
-            let mut recognised = false;
-            if item.is_word() {
-                let hint = match item.name_or_empty() {
-                    sym::Rust => Some(ReprRust),
-                    sym::C => Some(ReprC),
-                    sym::packed => Some(ReprPacked(Align::ONE)),
-                    sym::simd => Some(ReprSimd),
-                    sym::transparent => Some(ReprTransparent),
-                    sym::align => {
-                        sess.dcx().emit_err(session_diagnostics::InvalidReprAlignNeedArg {
-                            span: item.span(),
-                        });
-                        recognised = true;
-                        None
-                    }
-                    name => int_type_of_word(name).map(ReprInt),
-                };
-
-                if let Some(h) = hint {
-                    recognised = true;
-                    acc.push(h);
-                }
-            } else if let Some((name, value)) = item.singleton_lit_list() {
-                let mut literal_error = None;
-                let mut err_span = item.span();
-                if name == sym::align {
-                    recognised = true;
-                    match parse_alignment(&value.kind) {
-                        Ok(literal) => acc.push(ReprAlign(literal)),
-                        Err(message) => {
-                            err_span = value.span;
-                            literal_error = Some(message)
-                        }
-                    };
-                } else if name == sym::packed {
-                    recognised = true;
-                    match parse_alignment(&value.kind) {
-                        Ok(literal) => acc.push(ReprPacked(literal)),
-                        Err(message) => {
-                            err_span = value.span;
-                            literal_error = Some(message)
-                        }
-                    };
-                } else if matches!(name, sym::Rust | sym::C | sym::simd | sym::transparent)
-                    || int_type_of_word(name).is_some()
-                {
-                    recognised = true;
-                    sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoParen {
-                        span: item.span(),
-                        name: name.to_ident_string(),
-                    });
-                }
-                if let Some(literal_error) = literal_error {
-                    sess.dcx().emit_err(session_diagnostics::InvalidReprGeneric {
-                        span: err_span,
-                        repr_arg: name.to_ident_string(),
-                        error_part: literal_error,
-                    });
-                }
-            } else if let Some(meta_item) = item.meta_item() {
-                match &meta_item.kind {
-                    MetaItemKind::NameValue(value) => {
-                        if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) {
-                            let name = meta_item.name_or_empty().to_ident_string();
-                            recognised = true;
-                            sess.dcx().emit_err(session_diagnostics::IncorrectReprFormatGeneric {
-                                span: item.span(),
-                                repr_arg: &name,
-                                cause: IncorrectReprFormatGenericCause::from_lit_kind(
-                                    item.span(),
-                                    &value.kind,
-                                    &name,
-                                ),
-                            });
-                        } else if matches!(
-                            meta_item.name_or_empty(),
-                            sym::Rust | sym::C | sym::simd | sym::transparent
-                        ) || int_type_of_word(meta_item.name_or_empty()).is_some()
-                        {
-                            recognised = true;
-                            sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoValue {
-                                span: meta_item.span,
-                                name: meta_item.name_or_empty().to_ident_string(),
-                            });
-                        }
-                    }
-                    MetaItemKind::List(nested_items) => {
-                        if meta_item.has_name(sym::align) {
-                            recognised = true;
-                            if let [nested_item] = nested_items.as_slice() {
-                                sess.dcx().emit_err(
-                                    session_diagnostics::IncorrectReprFormatExpectInteger {
-                                        span: nested_item.span(),
-                                    },
-                                );
-                            } else {
-                                sess.dcx().emit_err(
-                                    session_diagnostics::IncorrectReprFormatAlignOneArg {
-                                        span: meta_item.span,
-                                    },
-                                );
-                            }
-                        } else if meta_item.has_name(sym::packed) {
-                            recognised = true;
-                            if let [nested_item] = nested_items.as_slice() {
-                                sess.dcx().emit_err(
-                                    session_diagnostics::IncorrectReprFormatPackedExpectInteger {
-                                        span: nested_item.span(),
-                                    },
-                                );
-                            } else {
-                                sess.dcx().emit_err(
-                                    session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg {
-                                        span: meta_item.span,
-                                    },
-                                );
-                            }
-                        } else if matches!(
-                            meta_item.name_or_empty(),
-                            sym::Rust | sym::C | sym::simd | sym::transparent
-                        ) || int_type_of_word(meta_item.name_or_empty()).is_some()
-                        {
-                            recognised = true;
-                            sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoParen {
-                                span: meta_item.span,
-                                name: meta_item.name_or_empty().to_ident_string(),
-                            });
-                        }
-                    }
-                    _ => (),
-                }
-            }
-            if !recognised {
-                // Not a word we recognize. This will be caught and reported by
-                // the `check_mod_attrs` pass, but this pass doesn't always run
-                // (e.g. if we only pretty-print the source), so we have to gate
-                // the `span_delayed_bug` call as follows:
-                if sess.opts.pretty.is_none_or(|pp| pp.needs_analysis()) {
-                    dcx.span_delayed_bug(item.span(), "unrecognized representation hint");
-                }
+impl CombineAttributeParser for ReprParser {
+    type Item = (ReprAttr, Span);
+    const PATH: &'static [rustc_span::Symbol] = &[sym::repr];
+    const CONVERT: ConvertFn<Self::Item> = AttributeKind::Repr;
+
+    fn extend<'a>(
+        cx: &'a AcceptContext<'a>,
+        args: &'a ArgParser<'a>,
+    ) -> impl IntoIterator<Item = Self::Item> + 'a {
+        let mut reprs = Vec::new();
+
+        let Some(list) = args.list() else {
+            return reprs;
+        };
+
+        if list.is_empty() {
+            // this is so validation can emit a lint
+            reprs.push((ReprAttr::ReprEmpty, cx.attr_span));
+        }
+
+        for param in list.mixed() {
+            if let Some(_) = param.lit() {
+                cx.emit_err(session_diagnostics::ReprIdent { span: cx.attr_span });
+                continue;
             }
+
+            reprs.extend(
+                param.meta_item().and_then(|mi| parse_repr(cx, &mi)).map(|r| (r, param.span())),
+            );
         }
+
+        reprs
     }
-    acc
+}
+
+macro_rules! int_pat {
+    () => {
+        sym::i8
+            | sym::u8
+            | sym::i16
+            | sym::u16
+            | sym::i32
+            | sym::u32
+            | sym::i64
+            | sym::u64
+            | sym::i128
+            | sym::u128
+            | sym::isize
+            | sym::usize
+    };
 }
 
 fn int_type_of_word(s: Symbol) -> Option<IntType> {
-    use rustc_attr_data_structures::IntType::*;
+    use IntType::*;
 
     match s {
-        sym::i8 => Some(SignedInt(ast::IntTy::I8)),
-        sym::u8 => Some(UnsignedInt(ast::UintTy::U8)),
-        sym::i16 => Some(SignedInt(ast::IntTy::I16)),
-        sym::u16 => Some(UnsignedInt(ast::UintTy::U16)),
-        sym::i32 => Some(SignedInt(ast::IntTy::I32)),
-        sym::u32 => Some(UnsignedInt(ast::UintTy::U32)),
-        sym::i64 => Some(SignedInt(ast::IntTy::I64)),
-        sym::u64 => Some(UnsignedInt(ast::UintTy::U64)),
-        sym::i128 => Some(SignedInt(ast::IntTy::I128)),
-        sym::u128 => Some(UnsignedInt(ast::UintTy::U128)),
-        sym::isize => Some(SignedInt(ast::IntTy::Isize)),
-        sym::usize => Some(UnsignedInt(ast::UintTy::Usize)),
+        sym::i8 => Some(SignedInt(IntTy::I8)),
+        sym::u8 => Some(UnsignedInt(UintTy::U8)),
+        sym::i16 => Some(SignedInt(IntTy::I16)),
+        sym::u16 => Some(UnsignedInt(UintTy::U16)),
+        sym::i32 => Some(SignedInt(IntTy::I32)),
+        sym::u32 => Some(UnsignedInt(UintTy::U32)),
+        sym::i64 => Some(SignedInt(IntTy::I64)),
+        sym::u64 => Some(UnsignedInt(UintTy::U64)),
+        sym::i128 => Some(SignedInt(IntTy::I128)),
+        sym::u128 => Some(UnsignedInt(UintTy::U128)),
+        sym::isize => Some(SignedInt(IntTy::Isize)),
+        sym::usize => Some(UnsignedInt(UintTy::Usize)),
         _ => None,
     }
 }
 
-pub fn parse_alignment(node: &ast::LitKind) -> Result<Align, &'static str> {
-    if let ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed) = node {
+fn parse_repr(cx: &AcceptContext<'_>, param: &MetaItemParser<'_>) -> Option<ReprAttr> {
+    use ReprAttr::*;
+
+    // FIXME(jdonszelmann): invert the parsing here to match on the word first and then the
+    // structure.
+    let (ident, args) = param.word_or_empty();
+
+    match (ident.name, args) {
+        (sym::align, ArgParser::NoArgs) => {
+            cx.emit_err(session_diagnostics::InvalidReprAlignNeedArg { span: ident.span });
+            None
+        }
+        (sym::align, ArgParser::List(l)) => parse_repr_align(cx, l, param.span(), AlignKind::Align),
+
+        (sym::packed, ArgParser::NoArgs) => Some(ReprPacked(Align::ONE)),
+        (sym::packed, ArgParser::List(l)) => {
+            parse_repr_align(cx, l, param.span(), AlignKind::Packed)
+        }
+
+        (sym::align | sym::packed, ArgParser::NameValue(l)) => {
+            cx.emit_err(session_diagnostics::IncorrectReprFormatGeneric {
+                span: param.span(),
+                // FIXME(jdonszelmann) can just be a string in the diag type
+                repr_arg: &ident.to_string(),
+                cause: IncorrectReprFormatGenericCause::from_lit_kind(
+                    param.span(),
+                    &l.value_as_lit().kind,
+                    ident.name.as_str(),
+                ),
+            });
+            None
+        }
+
+        (sym::Rust, ArgParser::NoArgs) => Some(ReprRust),
+        (sym::C, ArgParser::NoArgs) => Some(ReprC),
+        (sym::simd, ArgParser::NoArgs) => Some(ReprSimd),
+        (sym::transparent, ArgParser::NoArgs) => Some(ReprTransparent),
+        (i @ int_pat!(), ArgParser::NoArgs) => {
+            // int_pat!() should make sure it always parses
+            Some(ReprInt(int_type_of_word(i).unwrap()))
+        }
+
+        (
+            sym::Rust | sym::C | sym::simd | sym::transparent | int_pat!(),
+            ArgParser::NameValue(_),
+        ) => {
+            cx.emit_err(session_diagnostics::InvalidReprHintNoValue {
+                span: param.span(),
+                name: ident.to_string(),
+            });
+            None
+        }
+        (sym::Rust | sym::C | sym::simd | sym::transparent | int_pat!(), ArgParser::List(_)) => {
+            cx.emit_err(session_diagnostics::InvalidReprHintNoParen {
+                span: param.span(),
+                name: ident.to_string(),
+            });
+            None
+        }
+
+        _ => {
+            cx.emit_err(session_diagnostics::UnrecognizedReprHint { span: param.span() });
+            None
+        }
+    }
+}
+
+enum AlignKind {
+    Packed,
+    Align,
+}
+
+fn parse_repr_align(
+    cx: &AcceptContext<'_>,
+    list: &MetaItemListParser<'_>,
+    param_span: Span,
+    align_kind: AlignKind,
+) -> Option<ReprAttr> {
+    use AlignKind::*;
+
+    let Some(align) = list.single() else {
+        match align_kind {
+            Packed => {
+                cx.emit_err(session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg {
+                    span: param_span,
+                });
+            }
+            Align => {
+                cx.dcx().emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg {
+                    span: param_span,
+                });
+            }
+        }
+
+        return None;
+    };
+
+    let Some(lit) = align.lit() else {
+        match align_kind {
+            Packed => {
+                cx.emit_err(session_diagnostics::IncorrectReprFormatPackedExpectInteger {
+                    span: align.span(),
+                });
+            }
+            Align => {
+                cx.emit_err(session_diagnostics::IncorrectReprFormatExpectInteger {
+                    span: align.span(),
+                });
+            }
+        }
+
+        return None;
+    };
+
+    match parse_alignment(&lit.kind) {
+        Ok(literal) => Some(match align_kind {
+            AlignKind::Packed => ReprAttr::ReprPacked(literal),
+            AlignKind::Align => ReprAttr::ReprAlign(literal),
+        }),
+        Err(message) => {
+            cx.emit_err(session_diagnostics::InvalidReprGeneric {
+                span: lit.span,
+                repr_arg: match align_kind {
+                    Packed => "packed".to_string(),
+                    Align => "align".to_string(),
+                },
+                error_part: message,
+            });
+            None
+        }
+    }
+}
+
+fn parse_alignment(node: &LitKind) -> Result<Align, &'static str> {
+    if let LitKind::Int(literal, LitIntType::Unsuffixed) = node {
         // `Align::from_bytes` accepts 0 as an input, check is_power_of_two() first
         if literal.get().is_power_of_two() {
             // Only possible error is larger than 2^29
diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs
index 454b8b5de82..6d76456e83c 100644
--- a/compiler/rustc_attr_parsing/src/attributes/stability.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs
@@ -1,266 +1,258 @@
-//! Parsing and validation of builtin attributes
-
 use std::num::NonZero;
 
-use rustc_ast::MetaItem;
-use rustc_ast::attr::AttributeExt;
-use rustc_ast_pretty::pprust;
 use rustc_attr_data_structures::{
-    ConstStability, DefaultBodyStability, Stability, StabilityLevel, StableSince, UnstableReason,
-    VERSION_PLACEHOLDER,
+    AttributeKind, DefaultBodyStability, PartialConstStability, Stability, StabilityLevel,
+    StableSince, UnstableReason, VERSION_PLACEHOLDER,
 };
 use rustc_errors::ErrorGuaranteed;
-use rustc_session::Session;
 use rustc_span::{Span, Symbol, kw, sym};
 
-use crate::attributes::util::UnsupportedLiteralReason;
-use crate::{parse_version, session_diagnostics};
-
-/// Collects stability info from `stable`/`unstable`/`rustc_allowed_through_unstable_modules`
-/// attributes in `attrs`. Returns `None` if no stability attributes are found.
-pub fn find_stability(
-    sess: &Session,
-    attrs: &[impl AttributeExt],
-    item_sp: Span,
-) -> Option<(Stability, Span)> {
-    let mut stab: Option<(Stability, Span)> = None;
-    let mut allowed_through_unstable_modules = None;
-
-    for attr in attrs {
-        match attr.name_or_empty() {
-            sym::rustc_allowed_through_unstable_modules => {
-                // The value is mandatory, but avoid ICEs in case such code reaches this function.
-                allowed_through_unstable_modules = Some(attr.value_str().unwrap_or_else(|| {
-                    sess.dcx().span_delayed_bug(
-                        item_sp,
-                        "`#[rustc_allowed_through_unstable_modules]` without deprecation message",
-                    );
-                    kw::Empty
-                }))
-            }
-            sym::unstable => {
-                if stab.is_some() {
-                    sess.dcx().emit_err(session_diagnostics::MultipleStabilityLevels {
-                        span: attr.span(),
-                    });
-                    break;
-                }
+use super::util::parse_version;
+use super::{AcceptMapping, AttributeParser, SingleAttributeParser};
+use crate::context::{AcceptContext, FinalizeContext};
+use crate::parser::{ArgParser, MetaItemParser};
+use crate::session_diagnostics::{self, UnsupportedLiteralReason};
+
+macro_rules! reject_outside_std {
+    ($cx: ident) => {
+        // Emit errors for non-staged-api crates.
+        if !$cx.features().staged_api() {
+            $cx.emit_err(session_diagnostics::StabilityOutsideStd { span: $cx.attr_span });
+            return;
+        }
+    };
+}
 
-                if let Some((feature, level)) = parse_unstability(sess, attr) {
-                    stab = Some((Stability { level, feature }, attr.span()));
-                }
-            }
-            sym::stable => {
-                if stab.is_some() {
-                    sess.dcx().emit_err(session_diagnostics::MultipleStabilityLevels {
-                        span: attr.span(),
-                    });
-                    break;
-                }
-                if let Some((feature, level)) = parse_stability(sess, attr) {
-                    stab = Some((Stability { level, feature }, attr.span()));
-                }
-            }
-            _ => {}
+#[derive(Default)]
+pub(crate) struct StabilityParser {
+    allowed_through_unstable_modules: Option<Symbol>,
+    stability: Option<(Stability, Span)>,
+}
+
+impl StabilityParser {
+    /// Checks, and emits an error when a stability (or unstability) was already set, which would be a duplicate.
+    fn check_duplicate(&self, cx: &AcceptContext<'_>) -> bool {
+        if let Some((_, _)) = self.stability {
+            cx.emit_err(session_diagnostics::MultipleStabilityLevels { span: cx.attr_span });
+            true
+        } else {
+            false
         }
     }
+}
 
-    if let Some(allowed_through_unstable_modules) = allowed_through_unstable_modules {
-        match &mut stab {
-            Some((
+impl AttributeParser for StabilityParser {
+    const ATTRIBUTES: AcceptMapping<Self> = &[
+        (&[sym::stable], |this, cx, args| {
+            reject_outside_std!(cx);
+            if !this.check_duplicate(cx)
+                && let Some((feature, level)) = parse_stability(cx, args)
+            {
+                this.stability = Some((Stability { level, feature }, cx.attr_span));
+            }
+        }),
+        (&[sym::unstable], |this, cx, args| {
+            reject_outside_std!(cx);
+            if !this.check_duplicate(cx)
+                && let Some((feature, level)) = parse_unstability(cx, args)
+            {
+                this.stability = Some((Stability { level, feature }, cx.attr_span));
+            }
+        }),
+        (&[sym::rustc_allowed_through_unstable_modules], |this, cx, args| {
+            reject_outside_std!(cx);
+            this.allowed_through_unstable_modules =
+                Some(match args.name_value().and_then(|i| i.value_as_str()) {
+                    Some(msg) => msg,
+                    None => kw::Empty,
+                });
+        }),
+    ];
+
+    fn finalize(mut self, cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
+        if let Some(atum) = self.allowed_through_unstable_modules {
+            if let Some((
                 Stability {
-                    level: StabilityLevel::Stable { allowed_through_unstable_modules: in_stab, .. },
+                    level: StabilityLevel::Stable { ref mut allowed_through_unstable_modules, .. },
                     ..
                 },
                 _,
-            )) => *in_stab = Some(allowed_through_unstable_modules),
-            _ => {
-                sess.dcx()
-                    .emit_err(session_diagnostics::RustcAllowedUnstablePairing { span: item_sp });
+            )) = self.stability
+            {
+                *allowed_through_unstable_modules = Some(atum);
+            } else {
+                cx.dcx().emit_err(session_diagnostics::RustcAllowedUnstablePairing {
+                    span: cx.target_span,
+                });
             }
         }
-    }
 
-    stab
+        let (stability, span) = self.stability?;
+
+        Some(AttributeKind::Stability { stability, span })
+    }
 }
 
-/// Collects stability info from `rustc_const_stable`/`rustc_const_unstable`/`rustc_promotable`
-/// attributes in `attrs`. Returns `None` if no stability attributes are found.
-pub fn find_const_stability(
-    sess: &Session,
-    attrs: &[impl AttributeExt],
-    item_sp: Span,
-) -> Option<(ConstStability, Span)> {
-    let mut const_stab: Option<(ConstStability, Span)> = None;
-    let mut promotable = false;
-    let mut const_stable_indirect = false;
-
-    for attr in attrs {
-        match attr.name_or_empty() {
-            sym::rustc_promotable => promotable = true,
-            sym::rustc_const_stable_indirect => const_stable_indirect = true,
-            sym::rustc_const_unstable => {
-                if const_stab.is_some() {
-                    sess.dcx().emit_err(session_diagnostics::MultipleStabilityLevels {
-                        span: attr.span(),
-                    });
-                    break;
-                }
+// FIXME(jdonszelmann) change to Single
+#[derive(Default)]
+pub(crate) struct BodyStabilityParser {
+    stability: Option<(DefaultBodyStability, Span)>,
+}
 
-                if let Some((feature, level)) = parse_unstability(sess, attr) {
-                    const_stab = Some((
-                        ConstStability {
-                            level,
-                            feature,
-                            const_stable_indirect: false,
-                            promotable: false,
-                        },
-                        attr.span(),
-                    ));
-                }
+impl AttributeParser for BodyStabilityParser {
+    const ATTRIBUTES: AcceptMapping<Self> =
+        &[(&[sym::rustc_default_body_unstable], |this, cx, args| {
+            reject_outside_std!(cx);
+            if this.stability.is_some() {
+                cx.dcx()
+                    .emit_err(session_diagnostics::MultipleStabilityLevels { span: cx.attr_span });
+            } else if let Some((feature, level)) = parse_unstability(cx, args) {
+                this.stability = Some((DefaultBodyStability { level, feature }, cx.attr_span));
             }
-            sym::rustc_const_stable => {
-                if const_stab.is_some() {
-                    sess.dcx().emit_err(session_diagnostics::MultipleStabilityLevels {
-                        span: attr.span(),
-                    });
-                    break;
-                }
-                if let Some((feature, level)) = parse_stability(sess, attr) {
-                    const_stab = Some((
-                        ConstStability {
-                            level,
-                            feature,
-                            const_stable_indirect: false,
-                            promotable: false,
-                        },
-                        attr.span(),
-                    ));
-                }
-            }
-            _ => {}
-        }
-    }
+        })];
 
-    // Merge promotable and const_stable_indirect into stability info
-    if promotable {
-        match &mut const_stab {
-            Some((stab, _)) => stab.promotable = promotable,
-            _ => {
-                _ = sess
-                    .dcx()
-                    .emit_err(session_diagnostics::RustcPromotablePairing { span: item_sp })
-            }
-        }
+    fn finalize(self, _cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
+        let (stability, span) = self.stability?;
+
+        Some(AttributeKind::BodyStability { stability, span })
     }
-    if const_stable_indirect {
-        match &mut const_stab {
-            Some((stab, _)) => {
-                if stab.is_const_unstable() {
-                    stab.const_stable_indirect = true;
-                } else {
-                    _ = sess.dcx().emit_err(session_diagnostics::RustcConstStableIndirectPairing {
-                        span: item_sp,
-                    })
-                }
-            }
-            _ => {
-                // This function has no const stability attribute, but has `const_stable_indirect`.
-                // We ignore that; unmarked functions are subject to recursive const stability
-                // checks by default so we do carry out the user's intent.
-            }
-        }
+}
+
+pub(crate) struct ConstStabilityIndirectParser;
+// FIXME(jdonszelmann): single word attribute group when we have these
+impl SingleAttributeParser for ConstStabilityIndirectParser {
+    const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_const_stable_indirect];
+
+    // ignore
+    fn on_duplicate(_cx: &AcceptContext<'_>, _first_span: Span) {}
+
+    fn convert(_cx: &AcceptContext<'_>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
+        Some(AttributeKind::ConstStabilityIndirect)
     }
+}
 
-    const_stab
+#[derive(Default)]
+pub(crate) struct ConstStabilityParser {
+    promotable: bool,
+    stability: Option<(PartialConstStability, Span)>,
 }
 
-/// Calculates the const stability for a const function in a `-Zforce-unstable-if-unmarked` crate
-/// without the `staged_api` feature.
-pub fn unmarked_crate_const_stab(
-    _sess: &Session,
-    attrs: &[impl AttributeExt],
-    regular_stab: Stability,
-) -> ConstStability {
-    assert!(regular_stab.level.is_unstable());
-    // The only attribute that matters here is `rustc_const_stable_indirect`.
-    // We enforce recursive const stability rules for those functions.
-    let const_stable_indirect =
-        attrs.iter().any(|a| a.name_or_empty() == sym::rustc_const_stable_indirect);
-    ConstStability {
-        feature: regular_stab.feature,
-        const_stable_indirect,
-        promotable: false,
-        level: regular_stab.level,
+impl ConstStabilityParser {
+    /// Checks, and emits an error when a stability (or unstability) was already set, which would be a duplicate.
+    fn check_duplicate(&self, cx: &AcceptContext<'_>) -> bool {
+        if let Some((_, _)) = self.stability {
+            cx.emit_err(session_diagnostics::MultipleStabilityLevels { span: cx.attr_span });
+            true
+        } else {
+            false
+        }
     }
 }
 
-/// Collects stability info from `rustc_default_body_unstable` attributes in `attrs`.
-/// Returns `None` if no stability attributes are found.
-pub fn find_body_stability(
-    sess: &Session,
-    attrs: &[impl AttributeExt],
-) -> Option<(DefaultBodyStability, Span)> {
-    let mut body_stab: Option<(DefaultBodyStability, Span)> = None;
-
-    for attr in attrs {
-        if attr.has_name(sym::rustc_default_body_unstable) {
-            if body_stab.is_some() {
-                sess.dcx()
-                    .emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span() });
-                break;
+impl AttributeParser for ConstStabilityParser {
+    const ATTRIBUTES: AcceptMapping<Self> = &[
+        (&[sym::rustc_const_stable], |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,
+                ));
             }
-
-            if let Some((feature, level)) = parse_unstability(sess, attr) {
-                body_stab = Some((DefaultBodyStability { level, feature }, attr.span()));
+        }),
+        (&[sym::rustc_const_unstable], |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], |this, cx, _| {
+            reject_outside_std!(cx);
+            this.promotable = true;
+        }),
+    ];
+
+    fn finalize(mut self, cx: &FinalizeContext<'_>) -> Option<AttributeKind> {
+        if self.promotable {
+            if let Some((ref mut stab, _)) = self.stability {
+                stab.promotable = true;
+            } else {
+                cx.dcx()
+                    .emit_err(session_diagnostics::RustcPromotablePairing { span: cx.target_span });
             }
         }
-    }
 
-    body_stab
+        let (stability, span) = self.stability?;
+
+        Some(AttributeKind::ConstStability { stability, span })
+    }
 }
 
-fn insert_or_error(sess: &Session, meta: &MetaItem, item: &mut Option<Symbol>) -> Option<()> {
+/// Tries to insert the value of a `key = value` meta item into an option.
+///
+/// Emits an error when either the option was already Some, or the arguments weren't of form
+/// `name = value`
+fn insert_value_into_option_or_error(
+    cx: &AcceptContext<'_>,
+    param: &MetaItemParser<'_>,
+    item: &mut Option<Symbol>,
+) -> Option<()> {
     if item.is_some() {
-        sess.dcx().emit_err(session_diagnostics::MultipleItem {
-            span: meta.span,
-            item: pprust::path_to_string(&meta.path),
+        cx.emit_err(session_diagnostics::MultipleItem {
+            span: param.span(),
+            item: param.path_without_args().to_string(),
         });
         None
-    } else if let Some(v) = meta.value_str() {
-        *item = Some(v);
+    } else if let Some(v) = param.args().name_value()
+        && let Some(s) = v.value_as_str()
+    {
+        *item = Some(s);
         Some(())
     } else {
-        sess.dcx().emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span });
+        cx.emit_err(session_diagnostics::IncorrectMetaItem {
+            span: param.span(),
+            suggestion: None,
+        });
         None
     }
 }
 
 /// Read the content of a `stable`/`rustc_const_stable` attribute, and return the feature name and
 /// its stability information.
-fn parse_stability(sess: &Session, attr: &impl AttributeExt) -> Option<(Symbol, StabilityLevel)> {
-    let metas = attr.meta_item_list()?;
-
+pub(crate) fn parse_stability(
+    cx: &AcceptContext<'_>,
+    args: &ArgParser<'_>,
+) -> Option<(Symbol, StabilityLevel)> {
     let mut feature = None;
     let mut since = None;
-    for meta in metas {
-        let Some(mi) = meta.meta_item() else {
-            sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral {
-                span: meta.span(),
+
+    for param in args.list()?.mixed() {
+        let param_span = param.span();
+        let Some(param) = param.meta_item() else {
+            cx.emit_err(session_diagnostics::UnsupportedLiteral {
+                span: param_span,
                 reason: UnsupportedLiteralReason::Generic,
                 is_bytestr: false,
-                start_point_span: sess.source_map().start_point(meta.span()),
+                start_point_span: cx.sess().source_map().start_point(param_span),
             });
             return None;
         };
 
-        match mi.name_or_empty() {
-            sym::feature => insert_or_error(sess, mi, &mut feature)?,
-            sym::since => insert_or_error(sess, mi, &mut since)?,
+        match param.word_or_empty_without_args().name {
+            sym::feature => insert_value_into_option_or_error(cx, &param, &mut feature)?,
+            sym::since => insert_value_into_option_or_error(cx, &param, &mut since)?,
             _ => {
-                sess.dcx().emit_err(session_diagnostics::UnknownMetaItem {
-                    span: meta.span(),
-                    item: pprust::path_to_string(&mi.path),
+                cx.emit_err(session_diagnostics::UnknownMetaItem {
+                    span: param_span,
+                    item: param.path_without_args().to_string(),
                     expected: &["feature", "since"],
                 });
                 return None;
@@ -271,9 +263,9 @@ fn parse_stability(sess: &Session, attr: &impl AttributeExt) -> Option<(Symbol,
     let feature = match feature {
         Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature),
         Some(_bad_feature) => {
-            Err(sess.dcx().emit_err(session_diagnostics::NonIdentFeature { span: attr.span() }))
+            Err(cx.emit_err(session_diagnostics::NonIdentFeature { span: cx.attr_span }))
         }
-        None => Err(sess.dcx().emit_err(session_diagnostics::MissingFeature { span: attr.span() })),
+        None => Err(cx.emit_err(session_diagnostics::MissingFeature { span: cx.attr_span })),
     };
 
     let since = if let Some(since) = since {
@@ -282,11 +274,11 @@ fn parse_stability(sess: &Session, attr: &impl AttributeExt) -> Option<(Symbol,
         } else if let Some(version) = parse_version(since) {
             StableSince::Version(version)
         } else {
-            sess.dcx().emit_err(session_diagnostics::InvalidSince { span: attr.span() });
+            cx.emit_err(session_diagnostics::InvalidSince { span: cx.attr_span });
             StableSince::Err
         }
     } else {
-        sess.dcx().emit_err(session_diagnostics::MissingSince { span: attr.span() });
+        cx.emit_err(session_diagnostics::MissingSince { span: cx.attr_span });
         StableSince::Err
     };
 
@@ -299,46 +291,48 @@ fn parse_stability(sess: &Session, attr: &impl AttributeExt) -> Option<(Symbol,
     }
 }
 
-/// Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable`
+// Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable`
 /// attribute, and return the feature name and its stability information.
-fn parse_unstability(sess: &Session, attr: &impl AttributeExt) -> Option<(Symbol, StabilityLevel)> {
-    let metas = attr.meta_item_list()?;
-
+pub(crate) fn parse_unstability(
+    cx: &AcceptContext<'_>,
+    args: &ArgParser<'_>,
+) -> Option<(Symbol, StabilityLevel)> {
     let mut feature = None;
     let mut reason = None;
     let mut issue = None;
     let mut issue_num = None;
     let mut is_soft = false;
     let mut implied_by = None;
-    for meta in metas {
-        let Some(mi) = meta.meta_item() else {
-            sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral {
-                span: meta.span(),
+    for param in args.list()?.mixed() {
+        let Some(param) = param.meta_item() else {
+            cx.emit_err(session_diagnostics::UnsupportedLiteral {
+                span: param.span(),
                 reason: UnsupportedLiteralReason::Generic,
                 is_bytestr: false,
-                start_point_span: sess.source_map().start_point(meta.span()),
+                start_point_span: cx.sess().source_map().start_point(param.span()),
             });
             return None;
         };
 
-        match mi.name_or_empty() {
-            sym::feature => insert_or_error(sess, mi, &mut feature)?,
-            sym::reason => insert_or_error(sess, mi, &mut reason)?,
+        let (word, args) = param.word_or_empty();
+        match word.name {
+            sym::feature => insert_value_into_option_or_error(cx, &param, &mut feature)?,
+            sym::reason => insert_value_into_option_or_error(cx, &param, &mut reason)?,
             sym::issue => {
-                insert_or_error(sess, mi, &mut issue)?;
+                insert_value_into_option_or_error(cx, &param, &mut issue)?;
 
-                // These unwraps are safe because `insert_or_error` ensures the meta item
+                // These unwraps are safe because `insert_value_into_option_or_error` ensures the meta item
                 // is a name/value pair string literal.
                 issue_num = match issue.unwrap().as_str() {
                     "none" => None,
-                    issue => match issue.parse::<NonZero<u32>>() {
+                    issue_str => match issue_str.parse::<NonZero<u32>>() {
                         Ok(num) => Some(num),
                         Err(err) => {
-                            sess.dcx().emit_err(
+                            cx.emit_err(
                                 session_diagnostics::InvalidIssueString {
-                                    span: mi.span,
+                                    span: param.span(),
                                     cause: session_diagnostics::InvalidIssueStringCause::from_int_error_kind(
-                                        mi.name_value_literal_span().unwrap(),
+                                        args.name_value().unwrap().value_span,
                                         err.kind(),
                                     ),
                                 },
@@ -349,16 +343,16 @@ fn parse_unstability(sess: &Session, attr: &impl AttributeExt) -> Option<(Symbol
                 };
             }
             sym::soft => {
-                if !mi.is_word() {
-                    sess.dcx().emit_err(session_diagnostics::SoftNoArgs { span: mi.span });
+                if !args.no_args() {
+                    cx.emit_err(session_diagnostics::SoftNoArgs { span: param.span() });
                 }
                 is_soft = true;
             }
-            sym::implied_by => insert_or_error(sess, mi, &mut implied_by)?,
+            sym::implied_by => insert_value_into_option_or_error(cx, &param, &mut implied_by)?,
             _ => {
-                sess.dcx().emit_err(session_diagnostics::UnknownMetaItem {
-                    span: meta.span(),
-                    item: pprust::path_to_string(&mi.path),
+                cx.emit_err(session_diagnostics::UnknownMetaItem {
+                    span: param.span(),
+                    item: param.path_without_args().to_string(),
                     expected: &["feature", "reason", "issue", "soft", "implied_by"],
                 });
                 return None;
@@ -369,14 +363,13 @@ fn parse_unstability(sess: &Session, attr: &impl AttributeExt) -> Option<(Symbol
     let feature = match feature {
         Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature),
         Some(_bad_feature) => {
-            Err(sess.dcx().emit_err(session_diagnostics::NonIdentFeature { span: attr.span() }))
+            Err(cx.emit_err(session_diagnostics::NonIdentFeature { span: cx.attr_span }))
         }
-        None => Err(sess.dcx().emit_err(session_diagnostics::MissingFeature { span: attr.span() })),
+        None => Err(cx.emit_err(session_diagnostics::MissingFeature { span: cx.attr_span })),
     };
 
-    let issue = issue.ok_or_else(|| {
-        sess.dcx().emit_err(session_diagnostics::MissingIssue { span: attr.span() })
-    });
+    let issue =
+        issue.ok_or_else(|| cx.emit_err(session_diagnostics::MissingIssue { span: cx.attr_span }));
 
     match (feature, issue) {
         (Ok(feature), Ok(_)) => {
diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs
index f4065a77048..ad83a1f7af8 100644
--- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs
@@ -1,36 +1,33 @@
-use rustc_ast::attr::AttributeExt;
-use rustc_attr_data_structures::TransparencyError;
+use rustc_attr_data_structures::AttributeKind;
 use rustc_span::hygiene::Transparency;
 use rustc_span::sym;
 
-pub fn find_transparency(
-    attrs: &[impl AttributeExt],
-    macro_rules: bool,
-) -> (Transparency, Option<TransparencyError>) {
-    let mut transparency = None;
-    let mut error = None;
-    for attr in attrs {
-        if attr.has_name(sym::rustc_macro_transparency) {
-            if let Some((_, old_span)) = transparency {
-                error = Some(TransparencyError::MultipleTransparencyAttrs(old_span, attr.span()));
-                break;
-            } else if let Some(value) = attr.value_str() {
-                transparency = Some((
-                    match value {
-                        sym::transparent => Transparency::Transparent,
-                        sym::semitransparent => Transparency::SemiTransparent,
-                        sym::opaque => Transparency::Opaque,
-                        _ => {
-                            error =
-                                Some(TransparencyError::UnknownTransparency(value, attr.span()));
-                            continue;
-                        }
-                    },
-                    attr.span(),
-                ));
+use super::{AcceptContext, SingleAttributeParser};
+use crate::parser::ArgParser;
+
+pub(crate) struct TransparencyParser;
+
+// FIXME(jdonszelmann): make these proper diagnostics
+#[allow(rustc::untranslatable_diagnostic)]
+#[allow(rustc::diagnostic_outside_of_impl)]
+impl SingleAttributeParser for TransparencyParser {
+    const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_macro_transparency];
+
+    fn on_duplicate(cx: &crate::context::AcceptContext<'_>, first_span: rustc_span::Span) {
+        cx.dcx().span_err(vec![first_span, cx.attr_span], "multiple macro transparency attributes");
+    }
+
+    fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+        match args.name_value().and_then(|nv| nv.value_as_str()) {
+            Some(sym::transparent) => Some(Transparency::Transparent),
+            Some(sym::semitransparent) => Some(Transparency::SemiTransparent),
+            Some(sym::opaque) => Some(Transparency::Opaque),
+            Some(other) => {
+                cx.dcx().span_err(cx.attr_span, format!("unknown macro transparency: `{other}`"));
+                None
             }
+            None => None,
         }
+        .map(AttributeKind::MacroTransparency)
     }
-    let fallback = if macro_rules { Transparency::SemiTransparent } else { Transparency::Opaque };
-    (transparency.map_or(fallback, |t| t.0), error)
 }
diff --git a/compiler/rustc_attr_parsing/src/attributes/util.rs b/compiler/rustc_attr_parsing/src/attributes/util.rs
index e36f7dfff5a..05a9029c59a 100644
--- a/compiler/rustc_attr_parsing/src/attributes/util.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/util.rs
@@ -3,22 +3,6 @@ use rustc_attr_data_structures::RustcVersion;
 use rustc_feature::is_builtin_attr_name;
 use rustc_span::{Symbol, sym};
 
-pub(crate) enum UnsupportedLiteralReason {
-    Generic,
-    CfgString,
-    CfgBoolean,
-    DeprecatedString,
-    DeprecatedKvPair,
-}
-
-pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool {
-    attr.is_doc_comment() || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name))
-}
-
-pub fn find_crate_name(attrs: &[impl AttributeExt]) -> Option<Symbol> {
-    first_attr_value_str_by_name(attrs, sym::crate_name)
-}
-
 /// Parse a rustc version number written inside string literal in an attribute,
 /// like appears in `since = "1.0.0"`. Suffixes like "-dev" and "-nightly" are
 /// not accepted in this position, unlike when parsing CFG_RELEASE.
@@ -34,3 +18,11 @@ pub fn parse_version(s: Symbol) -> Option<RustcVersion> {
     let patch = digits.next().unwrap_or("0").parse().ok()?;
     Some(RustcVersion { major, minor, patch })
 }
+
+pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool {
+    attr.is_doc_comment() || attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name))
+}
+
+pub fn find_crate_name(attrs: &[impl AttributeExt]) -> Option<Symbol> {
+    first_attr_value_str_by_name(attrs, sym::crate_name)
+}
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
new file mode 100644
index 00000000000..99eee0d3c4a
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -0,0 +1,348 @@
+use std::cell::RefCell;
+use std::collections::BTreeMap;
+use std::ops::Deref;
+use std::sync::LazyLock;
+
+use rustc_ast::{self as ast, DelimArgs};
+use rustc_attr_data_structures::AttributeKind;
+use rustc_errors::{DiagCtxtHandle, Diagnostic};
+use rustc_feature::Features;
+use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId};
+use rustc_session::Session;
+use rustc_span::symbol::kw;
+use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
+
+use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
+use crate::attributes::confusables::ConfusablesParser;
+use crate::attributes::deprecation::DeprecationParser;
+use crate::attributes::repr::ReprParser;
+use crate::attributes::stability::{
+    BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
+};
+use crate::attributes::transparency::TransparencyParser;
+use crate::attributes::{AttributeParser as _, Combine, Single};
+use crate::parser::{ArgParser, MetaItemParser};
+
+macro_rules! attribute_groups {
+    (
+        pub(crate) static $name: ident = [$($names: ty),* $(,)?];
+    ) => {
+        pub(crate) static $name: LazyLock<(
+            BTreeMap<&'static [Symbol], Vec<Box<dyn Fn(&AcceptContext<'_>, &ArgParser<'_>) + Send + Sync>>>,
+            Vec<Box<dyn Send + Sync + Fn(&FinalizeContext<'_>) -> Option<AttributeKind>>>
+        )> = LazyLock::new(|| {
+            let mut accepts = BTreeMap::<_, Vec<Box<dyn Fn(&AcceptContext<'_>, &ArgParser<'_>) + Send + Sync>>>::new();
+            let mut finalizes = Vec::<Box<dyn Send + Sync + Fn(&FinalizeContext<'_>) -> Option<AttributeKind>>>::new();
+            $(
+                {
+                    thread_local! {
+                        static STATE_OBJECT: RefCell<$names> = RefCell::new(<$names>::default());
+                    };
+
+                    for (k, v) in <$names>::ATTRIBUTES {
+                        accepts.entry(*k).or_default().push(Box::new(|cx, args| {
+                            STATE_OBJECT.with_borrow_mut(|s| {
+                                v(s, cx, args)
+                            })
+                        }));
+                    }
+
+                    finalizes.push(Box::new(|cx| {
+                        let state = STATE_OBJECT.take();
+                        state.finalize(cx)
+                    }));
+                }
+            )*
+
+            (accepts, finalizes)
+        });
+    };
+}
+
+attribute_groups!(
+    pub(crate) static ATTRIBUTE_MAPPING = [
+        // tidy-alphabetical-start
+        BodyStabilityParser,
+        ConfusablesParser,
+        ConstStabilityParser,
+        StabilityParser,
+        // tidy-alphabetical-end
+
+        // tidy-alphabetical-start
+        Combine<AllowConstFnUnstableParser>,
+        Combine<AllowInternalUnstableParser>,
+        Combine<ReprParser>,
+        // tidy-alphabetical-end
+
+        // tidy-alphabetical-start
+        Single<ConstStabilityIndirectParser>,
+        Single<DeprecationParser>,
+        Single<TransparencyParser>,
+        // tidy-alphabetical-end
+    ];
+);
+
+/// Context given to every attribute parser when accepting
+///
+/// Gives [`AttributeParser`]s enough information to create errors, for example.
+pub(crate) struct AcceptContext<'a> {
+    pub(crate) group_cx: &'a FinalizeContext<'a>,
+    /// The span of the attribute currently being parsed
+    pub(crate) attr_span: Span,
+}
+
+impl<'a> AcceptContext<'a> {
+    pub(crate) fn emit_err(&self, diag: impl Diagnostic<'a>) -> ErrorGuaranteed {
+        if self.limit_diagnostics {
+            self.dcx().create_err(diag).delay_as_bug()
+        } else {
+            self.dcx().emit_err(diag)
+        }
+    }
+}
+
+impl<'a> Deref for AcceptContext<'a> {
+    type Target = FinalizeContext<'a>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.group_cx
+    }
+}
+
+/// Context given to every attribute parser during finalization.
+///
+/// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create errors, for example.
+pub(crate) struct FinalizeContext<'a> {
+    /// The parse context, gives access to the session and the
+    /// diagnostics context.
+    pub(crate) cx: &'a AttributeParser<'a>,
+    /// The span of the syntactical component this attribute was applied to
+    pub(crate) target_span: Span,
+}
+
+impl<'a> Deref for FinalizeContext<'a> {
+    type Target = AttributeParser<'a>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.cx
+    }
+}
+
+#[derive(PartialEq, Clone, Copy, Debug)]
+pub enum OmitDoc {
+    Lower,
+    Skip,
+}
+
+/// Context created once, for example as part of the ast lowering
+/// context, through which all attributes can be lowered.
+pub struct AttributeParser<'sess> {
+    #[expect(dead_code)] // FIXME(jdonszelmann): needed later to verify we parsed all attributes
+    tools: Vec<Symbol>,
+    sess: &'sess Session,
+    features: Option<&'sess Features>,
+
+    /// *only* parse attributes with this symbol.
+    ///
+    /// Used in cases where we want the lowering infrastructure for
+    /// parse just a single attribute.
+    parse_only: Option<Symbol>,
+
+    /// Can be used to instruct parsers to reduce the number of diagnostics it emits.
+    /// Useful when using `parse_limited` and you know the attr will be reparsed later.
+    pub(crate) limit_diagnostics: bool,
+}
+
+impl<'sess> AttributeParser<'sess> {
+    /// This method allows you to parse attributes *before* you have access to features or tools.
+    /// One example where this is necessary, is to parse `feature` attributes themselves for
+    /// example.
+    ///
+    /// Try to use this as little as possible. Attributes *should* be lowered during `rustc_ast_lowering`.
+    /// Some attributes require access to features to parse, which would crash if you tried to do so
+    /// through [`parse_limited`](Self::parse_limited).
+    ///
+    /// To make sure use is limited, supply a `Symbol` you'd like to parse. Only attributes with
+    /// that symbol are picked out of the list of instructions and parsed. Those are returned.
+    pub fn parse_limited(
+        sess: &'sess Session,
+        attrs: &[ast::Attribute],
+        sym: Symbol,
+        target_span: Span,
+        limit_diagnostics: bool,
+    ) -> Option<Attribute> {
+        let mut parsed = Self {
+            sess,
+            features: None,
+            tools: Vec::new(),
+            parse_only: Some(sym),
+            limit_diagnostics,
+        }
+        .parse_attribute_list(attrs, target_span, OmitDoc::Skip, std::convert::identity);
+
+        assert!(parsed.len() <= 1);
+
+        parsed.pop()
+    }
+
+    pub fn new(sess: &'sess Session, features: &'sess Features, tools: Vec<Symbol>) -> Self {
+        Self { sess, features: Some(features), tools, parse_only: None, limit_diagnostics: false }
+    }
+
+    pub(crate) fn sess(&self) -> &'sess Session {
+        self.sess
+    }
+
+    pub(crate) fn features(&self) -> &'sess Features {
+        self.features.expect("features not available at this point in the compiler")
+    }
+
+    pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> {
+        self.sess.dcx()
+    }
+
+    /// Parse a list of attributes.
+    ///
+    /// `target_span` is the span of the thing this list of attributes is applied to,
+    /// and when `omit_doc` is set, doc attributes are filtered out.
+    pub fn parse_attribute_list<'a>(
+        &'a self,
+        attrs: &'a [ast::Attribute],
+        target_span: Span,
+        omit_doc: OmitDoc,
+
+        lower_span: impl Copy + Fn(Span) -> Span,
+    ) -> Vec<Attribute> {
+        let mut attributes = Vec::new();
+
+        let group_cx = FinalizeContext { cx: self, target_span };
+
+        for attr in attrs {
+            // if we're only looking for a single attribute,
+            // skip all the ones we don't care about
+            if let Some(expected) = self.parse_only {
+                if attr.name_or_empty() != expected {
+                    continue;
+                }
+            }
+
+            // sometimes, for example for `#![doc = include_str!("readme.md")]`,
+            // doc still contains a non-literal. You might say, when we're lowering attributes
+            // that's expanded right? But no, sometimes, when parsing attributes on macros,
+            // we already use the lowering logic and these are still there. So, when `omit_doc`
+            // is set we *also* want to ignore these
+            if omit_doc == OmitDoc::Skip && attr.name_or_empty() == sym::doc {
+                continue;
+            }
+
+            match &attr.kind {
+                ast::AttrKind::DocComment(comment_kind, symbol) => {
+                    if omit_doc == OmitDoc::Skip {
+                        continue;
+                    }
+
+                    attributes.push(Attribute::Parsed(AttributeKind::DocComment {
+                        style: attr.style,
+                        kind: *comment_kind,
+                        span: lower_span(attr.span),
+                        comment: *symbol,
+                    }))
+                }
+                // // FIXME: make doc attributes go through a proper attribute parser
+                // ast::AttrKind::Normal(n) if n.name_or_empty() == sym::doc => {
+                //     let p = GenericMetaItemParser::from_attr(&n, self.dcx());
+                //
+                //     attributes.push(Attribute::Parsed(AttributeKind::DocComment {
+                //         style: attr.style,
+                //         kind: CommentKind::Line,
+                //         span: attr.span,
+                //         comment: p.args().name_value(),
+                //     }))
+                // }
+                ast::AttrKind::Normal(n) => {
+                    let parser = MetaItemParser::from_attr(n, self.dcx());
+                    let (path, args) = parser.deconstruct();
+                    let parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
+
+                    if let Some(accepts) = ATTRIBUTE_MAPPING.0.get(parts.as_slice()) {
+                        for f in accepts {
+                            let cx = AcceptContext {
+                                group_cx: &group_cx,
+                                attr_span: lower_span(attr.span),
+                            };
+
+                            f(&cx, &args)
+                        }
+                    } else {
+                        // if we're here, we must be compiling a tool attribute... Or someone forgot to
+                        // parse their fancy new attribute. Let's warn them in any case. If you are that
+                        // person, and you really your attribute should remain unparsed, carefully read the
+                        // documentation in this module and if you still think so you can add an exception
+                        // to this assertion.
+
+                        // FIXME(jdonszelmann): convert other attributes, and check with this that
+                        // we caught em all
+                        // const FIXME_TEMPORARY_ATTR_ALLOWLIST: &[Symbol] = &[sym::cfg];
+                        // assert!(
+                        //     self.tools.contains(&parts[0]) || true,
+                        //     // || FIXME_TEMPORARY_ATTR_ALLOWLIST.contains(&parts[0]),
+                        //     "attribute {path} wasn't parsed and isn't a know tool attribute",
+                        // );
+
+                        attributes.push(Attribute::Unparsed(Box::new(AttrItem {
+                            path: AttrPath::from_ast(&n.item.path),
+                            args: self.lower_attr_args(&n.item.args, lower_span),
+                            id: HashIgnoredAttrId { attr_id: attr.id },
+                            style: attr.style,
+                            span: lower_span(attr.span),
+                        })));
+                    }
+                }
+            }
+        }
+
+        let mut parsed_attributes = Vec::new();
+        for f in &ATTRIBUTE_MAPPING.1 {
+            if let Some(attr) = f(&group_cx) {
+                parsed_attributes.push(Attribute::Parsed(attr));
+            }
+        }
+
+        attributes.extend(parsed_attributes);
+
+        attributes
+    }
+
+    fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs {
+        match args {
+            ast::AttrArgs::Empty => AttrArgs::Empty,
+            ast::AttrArgs::Delimited(args) => AttrArgs::Delimited(DelimArgs {
+                dspan: args.dspan,
+                delim: args.delim,
+                tokens: args.tokens.flattened(),
+            }),
+            // This is an inert key-value attribute - it will never be visible to macros
+            // after it gets lowered to HIR. Therefore, we can extract literals to handle
+            // nonterminals in `#[doc]` (e.g. `#[doc = $e]`).
+            ast::AttrArgs::Eq { eq_span, expr } => {
+                // In valid code the value always ends up as a single literal. Otherwise, a dummy
+                // literal suffices because the error is handled elsewhere.
+                let lit = if let ast::ExprKind::Lit(token_lit) = expr.kind
+                    && let Ok(lit) =
+                        ast::MetaItemLit::from_token_lit(token_lit, lower_span(expr.span))
+                {
+                    lit
+                } else {
+                    let guar = self.dcx().has_errors().unwrap();
+                    ast::MetaItemLit {
+                        symbol: kw::Empty,
+                        suffix: None,
+                        kind: ast::LitKind::Err(guar),
+                        span: DUMMY_SP,
+                    }
+                };
+                AttrArgs::Eq { eq_span: lower_span(*eq_span), expr: lit }
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs
index a1264a6875f..9841166b37d 100644
--- a/compiler/rustc_attr_parsing/src/lib.rs
+++ b/compiler/rustc_attr_parsing/src/lib.rs
@@ -1,8 +1,79 @@
-//! Functions and types dealing with attributes and meta items.
+//! Centralized logic for parsing and attributes.
 //!
-//! FIXME(Centril): For now being, much of the logic is still in `rustc_ast::attr`.
-//! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax`
-//! to this crate.
+//! Part of a series of crates:
+//! - rustc_attr_data_structures: contains types that the parsers parse into
+//! - rustc_attr_parsing: this crate
+//! - (in the future): rustc_attr_validation
+//!
+//! History: Check out [#131229](https://github.com/rust-lang/rust/issues/131229).
+//! There used to be only one definition of attributes in the compiler: `ast::Attribute`.
+//! These were then parsed or validated or both in places distributed all over the compiler.
+//! This was a mess...
+//!
+//! Attributes are markers on items.
+//! Many of them are actually attribute-like proc-macros, and are expanded to some other rust syntax.
+//! This could either be a user provided proc macro, or something compiler provided.
+//! `derive` is an example of one that the compiler provides.
+//! These are built-in, but they have a valid expansion to Rust tokens and are thus called "active".
+//! I personally like calling these *active* compiler-provided attributes, built-in *macros*,
+//! because they still expand, and this helps to differentiate them from built-in *attributes*.
+//! However, I'll be the first to admit that the naming here can be confusing.
+//!
+//! The alternative to active attributes, are inert attributes.
+//! These can occur in user code (proc-macro helper attributes).
+//! But what's important is, many built-in attributes are inert like this.
+//! There is nothing they expand to during the macro expansion process,
+//! sometimes because they literally cannot expand to something that is valid Rust.
+//! They are really just markers to guide the compilation process.
+//! An example is `#[inline(...)]` which changes how code for functions is generated.
+//!
+//! ```text
+//!                      Active                 Inert
+//!              ┌──────────────────────┬──────────────────────┐
+//!              │     (mostly in)      │    these are parsed  │
+//!              │ rustc_builtin_macros │        here!         │
+//!              │                      │                      │
+//!              │                      │                      │
+//!              │    #[derive(...)]    │    #[stable()]       │
+//!     Built-in │    #[cfg()]          │    #[inline()]       │
+//!              │    #[cfg_attr()]     │    #[repr()]         │
+//!              │                      │                      │
+//!              │                      │                      │
+//!              │                      │                      │
+//!              ├──────────────────────┼──────────────────────┤
+//!              │                      │                      │
+//!              │                      │                      │
+//!              │                      │       `b` in         │
+//!              │                      │ #[proc_macro_derive( │
+//! User created │ #[proc_macro_attr()] │    a,                │
+//!              │                      │    attributes(b)     │
+//!              │                      │ ]                    │
+//!              │                      │                      │
+//!              │                      │                      │
+//!              │                      │                      │
+//!              └──────────────────────┴──────────────────────┘
+//! ```
+//!
+//! In this crate, syntactical attributes (sequences of tokens that look like
+//! `#[something(something else)]`) are parsed into more semantic attributes, markers on items.
+//! Multiple syntactic attributes might influence a single semantic attribute. For example,
+//! `#[stable(...)]` and `#[unstable()]` cannot occur together, and both semantically define
+//! a "stability" of an item. So, the stability attribute has an
+//! [`AttributeParser`](attributes::AttributeParser) that recognizes both the `#[stable()]`
+//! and `#[unstable()]` syntactic attributes, and at the end produce a single [`AttributeKind::Stability`].
+//!
+//! As a rule of thumb, when a syntactical attribute can be applied more than once, they should be
+//! combined into a single semantic attribute. For example:
+//!
+//! ```
+//! #[repr(C)]
+//! #[repr(packed)]
+//! struct Meow {}
+//! ```
+//!
+//! should result in a single `AttributeKind::Repr` containing a list of repr annotations, in this
+//! case `C` and `packed`. This is equivalent to writing `#[repr(C, packed)]` in a single
+//! syntactical annotation.
 
 // tidy-alphabetical-start
 #![allow(internal_features)]
@@ -12,11 +83,59 @@
 #![warn(unreachable_pub)]
 // tidy-alphabetical-end
 
+#[macro_use]
 mod attributes;
+mod context;
+pub mod parser;
 mod session_diagnostics;
 
-pub use attributes::*;
+pub use attributes::cfg::*;
+pub use attributes::util::{find_crate_name, is_builtin_attr, parse_version};
+pub use context::{AttributeParser, OmitDoc};
 pub use rustc_attr_data_structures::*;
-pub use util::{find_crate_name, is_builtin_attr, parse_version};
 
 rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
+
+/// Finds attributes in sequences of attributes by pattern matching.
+///
+/// A little like `matches` but for attributes.
+///
+/// ```rust,ignore (illustrative)
+/// // finds the repr attribute
+/// if let Some(r) = find_attr!(attrs, AttributeKind::Repr(r) => r) {
+///
+/// }
+///
+/// // checks if one has matched
+/// if find_attr!(attrs, AttributeKind::Repr(_)) {
+///
+/// }
+/// ```
+///
+/// Often this requires you to first end up with a list of attributes.
+/// A common way to get those is through `tcx.get_all_attrs(did)`
+#[macro_export]
+macro_rules! find_attr {
+    ($attributes_list: expr, $pattern: pat $(if $guard: expr)?) => {{
+        $crate::find_attr!($attributes_list, $pattern $(if $guard)? => ()).is_some()
+    }};
+
+    ($attributes_list: expr, $pattern: pat $(if $guard: expr)? => $e: expr) => {{
+        fn check_attribute_iterator<'a>(_: &'_ impl IntoIterator<Item = &'a rustc_hir::Attribute>) {}
+        check_attribute_iterator(&$attributes_list);
+
+        let find_attribute = |iter| {
+            for i in $attributes_list {
+                match i {
+                    rustc_hir::Attribute::Parsed($pattern) $(if $guard)? => {
+                        return Some($e);
+                    }
+                    _ => {}
+                }
+            }
+
+            None
+        };
+        find_attribute($attributes_list)
+    }};
+}
diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs
new file mode 100644
index 00000000000..0ee0ea4ea59
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/parser.rs
@@ -0,0 +1,624 @@
+//! This is in essence an (improved) duplicate of `rustc_ast/attr/mod.rs`.
+//! That module is intended to be deleted in its entirety.
+//!
+//! FIXME(jdonszelmann): delete `rustc_ast/attr/mod.rs`
+
+use std::fmt::{Debug, Display};
+use std::iter::Peekable;
+
+use rustc_ast::token::{self, Delimiter, Token};
+use rustc_ast::tokenstream::{TokenStreamIter, TokenTree};
+use rustc_ast::{AttrArgs, DelimArgs, Expr, ExprKind, LitKind, MetaItemLit, NormalAttr, Path};
+use rustc_ast_pretty::pprust;
+use rustc_errors::DiagCtxtHandle;
+use rustc_hir::{self as hir, AttrPath};
+use rustc_span::symbol::{Ident, kw};
+use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol};
+
+pub struct SegmentIterator<'a> {
+    offset: usize,
+    path: &'a PathParser<'a>,
+}
+
+impl<'a> Iterator for SegmentIterator<'a> {
+    type Item = &'a Ident;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.offset >= self.path.len() {
+            return None;
+        }
+
+        let res = match self.path {
+            PathParser::Ast(ast_path) => &ast_path.segments[self.offset].ident,
+            PathParser::Attr(attr_path) => &attr_path.segments[self.offset],
+        };
+
+        self.offset += 1;
+        Some(res)
+    }
+}
+
+#[derive(Clone, Debug)]
+pub enum PathParser<'a> {
+    Ast(&'a Path),
+    Attr(AttrPath),
+}
+
+impl<'a> PathParser<'a> {
+    pub fn get_attribute_path(&self) -> hir::AttrPath {
+        AttrPath {
+            segments: self.segments().copied().collect::<Vec<_>>().into_boxed_slice(),
+            span: self.span(),
+        }
+    }
+
+    pub fn segments(&'a self) -> impl Iterator<Item = &'a Ident> {
+        SegmentIterator { offset: 0, path: self }
+    }
+
+    pub fn span(&self) -> Span {
+        match self {
+            PathParser::Ast(path) => path.span,
+            PathParser::Attr(attr_path) => attr_path.span,
+        }
+    }
+
+    pub fn len(&self) -> usize {
+        match self {
+            PathParser::Ast(path) => path.segments.len(),
+            PathParser::Attr(attr_path) => attr_path.segments.len(),
+        }
+    }
+
+    pub fn segments_is(&self, segments: &[Symbol]) -> bool {
+        self.len() == segments.len() && self.segments().zip(segments).all(|(a, b)| a.name == *b)
+    }
+
+    pub fn word(&self) -> Option<Ident> {
+        (self.len() == 1).then(|| **self.segments().next().as_ref().unwrap())
+    }
+
+    pub fn word_or_empty(&self) -> Ident {
+        self.word().unwrap_or_else(Ident::empty)
+    }
+
+    /// Asserts that this MetaItem is some specific word.
+    ///
+    /// See [`word`](Self::word) for examples of what a word is.
+    pub fn word_is(&self, sym: Symbol) -> bool {
+        self.word().map(|i| i.name == sym).unwrap_or(false)
+    }
+}
+
+impl Display for PathParser<'_> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            PathParser::Ast(path) => write!(f, "{}", pprust::path_to_string(path)),
+            PathParser::Attr(attr_path) => write!(f, "{attr_path}"),
+        }
+    }
+}
+
+#[derive(Clone, Debug)]
+#[must_use]
+pub enum ArgParser<'a> {
+    NoArgs,
+    List(MetaItemListParser<'a>),
+    NameValue(NameValueParser),
+}
+
+impl<'a> ArgParser<'a> {
+    pub fn span(&self) -> Option<Span> {
+        match self {
+            Self::NoArgs => None,
+            Self::List(l) => Some(l.span),
+            Self::NameValue(n) => Some(n.value_span.with_lo(n.eq_span.lo())),
+        }
+    }
+
+    pub fn from_attr_args(value: &'a AttrArgs, dcx: DiagCtxtHandle<'a>) -> Self {
+        match value {
+            AttrArgs::Empty => Self::NoArgs,
+            AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
+                Self::List(MetaItemListParser::new(args, dcx))
+            }
+            AttrArgs::Delimited(args) => {
+                Self::List(MetaItemListParser { sub_parsers: vec![], span: args.dspan.entire() })
+            }
+            AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser {
+                eq_span: *eq_span,
+                value: expr_to_lit(dcx, &expr),
+                value_span: expr.span,
+            }),
+        }
+    }
+
+    /// Asserts that this MetaItem is a list
+    ///
+    /// Some examples:
+    ///
+    /// - `#[allow(clippy::complexity)]`: `(clippy::complexity)` is a list
+    /// - `#[rustfmt::skip::macros(target_macro_name)]`: `(target_macro_name)` is a list
+    pub fn list(&self) -> Option<&MetaItemListParser<'a>> {
+        match self {
+            Self::List(l) => Some(l),
+            Self::NameValue(_) | Self::NoArgs => None,
+        }
+    }
+
+    /// Asserts that this MetaItem is a name-value pair.
+    ///
+    /// Some examples:
+    ///
+    /// - `#[clippy::cyclomatic_complexity = "100"]`: `clippy::cyclomatic_complexity = "100"` is a name value pair,
+    ///   where the name is a path (`clippy::cyclomatic_complexity`). You already checked the path
+    ///   to get an `ArgParser`, so this method will effectively only assert that the `= "100"` is
+    ///   there
+    /// - `#[doc = "hello"]`: `doc = "hello`  is also a name value pair
+    pub fn name_value(&self) -> Option<&NameValueParser> {
+        match self {
+            Self::NameValue(n) => Some(n),
+            Self::List(_) | Self::NoArgs => None,
+        }
+    }
+
+    /// Asserts that there are no arguments
+    pub fn no_args(&self) -> bool {
+        matches!(self, Self::NoArgs)
+    }
+}
+
+/// Inside lists, values could be either literals, or more deeply nested meta items.
+/// This enum represents that.
+///
+/// Choose which one you want using the provided methods.
+#[derive(Debug, Clone)]
+pub enum MetaItemOrLitParser<'a> {
+    MetaItemParser(MetaItemParser<'a>),
+    Lit(MetaItemLit),
+    Err(Span, ErrorGuaranteed),
+}
+
+impl<'a> MetaItemOrLitParser<'a> {
+    pub fn span(&self) -> Span {
+        match self {
+            MetaItemOrLitParser::MetaItemParser(generic_meta_item_parser) => {
+                generic_meta_item_parser.span()
+            }
+            MetaItemOrLitParser::Lit(meta_item_lit) => meta_item_lit.span,
+            MetaItemOrLitParser::Err(span, _) => *span,
+        }
+    }
+
+    pub fn lit(&self) -> Option<&MetaItemLit> {
+        match self {
+            MetaItemOrLitParser::Lit(meta_item_lit) => Some(meta_item_lit),
+            _ => None,
+        }
+    }
+
+    pub fn meta_item(&self) -> Option<&MetaItemParser<'a>> {
+        match self {
+            MetaItemOrLitParser::MetaItemParser(parser) => Some(parser),
+            _ => None,
+        }
+    }
+}
+
+/// Utility that deconstructs a MetaItem into usable parts.
+///
+/// MetaItems are syntactically extremely flexible, but specific attributes want to parse
+/// them in custom, more restricted ways. This can be done using this struct.
+///
+/// MetaItems consist of some path, and some args. The args could be empty. In other words:
+///
+/// - `name` -> args are empty
+/// - `name(...)` -> args are a [`list`](ArgParser::list), which is the bit between the parentheses
+/// - `name = value`-> arg is [`name_value`](ArgParser::name_value), where the argument is the
+///   `= value` part
+///
+/// The syntax of MetaItems can be found at <https://doc.rust-lang.org/reference/attributes.html>
+#[derive(Clone)]
+pub struct MetaItemParser<'a> {
+    path: PathParser<'a>,
+    args: ArgParser<'a>,
+}
+
+impl<'a> Debug for MetaItemParser<'a> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.debug_struct("MetaItemParser")
+            .field("path", &self.path)
+            .field("args", &self.args)
+            .finish()
+    }
+}
+
+impl<'a> MetaItemParser<'a> {
+    /// Create a new parser from a [`NormalAttr`], which is stored inside of any
+    /// [`ast::Attribute`](rustc_ast::Attribute)
+    pub fn from_attr(attr: &'a NormalAttr, dcx: DiagCtxtHandle<'a>) -> Self {
+        Self {
+            path: PathParser::Ast(&attr.item.path),
+            args: ArgParser::from_attr_args(&attr.item.args, dcx),
+        }
+    }
+}
+
+impl<'a> MetaItemParser<'a> {
+    pub fn span(&self) -> Span {
+        if let Some(other) = self.args.span() {
+            self.path.span().with_hi(other.hi())
+        } else {
+            self.path.span()
+        }
+    }
+
+    /// Gets just the path, without the args.
+    pub fn path_without_args(&self) -> PathParser<'a> {
+        self.path.clone()
+    }
+
+    /// Gets just the args parser, without caring about the path.
+    pub fn args(&self) -> &ArgParser<'a> {
+        &self.args
+    }
+
+    pub fn deconstruct(&self) -> (PathParser<'a>, &ArgParser<'a>) {
+        (self.path_without_args(), self.args())
+    }
+
+    /// Asserts that this MetaItem starts with a path. Some examples:
+    ///
+    /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path
+    /// - `#[allow(clippy::complexity)]`: `clippy::complexity` is a path
+    /// - `#[inline]`: `inline` is a single segment path
+    pub fn path(&self) -> (PathParser<'a>, &ArgParser<'a>) {
+        self.deconstruct()
+    }
+
+    /// Asserts that this MetaItem starts with a word, or single segment path.
+    /// Doesn't return the args parser.
+    ///
+    /// For examples. see [`Self::word`]
+    pub fn word_without_args(&self) -> Option<Ident> {
+        Some(self.word()?.0)
+    }
+
+    /// Like [`word`](Self::word), but returns an empty symbol instead of None
+    pub fn word_or_empty_without_args(&self) -> Ident {
+        self.word_or_empty().0
+    }
+
+    /// Asserts that this MetaItem starts with a word, or single segment path.
+    ///
+    /// Some examples:
+    /// - `#[inline]`: `inline` is a word
+    /// - `#[rustfmt::skip]`: `rustfmt::skip` is a path,
+    ///   and not a word and should instead be parsed using [`path`](Self::path)
+    pub fn word(&self) -> Option<(Ident, &ArgParser<'a>)> {
+        let (path, args) = self.deconstruct();
+        Some((path.word()?, args))
+    }
+
+    /// Like [`word`](Self::word), but returns an empty symbol instead of None
+    pub fn word_or_empty(&self) -> (Ident, &ArgParser<'a>) {
+        let (path, args) = self.deconstruct();
+        (path.word().unwrap_or(Ident::empty()), args)
+    }
+
+    /// Asserts that this MetaItem starts with some specific word.
+    ///
+    /// See [`word`](Self::word) for examples of what a word is.
+    pub fn word_is(&self, sym: Symbol) -> Option<&ArgParser<'a>> {
+        self.path_without_args().word_is(sym).then(|| self.args())
+    }
+
+    /// Asserts that this MetaItem starts with some specific path.
+    ///
+    /// See [`word`](Self::path) for examples of what a word is.
+    pub fn path_is(&self, segments: &[Symbol]) -> Option<&ArgParser<'a>> {
+        self.path_without_args().segments_is(segments).then(|| self.args())
+    }
+}
+
+#[derive(Clone)]
+pub struct NameValueParser {
+    pub eq_span: Span,
+    value: MetaItemLit,
+    pub value_span: Span,
+}
+
+impl Debug for NameValueParser {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        f.debug_struct("NameValueParser")
+            .field("eq_span", &self.eq_span)
+            .field("value", &self.value)
+            .field("value_span", &self.value_span)
+            .finish()
+    }
+}
+
+impl NameValueParser {
+    pub fn value_as_lit(&self) -> &MetaItemLit {
+        &self.value
+    }
+
+    pub fn value_as_str(&self) -> Option<Symbol> {
+        self.value_as_lit().kind.str()
+    }
+}
+
+fn expr_to_lit(dcx: DiagCtxtHandle<'_>, expr: &Expr) -> MetaItemLit {
+    // In valid code the value always ends up as a single literal. Otherwise, a dummy
+    // literal suffices because the error is handled elsewhere.
+    if let ExprKind::Lit(token_lit) = expr.kind
+        && let Ok(lit) = MetaItemLit::from_token_lit(token_lit, expr.span)
+    {
+        lit
+    } else {
+        let guar = dcx.has_errors().unwrap();
+        MetaItemLit { symbol: kw::Empty, suffix: None, kind: LitKind::Err(guar), span: DUMMY_SP }
+    }
+}
+
+struct MetaItemListParserContext<'a> {
+    // the tokens inside the delimiters, so `#[some::attr(a b c)]` would have `a b c` inside
+    inside_delimiters: Peekable<TokenStreamIter<'a>>,
+    dcx: DiagCtxtHandle<'a>,
+}
+
+impl<'a> MetaItemListParserContext<'a> {
+    fn done(&mut self) -> bool {
+        self.inside_delimiters.peek().is_none()
+    }
+
+    fn next_path(&mut self) -> Option<AttrPath> {
+        // FIXME: Share code with `parse_path`.
+        let tt = self.inside_delimiters.next().map(|tt| TokenTree::uninterpolate(tt));
+
+        match tt.as_deref()? {
+            &TokenTree::Token(
+                Token { kind: ref kind @ (token::Ident(..) | token::PathSep), span },
+                _,
+            ) => {
+                // here we have either an ident or pathsep `::`.
+
+                let mut segments = if let &token::Ident(name, _) = kind {
+                    // when we lookahead another pathsep, more path's coming
+                    if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
+                        self.inside_delimiters.peek()
+                    {
+                        self.inside_delimiters.next();
+                        vec![Ident::new(name, span)]
+                    } else {
+                        // else we have a single identifier path, that's all
+                        return Some(AttrPath {
+                            segments: vec![Ident::new(name, span)].into_boxed_slice(),
+                            span,
+                        });
+                    }
+                } else {
+                    // if `::` is all we get, we just got a path root
+                    vec![Ident::new(kw::PathRoot, span)]
+                };
+
+                // one segment accepted. accept n more
+                loop {
+                    // another ident?
+                    if let Some(&TokenTree::Token(Token { kind: token::Ident(name, _), span }, _)) =
+                        self.inside_delimiters
+                            .next()
+                            .map(|tt| TokenTree::uninterpolate(tt))
+                            .as_deref()
+                    {
+                        segments.push(Ident::new(name, span));
+                    } else {
+                        return None;
+                    }
+                    // stop unless we see another `::`
+                    if let Some(TokenTree::Token(Token { kind: token::PathSep, .. }, _)) =
+                        self.inside_delimiters.peek()
+                    {
+                        self.inside_delimiters.next();
+                    } else {
+                        break;
+                    }
+                }
+                let span = span.with_hi(segments.last().unwrap().span.hi());
+                Some(AttrPath { segments: segments.into_boxed_slice(), span })
+            }
+            TokenTree::Token(Token { kind: token::OpenDelim(_) | token::CloseDelim(_), .. }, _) => {
+                None
+            }
+            _ => {
+                // malformed attributes can get here. We can't crash, but somewhere else should've
+                // already warned for this.
+                None
+            }
+        }
+    }
+
+    fn value(&mut self) -> Option<MetaItemLit> {
+        match self.inside_delimiters.next() {
+            Some(TokenTree::Delimited(.., Delimiter::Invisible(_), inner_tokens)) => {
+                MetaItemListParserContext {
+                    inside_delimiters: inner_tokens.iter().peekable(),
+                    dcx: self.dcx,
+                }
+                .value()
+            }
+            Some(TokenTree::Token(token, _)) => MetaItemLit::from_token(token),
+            _ => None,
+        }
+    }
+
+    /// parses one element on the inside of a list attribute like `#[my_attr( <insides> )]`
+    ///
+    /// parses a path followed be either:
+    /// 1. nothing (a word attr)
+    /// 2. a parenthesized list
+    /// 3. an equals sign and a literal (name-value)
+    ///
+    /// Can also parse *just* a literal. This is for cases like as `#[my_attr("literal")]`
+    /// where no path is given before the literal
+    ///
+    /// Some exceptions too for interpolated attributes which are already pre-processed
+    fn next(&mut self) -> Option<MetaItemOrLitParser<'a>> {
+        // a list element is either a literal
+        if let Some(TokenTree::Token(token, _)) = self.inside_delimiters.peek()
+            && let Some(lit) = MetaItemLit::from_token(token)
+        {
+            self.inside_delimiters.next();
+            return Some(MetaItemOrLitParser::Lit(lit));
+        }
+
+        // or a path.
+        let path =
+            if let Some(TokenTree::Token(Token { kind: token::Interpolated(nt), span, .. }, _)) =
+                self.inside_delimiters.peek()
+            {
+                match &**nt {
+                    // or maybe a full nt meta including the path but we return immediately
+                    token::Nonterminal::NtMeta(item) => {
+                        self.inside_delimiters.next();
+
+                        return Some(MetaItemOrLitParser::MetaItemParser(MetaItemParser {
+                            path: PathParser::Ast(&item.path),
+                            args: ArgParser::from_attr_args(&item.args, self.dcx),
+                        }));
+                    }
+                    // an already interpolated path from a macro expansion is a path, no need to parse
+                    // one from tokens
+                    token::Nonterminal::NtPath(path) => {
+                        self.inside_delimiters.next();
+
+                        AttrPath::from_ast(path)
+                    }
+                    _ => {
+                        self.inside_delimiters.next();
+                        // we go into this path if an expr ended up in an attribute that
+                        // expansion did not turn into a literal. Say, `#[repr(align(macro!()))]`
+                        // where the macro didn't expand to a literal. An error is already given
+                        // for this at this point, and then we do continue. This makes this path
+                        // reachable...
+                        let e = self.dcx.span_delayed_bug(
+                            *span,
+                            "expr in place where literal is expected (builtin attr parsing)",
+                        );
+
+                        return Some(MetaItemOrLitParser::Err(*span, e));
+                    }
+                }
+            } else {
+                self.next_path()?
+            };
+
+        // Paths can be followed by:
+        // - `(more meta items)` (another list)
+        // - `= lit` (a name-value)
+        // - nothing
+        Some(MetaItemOrLitParser::MetaItemParser(match self.inside_delimiters.peek() {
+            Some(TokenTree::Delimited(dspan, _, Delimiter::Parenthesis, inner_tokens)) => {
+                self.inside_delimiters.next();
+
+                MetaItemParser {
+                    path: PathParser::Attr(path),
+                    args: ArgParser::List(MetaItemListParser::new_tts(
+                        inner_tokens.iter(),
+                        dspan.entire(),
+                        self.dcx,
+                    )),
+                }
+            }
+            Some(TokenTree::Delimited(_, ..)) => {
+                self.inside_delimiters.next();
+                // self.dcx.span_delayed_bug(span.entire(), "wrong delimiters");
+                return None;
+            }
+            Some(TokenTree::Token(Token { kind: token::Eq, span }, _)) => {
+                self.inside_delimiters.next();
+                let value = self.value()?;
+                MetaItemParser {
+                    path: PathParser::Attr(path),
+                    args: ArgParser::NameValue(NameValueParser {
+                        eq_span: *span,
+                        value_span: value.span,
+                        value,
+                    }),
+                }
+            }
+            _ => MetaItemParser { path: PathParser::Attr(path), args: ArgParser::NoArgs },
+        }))
+    }
+
+    fn parse(mut self, span: Span) -> MetaItemListParser<'a> {
+        let mut sub_parsers = Vec::new();
+
+        while !self.done() {
+            let Some(n) = self.next() else {
+                continue;
+            };
+            sub_parsers.push(n);
+
+            match self.inside_delimiters.peek() {
+                None | Some(TokenTree::Token(Token { kind: token::Comma, .. }, _)) => {
+                    self.inside_delimiters.next();
+                }
+                Some(_) => {}
+            }
+        }
+
+        MetaItemListParser { sub_parsers, span }
+    }
+}
+
+#[derive(Debug, Clone)]
+pub struct MetaItemListParser<'a> {
+    sub_parsers: Vec<MetaItemOrLitParser<'a>>,
+    pub span: Span,
+}
+
+impl<'a> MetaItemListParser<'a> {
+    fn new(delim: &'a DelimArgs, dcx: DiagCtxtHandle<'a>) -> MetaItemListParser<'a> {
+        MetaItemListParser::new_tts(delim.tokens.iter(), delim.dspan.entire(), dcx)
+    }
+
+    fn new_tts(tts: TokenStreamIter<'a>, span: Span, dcx: DiagCtxtHandle<'a>) -> Self {
+        MetaItemListParserContext { inside_delimiters: tts.peekable(), dcx }.parse(span)
+    }
+
+    /// Lets you pick and choose as what you want to parse each element in the list
+    pub fn mixed<'s>(&'s self) -> impl Iterator<Item = &'s MetaItemOrLitParser<'a>> + 's {
+        self.sub_parsers.iter()
+    }
+
+    pub fn len(&self) -> usize {
+        self.sub_parsers.len()
+    }
+
+    pub fn is_empty(&self) -> bool {
+        self.len() == 0
+    }
+
+    /// Asserts that every item in the list is another list starting with a word.
+    ///
+    /// See [`MetaItemParser::word`] for examples of words.
+    pub fn all_word_list<'s>(&'s self) -> Option<Vec<(Ident, &'s ArgParser<'a>)>> {
+        self.mixed().map(|i| i.meta_item()?.word()).collect()
+    }
+
+    /// Asserts that every item in the list is another list starting with a full path.
+    ///
+    /// See [`MetaItemParser::path`] for examples of paths.
+    pub fn all_path_list<'s>(&'s self) -> Option<Vec<(PathParser<'a>, &'s ArgParser<'a>)>> {
+        self.mixed().map(|i| Some(i.meta_item()?.path())).collect()
+    }
+
+    /// Returns Some if the list contains only a single element.
+    ///
+    /// Inside the Some is the parser to parse this single element.
+    pub fn single(&self) -> Option<&MetaItemOrLitParser<'a>> {
+        let mut iter = self.mixed();
+        iter.next().filter(|_| iter.next().is_none())
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
index 92bc2a8aeb0..9d34b807ac2 100644
--- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs
+++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -6,9 +6,16 @@ use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuar
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::{Span, Symbol};
 
-use crate::attributes::util::UnsupportedLiteralReason;
 use crate::fluent_generated as fluent;
 
+pub(crate) enum UnsupportedLiteralReason {
+    Generic,
+    CfgString,
+    CfgBoolean,
+    DeprecatedString,
+    DeprecatedKvPair,
+}
+
 #[derive(Diagnostic)]
 #[diag(attr_parsing_expected_one_cfg_pattern, code = E0536)]
 pub(crate) struct ExpectedOneCfgPattern {
@@ -39,6 +46,21 @@ pub(crate) struct MultipleItem {
 pub(crate) struct IncorrectMetaItem {
     #[primary_span]
     pub span: Span,
+
+    #[subdiagnostic]
+    pub suggestion: Option<IncorrectMetaItemSuggestion>,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+    attr_parsing_incorrect_meta_item_suggestion,
+    applicability = "maybe-incorrect"
+)]
+pub(crate) struct IncorrectMetaItemSuggestion {
+    #[suggestion_part(code = "\"")]
+    pub lo: Span,
+    #[suggestion_part(code = "\"")]
+    pub hi: Span,
 }
 
 /// Error code: E0541
@@ -338,13 +360,6 @@ pub(crate) struct RustcPromotablePairing {
 }
 
 #[derive(Diagnostic)]
-#[diag(attr_parsing_rustc_const_stable_indirect_pairing)]
-pub(crate) struct RustcConstStableIndirectPairing {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(attr_parsing_rustc_allowed_unstable_pairing, code = E0789)]
 pub(crate) struct RustcAllowedUnstablePairing {
     #[primary_span]
@@ -423,3 +438,44 @@ pub(crate) struct UnknownVersionLiteral {
     #[primary_span]
     pub span: Span,
 }
+
+// FIXME(jdonszelmann) duplicated from `rustc_passes`, remove once `check_attr` is integrated.
+#[derive(Diagnostic)]
+#[diag(attr_parsing_unused_multiple)]
+pub(crate) struct UnusedMultiple {
+    #[primary_span]
+    #[suggestion(code = "", applicability = "machine-applicable")]
+    pub this: Span,
+    #[note]
+    pub other: Span,
+    pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(attr_parsing_stability_outside_std, code = E0734)]
+pub(crate) struct StabilityOutsideStd {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(attr_parsing_empty_confusables)]
+pub(crate) struct EmptyConfusables {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(attr_parsing_repr_ident, code = E0565)]
+pub(crate) struct ReprIdent {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(attr_parsing_unrecognized_repr_hint, code = E0552)]
+#[help]
+pub(crate) struct UnrecognizedReprHint {
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index 12e8be41614..dc35d5eb89c 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -4,7 +4,6 @@ use rustc_index::interval::IntervalSet;
 use rustc_infer::infer::canonical::QueryRegionConstraints;
 use rustc_infer::infer::outlives::for_liveness;
 use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, HasLocalDecls, Local, Location};
-use rustc_middle::span_bug;
 use rustc_middle::traits::query::DropckOutlivesResult;
 use rustc_middle::ty::relate::Relate;
 use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
@@ -12,7 +11,7 @@ use rustc_mir_dataflow::ResultsCursor;
 use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
 use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex};
 use rustc_mir_dataflow::points::{DenseLocationMap, PointIndex};
-use rustc_span::{DUMMY_SP, Span};
+use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::ObligationCtxt;
 use rustc_trait_selection::traits::query::dropck_outlives;
@@ -608,7 +607,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
             Ok(TypeOpOutput { output, constraints, .. }) => {
                 DropData { dropck_result: output, region_constraint_data: constraints }
             }
-            Err(_) => {
+            Err(ErrorGuaranteed { .. }) => {
                 // We don't run dropck on HIR, and dropck looks inside fields of
                 // types, so there's no guarantee that it succeeds. We also
                 // can't rely on the the `ErrorGuaranteed` from `fully_perform` here
@@ -631,10 +630,10 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
                         }
                     };
 
+                    // Could have no errors if a type lowering error, say, caused the query
+                    // to fail.
                     if !errors.is_empty() {
                         typeck.infcx.err_ctxt().report_fulfillment_errors(errors);
-                    } else {
-                        span_bug!(span, "Rerunning drop data query produced no error.");
                     }
                 });
                 DropData { dropck_result: Default::default(), region_constraint_data: None }
diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml
index f29be2ee818..b5f4f2efd1f 100644
--- a/compiler/rustc_builtin_macros/Cargo.toml
+++ b/compiler/rustc_builtin_macros/Cargo.toml
@@ -20,6 +20,7 @@ rustc_errors = { path = "../rustc_errors" }
 rustc_expand = { path = "../rustc_expand" }
 rustc_feature = { path = "../rustc_feature" }
 rustc_fluent_macro = { path = "../rustc_fluent_macro" }
+rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_lexer = { path = "../rustc_lexer" }
 rustc_lint_defs = { path = "../rustc_lint_defs" }
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 234ec858216..6b59ac25827 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -185,8 +185,9 @@ use rustc_ast::{
     self as ast, AnonConst, BindingMode, ByRef, EnumDef, Expr, GenericArg, GenericParamKind,
     Generics, Mutability, PatKind, VariantData,
 };
-use rustc_attr_parsing as attr;
+use rustc_attr_parsing::{AttributeKind, AttributeParser, ReprPacked};
 use rustc_expand::base::{Annotatable, ExtCtxt};
+use rustc_hir::Attribute;
 use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym};
 use thin_vec::{ThinVec, thin_vec};
 use ty::{Bounds, Path, Ref, Self_, Ty};
@@ -480,14 +481,10 @@ impl<'a> TraitDef<'a> {
     ) {
         match item {
             Annotatable::Item(item) => {
-                let is_packed = item.attrs.iter().any(|attr| {
-                    for r in attr::find_repr_attrs(cx.sess, attr) {
-                        if let attr::ReprPacked(_) = r {
-                            return true;
-                        }
-                    }
-                    false
-                });
+                let is_packed = matches!(
+                    AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, true),
+                    Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(x, _)| matches!(x, ReprPacked(..)))
+                );
 
                 let newitem = match &item.kind {
                     ast::ItemKind::Struct(struct_def, generics) => self.expand_struct_def(
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs
index 79820232496..72c9df59d83 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs
@@ -620,70 +620,31 @@ pub union MaybeUninit<T> {
 
 pub mod intrinsics {
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn abort() -> ! {
-        loop {}
-    }
+    pub fn abort() -> !;
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn size_of<T>() -> usize {
-        loop {}
-    }
+    pub fn size_of<T>() -> usize;
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub unsafe fn size_of_val<T: ?::Sized>(_val: *const T) -> usize {
-        loop {}
-    }
+    pub unsafe fn size_of_val<T: ?::Sized>(_val: *const T) -> usize;
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn min_align_of<T>() -> usize {
-        loop {}
-    }
+    pub fn min_align_of<T>() -> usize;
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub unsafe fn min_align_of_val<T: ?::Sized>(_val: *const T) -> usize {
-        loop {}
-    }
+    pub unsafe fn min_align_of_val<T: ?::Sized>(_val: *const T) -> usize;
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub unsafe fn copy<T>(_src: *const T, _dst: *mut T, _count: usize) {
-        loop {}
-    }
+    pub unsafe fn copy<T>(_src: *const T, _dst: *mut T, _count: usize);
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub unsafe fn transmute<T, U>(_e: T) -> U {
-        loop {}
-    }
+    pub unsafe fn transmute<T, U>(_e: T) -> U;
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub unsafe fn ctlz_nonzero<T>(_x: T) -> u32 {
-        loop {}
-    }
+    pub unsafe fn ctlz_nonzero<T>(_x: T) -> u32;
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn needs_drop<T: ?::Sized>() -> bool {
-        loop {}
-    }
+    pub fn needs_drop<T: ?::Sized>() -> bool;
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn bitreverse<T>(_x: T) -> T {
-        loop {}
-    }
+    pub fn bitreverse<T>(_x: T) -> T;
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn bswap<T>(_x: T) -> T {
-        loop {}
-    }
+    pub fn bswap<T>(_x: T) -> T;
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub unsafe fn write_bytes<T>(_dst: *mut T, _val: u8, _count: usize) {
-        loop {}
-    }
+    pub unsafe fn write_bytes<T>(_dst: *mut T, _val: u8, _count: usize);
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub unsafe fn unreachable() -> ! {
-        loop {}
-    }
+    pub unsafe fn unreachable() -> !;
 }
 
 pub mod libc {
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index fcccda62355..0929218ea2b 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -116,8 +116,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             });
         }
 
-        // simd_shuffle_generic<T, U, const I: &[u32]>(x: T, y: T) -> U
-        sym::simd_shuffle_generic => {
+        // simd_shuffle_const_generic<T, U, const I: &[u32]>(x: T, y: T) -> U
+        sym::simd_shuffle_const_generic => {
             let [x, y] = args else {
                 bug!("wrong number of args for intrinsic {intrinsic}");
             };
diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs
index 2ff1d757fd4..3dad35bc4ce 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core.rs
@@ -591,70 +591,31 @@ pub union MaybeUninit<T> {
 
 pub mod intrinsics {
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn abort() -> ! {
-        loop {}
-    }
+    pub fn abort() -> !;
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn size_of<T>() -> usize {
-        loop {}
-    }
+    pub fn size_of<T>() -> usize;
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub unsafe fn size_of_val<T: ?::Sized>(_val: *const T) -> usize {
-        loop {}
-    }
+    pub unsafe fn size_of_val<T: ?::Sized>(_val: *const T) -> usize;
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn min_align_of<T>() -> usize {
-        loop {}
-    }
+    pub fn min_align_of<T>() -> usize;
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub unsafe fn min_align_of_val<T: ?::Sized>(_val: *const T) -> usize {
-        loop {}
-    }
+    pub unsafe fn min_align_of_val<T: ?::Sized>(_val: *const T) -> usize;
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub unsafe fn copy<T>(_src: *const T, _dst: *mut T, _count: usize) {
-        loop {}
-    }
+    pub unsafe fn copy<T>(_src: *const T, _dst: *mut T, _count: usize);
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub unsafe fn transmute<T, U>(_e: T) -> U {
-        loop {}
-    }
+    pub unsafe fn transmute<T, U>(_e: T) -> U;
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub unsafe fn ctlz_nonzero<T>(_x: T) -> u32 {
-        loop {}
-    }
+    pub unsafe fn ctlz_nonzero<T>(_x: T) -> u32;
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn needs_drop<T: ?::Sized>() -> bool {
-        loop {}
-    }
+    pub fn needs_drop<T: ?::Sized>() -> bool;
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn bitreverse<T>(_x: T) -> T {
-        loop {}
-    }
+    pub fn bitreverse<T>(_x: T) -> T;
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn bswap<T>(_x: T) -> T {
-        loop {}
-    }
+    pub fn bswap<T>(_x: T) -> T;
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub unsafe fn write_bytes<T>(_dst: *mut T, _val: u8, _count: usize) {
-        loop {}
-    }
+    pub unsafe fn write_bytes<T>(_dst: *mut T, _val: u8, _count: usize);
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub unsafe fn unreachable() -> ! {
-        loop {}
-    }
+    pub unsafe fn unreachable() -> !;
 }
 
 pub mod libc {
diff --git a/compiler/rustc_codegen_gcc/tests/run/abort1.rs b/compiler/rustc_codegen_gcc/tests/run/abort1.rs
index 385e41a6881..fe46d9ae418 100644
--- a/compiler/rustc_codegen_gcc/tests/run/abort1.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/abort1.rs
@@ -36,10 +36,7 @@ mod intrinsics {
 
     #[rustc_nounwind]
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn abort() -> ! {
-        loop {}
-    }
+    pub fn abort() -> !;
 }
 
 /*
diff --git a/compiler/rustc_codegen_gcc/tests/run/abort2.rs b/compiler/rustc_codegen_gcc/tests/run/abort2.rs
index 6c66a930e07..4123f4f4bee 100644
--- a/compiler/rustc_codegen_gcc/tests/run/abort2.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/abort2.rs
@@ -36,10 +36,7 @@ mod intrinsics {
 
     #[rustc_nounwind]
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn abort() -> ! {
-        loop {}
-    }
+    pub fn abort() -> !;
 }
 
 /*
diff --git a/compiler/rustc_codegen_gcc/tests/run/assign.rs b/compiler/rustc_codegen_gcc/tests/run/assign.rs
index 4d414c577a6..286155852d5 100644
--- a/compiler/rustc_codegen_gcc/tests/run/assign.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/assign.rs
@@ -59,10 +59,7 @@ mod libc {
 mod intrinsics {
     #[rustc_nounwind]
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn abort() -> ! {
-        loop {}
-    }
+    pub fn abort() -> !;
 }
 
 #[lang = "panic"]
diff --git a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs
index 9be64f991ee..b0215860406 100644
--- a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs
@@ -61,10 +61,7 @@ mod libc {
 mod intrinsics {
     #[rustc_nounwind]
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn abort() -> ! {
-        loop {}
-    }
+    pub fn abort() -> !;
 }
 
 #[lang = "panic"]
diff --git a/compiler/rustc_codegen_gcc/tests/run/operations.rs b/compiler/rustc_codegen_gcc/tests/run/operations.rs
index c92d3cc0b8f..8ba7a4c5ed8 100644
--- a/compiler/rustc_codegen_gcc/tests/run/operations.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/operations.rs
@@ -67,10 +67,7 @@ mod libc {
 mod intrinsics {
     #[rustc_nounwind]
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn abort() -> ! {
-        loop {}
-    }
+    pub fn abort() -> !;
 }
 
 #[lang = "panic"]
diff --git a/compiler/rustc_codegen_gcc/tests/run/static.rs b/compiler/rustc_codegen_gcc/tests/run/static.rs
index 80c8782c4b1..c3c8121b1e1 100644
--- a/compiler/rustc_codegen_gcc/tests/run/static.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/static.rs
@@ -49,10 +49,7 @@ mod intrinsics {
 
     #[rustc_nounwind]
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    pub fn abort() -> ! {
-        loop {}
-    }
+    pub fn abort() -> !;
 }
 
 mod libc {
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index dfbb5bc1731..56fae135e55 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -1329,7 +1329,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
         ));
     }
 
-    if name == sym::simd_shuffle_generic {
+    if name == sym::simd_shuffle_const_generic {
         let idx = fn_args[2].expect_const().to_value().valtree.unwrap_branch();
         let n = idx.len() as u64;
 
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index b4b5d6a5b19..1fcb20e0d7b 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -281,6 +281,8 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
         ("riscv32" | "riscv64", "zaamo") if get_version().0 < 19 => None,
         ("riscv32" | "riscv64", "zabha") if get_version().0 < 19 => None,
         ("riscv32" | "riscv64", "zalrsc") if get_version().0 < 19 => None,
+        ("riscv32" | "riscv64", "zama16b") if get_version().0 < 19 => None,
+        ("riscv32" | "riscv64", "zacas") if get_version().0 < 20 => None,
         // Enable the evex512 target feature if an avx512 target feature is enabled.
         ("x86", s) if s.starts_with("avx512") => {
             Some(LLVMFeature::with_dependency(s, TargetFeatureFoldStrength::EnableOnly("evex512")))
diff --git a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
index 27331ce4ca6..da9f8d69297 100644
--- a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
+++ b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
@@ -94,7 +94,7 @@ impl<'tcx> AssertModuleSource<'tcx> {
                 other => {
                     self.tcx
                         .dcx()
-                        .emit_fatal(errors::UnknownReuseKind { span: attr.span, kind: other });
+                        .emit_fatal(errors::UnknownReuseKind { span: attr.span(), kind: other });
                 }
             }
         } else {
@@ -102,7 +102,7 @@ impl<'tcx> AssertModuleSource<'tcx> {
         };
 
         if !self.tcx.sess.opts.unstable_opts.query_dep_graph {
-            self.tcx.dcx().emit_fatal(errors::MissingQueryDepGraph { span: attr.span });
+            self.tcx.dcx().emit_fatal(errors::MissingQueryDepGraph { span: attr.span() });
         }
 
         if !self.check_config(attr) {
@@ -115,7 +115,7 @@ impl<'tcx> AssertModuleSource<'tcx> {
 
         if !user_path.starts_with(&crate_name) {
             self.tcx.dcx().emit_fatal(errors::MalformedCguName {
-                span: attr.span,
+                span: attr.span(),
                 user_path,
                 crate_name,
             });
@@ -145,7 +145,7 @@ impl<'tcx> AssertModuleSource<'tcx> {
             let cgu_names: Vec<&str> =
                 self.available_cgus.items().map(|cgu| cgu.as_str()).into_sorted_stable_ord();
             self.tcx.dcx().emit_err(errors::NoModuleNamed {
-                span: attr.span,
+                span: attr.span(),
                 user_path,
                 cgu_name,
                 cgu_names: cgu_names.join(", "),
@@ -155,7 +155,7 @@ impl<'tcx> AssertModuleSource<'tcx> {
         self.cgu_reuse_tracker.set_expectation(
             cgu_name,
             user_path,
-            attr.span,
+            attr.span(),
             expected_reuse,
             comp_kind,
         );
@@ -175,7 +175,7 @@ impl<'tcx> AssertModuleSource<'tcx> {
             }
         }
 
-        self.tcx.dcx().emit_fatal(errors::NoField { span: attr.span, name });
+        self.tcx.dcx().emit_fatal(errors::NoField { span: attr.span(), name });
     }
 
     /// Scan for a `cfg="foo"` attribute and check whether we have a
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 40238f4b491..73a97d32c2d 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -5,7 +5,9 @@ use std::time::{Duration, Instant};
 
 use itertools::Itertools;
 use rustc_abi::FIRST_VARIANT;
+use rustc_ast as ast;
 use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, AllocatorKind, global_fn_name};
+use rustc_attr_parsing::OptimizeAttr;
 use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
 use rustc_data_structures::sync::par_map;
@@ -29,7 +31,6 @@ use rustc_span::{DUMMY_SP, Symbol, sym};
 use rustc_trait_selection::infer::{BoundRegionConversionTime, TyCtxtInferExt};
 use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
 use tracing::{debug, info};
-use {rustc_ast as ast, rustc_attr_parsing as attr};
 
 use crate::assert_module_sources::CguReuse;
 use crate::back::link::are_upstream_rust_objects_already_included;
@@ -1061,7 +1062,7 @@ pub(crate) fn provide(providers: &mut Providers) {
 
         let any_for_speed = defids.items().any(|id| {
             let CodegenFnAttrs { optimize, .. } = tcx.codegen_fn_attrs(*id);
-            matches!(optimize, attr::OptimizeAttr::Speed)
+            matches!(optimize, OptimizeAttr::Speed)
         });
 
         if any_for_speed {
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 97bc84c0b69..673740b4aab 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -5,7 +5,8 @@ use rustc_ast::expand::autodiff_attrs::{
     AutoDiffAttrs, DiffActivity, DiffMode, valid_input_activity, valid_ret_activity,
 };
 use rustc_ast::{MetaItem, MetaItemInner, attr};
-use rustc_attr_parsing::{InlineAttr, InstructionSetAttr, OptimizeAttr};
+use rustc_attr_parsing::ReprAttr::ReprAlign;
+use rustc_attr_parsing::{AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::codes::*;
 use rustc_errors::{DiagMessage, SubdiagMessage, struct_span_code_err};
@@ -104,12 +105,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
             if let Fn | AssocFn | Variant | Ctor(..) = def_kind {
                 Some(tcx.fn_sig(did))
             } else {
-                tcx.dcx()
-                    .span_delayed_bug(attr.span, "this attribute can only be applied to functions");
+                tcx.dcx().span_delayed_bug(
+                    attr.span(),
+                    "this attribute can only be applied to functions",
+                );
                 None
             }
         };
 
+        if let hir::Attribute::Parsed(p) = attr {
+            match p {
+                AttributeKind::Repr(reprs) => {
+                    codegen_fn_attrs.alignment = reprs
+                        .iter()
+                        .find_map(|(r, _)| if let ReprAlign(x) = r { Some(*x) } else { None });
+                }
+
+                _ => {}
+            }
+        }
+
         let Some(Ident { name, .. }) = attr.ident() else {
             continue;
         };
@@ -130,14 +145,14 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                 if tcx.opt_item_name(did.to_def_id()).is_some() {
                     codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
                     mixed_export_name_no_mangle_lint_state.track_no_mangle(
-                        attr.span,
+                        attr.span(),
                         tcx.local_def_id_to_hir_id(did),
                         attr,
                     );
                 } else {
                     tcx.dcx()
                         .struct_span_err(
-                            attr.span,
+                            attr.span(),
                             format!(
                                 "`#[no_mangle]` cannot be used on {} {} as it has no name",
                                 tcx.def_descr_article(did.to_def_id()),
@@ -158,7 +173,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                             feature_err(
                                 &tcx.sess,
                                 sym::used_with_arg,
-                                attr.span,
+                                attr.span(),
                                 "`#[used(linker)]` is currently unstable",
                             )
                             .emit();
@@ -170,7 +185,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                             feature_err(
                                 &tcx.sess,
                                 sym::used_with_arg,
-                                attr.span,
+                                attr.span(),
                                 "`#[used(compiler)]` is currently unstable",
                             )
                             .emit();
@@ -178,7 +193,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                         codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
                     }
                     Some(_) => {
-                        tcx.dcx().emit_err(errors::ExpectedUsedSymbol { span: attr.span });
+                        tcx.dcx().emit_err(errors::ExpectedUsedSymbol { span: attr.span() });
                     }
                     None => {
                         // Unfortunately, unconditionally using `llvm.used` causes
@@ -223,7 +238,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                 {
                     struct_span_code_err!(
                         tcx.dcx(),
-                        attr.span,
+                        attr.span(),
                         E0737,
                         "`#[track_caller]` requires Rust ABI"
                     )
@@ -231,12 +246,12 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                 }
                 if is_closure
                     && !tcx.features().closure_track_caller()
-                    && !attr.span.allows_unstable(sym::closure_track_caller)
+                    && !attr.span().allows_unstable(sym::closure_track_caller)
                 {
                     feature_err(
                         &tcx.sess,
                         sym::closure_track_caller,
-                        attr.span,
+                        attr.span(),
                         "`#[track_caller]` on closures is currently unstable",
                     )
                     .emit();
@@ -250,19 +265,19 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                         // so it may not contain any null characters.
                         struct_span_code_err!(
                             tcx.dcx(),
-                            attr.span,
+                            attr.span(),
                             E0648,
                             "`export_name` may not contain null characters"
                         )
                         .emit();
                     }
                     codegen_fn_attrs.export_name = Some(s);
-                    mixed_export_name_no_mangle_lint_state.track_export_name(attr.span);
+                    mixed_export_name_no_mangle_lint_state.track_export_name(attr.span());
                 }
             }
             sym::target_feature => {
                 let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else {
-                    tcx.dcx().span_delayed_bug(attr.span, "target_feature applied to non-fn");
+                    tcx.dcx().span_delayed_bug(attr.span(), "target_feature applied to non-fn");
                     continue;
                 };
                 let safe_target_features =
@@ -292,7 +307,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                         // `main`, `start`, and other functions that are not usually
                         // allowed.
                     } else {
-                        check_target_feature_trait_unsafe(tcx, did, attr.span);
+                        check_target_feature_trait_unsafe(tcx, did, attr.span());
                     }
                 }
                 from_target_feature_attr(
@@ -310,7 +325,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
 
                         if tcx.is_mutable_static(did.into()) {
                             let mut diag = tcx.dcx().struct_span_err(
-                                attr.span,
+                                attr.span(),
                                 "extern mutable statics are not allowed with `#[linkage]`",
                             );
                             diag.note(
@@ -329,7 +344,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                 if let Some(val) = attr.value_str() {
                     if val.as_str().bytes().any(|b| b == 0) {
                         let msg = format!("illegal null byte in link_section value: `{val}`");
-                        tcx.dcx().span_err(attr.span, msg);
+                        tcx.dcx().span_err(attr.span(), msg);
                     } else {
                         codegen_fn_attrs.link_section = Some(val);
                     }
@@ -337,13 +352,13 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
             }
             sym::link_name => codegen_fn_attrs.link_name = attr.value_str(),
             sym::link_ordinal => {
-                link_ordinal_span = Some(attr.span);
+                link_ordinal_span = Some(attr.span());
                 if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
                     codegen_fn_attrs.link_ordinal = ordinal;
                 }
             }
             sym::no_sanitize => {
-                no_sanitize_span = Some(attr.span);
+                no_sanitize_span = Some(attr.span());
                 if let Some(list) = attr.meta_item_list() {
                     for item in list.iter() {
                         match item.name_or_empty() {
@@ -381,7 +396,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                                 {
                                     struct_span_code_err!(
                                         tcx.dcx(),
-                                        attr.span,
+                                        attr.span(),
                                         E0779,
                                         "target does not support `#[instruction_set]`"
                                     )
@@ -393,7 +408,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                                 _ => {
                                     struct_span_code_err!(
                                         tcx.dcx(),
-                                        attr.span,
+                                        attr.span(),
                                         E0779,
                                         "invalid instruction set specified",
                                     )
@@ -405,7 +420,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                         [] => {
                             struct_span_code_err!(
                                 tcx.dcx(),
-                                attr.span,
+                                attr.span(),
                                 E0778,
                                 "`#[instruction_set]` requires an argument"
                             )
@@ -415,7 +430,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                         _ => {
                             struct_span_code_err!(
                                 tcx.dcx(),
-                                attr.span,
+                                attr.span(),
                                 E0779,
                                 "cannot specify more than one instruction set"
                             )
@@ -424,27 +439,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                         }
                     })
             }
-            sym::repr => {
-                codegen_fn_attrs.alignment = if let Some(items) = attr.meta_item_list()
-                    && let [item] = items.as_slice()
-                    && let Some((sym::align, literal)) = item.singleton_lit_list()
-                {
-                    rustc_attr_parsing::parse_alignment(&literal.kind)
-                        .inspect_err(|msg| {
-                            struct_span_code_err!(
-                                tcx.dcx(),
-                                literal.span,
-                                E0589,
-                                "invalid `repr(align)` attribute: {}",
-                                msg
-                            )
-                            .emit();
-                        })
-                        .ok()
-                } else {
-                    None
-                };
-            }
             sym::patchable_function_entry => {
                 codegen_fn_attrs.patchable_function_entry = attr.meta_item_list().and_then(|l| {
                     let mut prefix = None;
@@ -510,7 +504,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                     }
 
                     if let (None, None) = (prefix, entry) {
-                        tcx.dcx().span_err(attr.span, "must specify at least one parameter");
+                        tcx.dcx().span_err(attr.span(), "must specify at least one parameter");
                     }
 
                     Some(PatchableFunctionEntry::from_prefix_and_entry(
@@ -536,18 +530,19 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         let Some(ref items) = attr.meta_item_list() else {
             return ia;
         };
+        inline_span = Some(attr.span());
 
-        inline_span = Some(attr.span);
         let [item] = &items[..] else {
-            struct_span_code_err!(tcx.dcx(), attr.span, E0534, "expected one argument").emit();
+            struct_span_code_err!(tcx.dcx(), attr.span(), E0534, "expected one argument").emit();
             return InlineAttr::None;
         };
+
         if item.has_name(sym::always) {
             InlineAttr::Always
         } else if item.has_name(sym::never) {
             InlineAttr::Never
         } else {
-            struct_span_code_err!(tcx.dcx(), item.span(), E0535, "invalid argument")
+            struct_span_code_err!(tcx.dcx(), items[0].span(), E0535, "invalid argument")
                 .with_help("valid inline arguments are `always` and `never`")
                 .emit();
 
@@ -560,9 +555,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         }
 
         if attr.is_word() {
-            InlineAttr::Force { attr_span: attr.span, reason: None }
+            InlineAttr::Force { attr_span: attr.span(), reason: None }
         } else if let Some(val) = attr.value_str() {
-            InlineAttr::Force { attr_span: attr.span, reason: Some(val) }
+            InlineAttr::Force { attr_span: attr.span(), reason: Some(val) }
         } else {
             debug!("`rustc_force_inline` not checked by attribute validation");
             ia
@@ -582,16 +577,16 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         }
         let err = |sp, s| struct_span_code_err!(tcx.dcx(), sp, E0722, "{}", s).emit();
         if attr.is_word() {
-            err(attr.span, "expected one argument");
+            err(attr.span(), "expected one argument");
             return ia;
         }
         let Some(ref items) = attr.meta_item_list() else {
             return OptimizeAttr::Default;
         };
 
-        inline_span = Some(attr.span);
+        inline_span = Some(attr.span());
         let [item] = &items[..] else {
-            err(attr.span, "expected one argument");
+            err(attr.span(), "expected one argument");
             return OptimizeAttr::Default;
         };
         if item.has_name(sym::size) {
@@ -703,7 +698,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         let span = tcx
             .get_attrs(did, sym::target_feature)
             .next()
-            .map_or_else(|| tcx.def_span(did), |a| a.span);
+            .map_or_else(|| tcx.def_span(did), |a| a.span());
         tcx.dcx()
             .create_err(errors::TargetFeatureDisableOrEnable {
                 features,
@@ -752,7 +747,7 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Option<u16> {
     use rustc_ast::{LitIntType, LitKind, MetaItemLit};
     let meta_item_list = attr.meta_item_list()?;
     let [sole_meta_list] = &meta_item_list[..] else {
-        tcx.dcx().emit_err(errors::InvalidLinkOrdinalNargs { span: attr.span });
+        tcx.dcx().emit_err(errors::InvalidLinkOrdinalNargs { span: attr.span() });
         return None;
     };
     if let Some(MetaItemLit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) =
@@ -776,13 +771,13 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Option<u16> {
         } else {
             let msg = format!("ordinal value in `link_ordinal` is too large: `{ordinal}`");
             tcx.dcx()
-                .struct_span_err(attr.span, msg)
+                .struct_span_err(attr.span(), msg)
                 .with_note("the value may not exceed `u16::MAX`")
                 .emit();
             None
         }
     } else {
-        tcx.dcx().emit_err(errors::InvalidLinkOrdinalFormat { span: attr.span });
+        tcx.dcx().emit_err(errors::InvalidLinkOrdinalFormat { span: attr.span() });
         None
     }
 }
@@ -828,7 +823,7 @@ impl<'a> MixedExportNameAndNoMangleState<'a> {
             export_name: Some(export_name),
             no_mangle: Some(no_mangle),
             hir_id: Some(hir_id),
-            no_mangle_attr: Some(no_mangle_attr),
+            no_mangle_attr: Some(_),
         } = self
         {
             tcx.emit_node_span_lint(
@@ -837,7 +832,7 @@ impl<'a> MixedExportNameAndNoMangleState<'a> {
                 no_mangle,
                 errors::MixedExportNameAndNoMangle {
                     no_mangle,
-                    no_mangle_attr: rustc_hir_pretty::attribute_to_string(&tcx, no_mangle_attr),
+                    no_mangle_attr: "#[unsafe(no_mangle)]".to_string(),
                     export_name,
                     removal_span: no_mangle,
                 },
@@ -869,7 +864,7 @@ fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> {
         _ => {
             //FIXME(ZuseZ4): Once we fixed our parser, we should also prohibit the two-attribute
             //branch above.
-            span_bug!(attrs[1].span, "cg_ssa: rustc_autodiff should only exist once per source");
+            span_bug!(attrs[1].span(), "cg_ssa: rustc_autodiff should only exist once per source");
         }
     };
 
@@ -881,12 +876,12 @@ fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> {
     }
 
     let [mode, input_activities @ .., ret_activity] = &list[..] else {
-        span_bug!(attr.span, "rustc_autodiff attribute must contain mode and activities");
+        span_bug!(attr.span(), "rustc_autodiff attribute must contain mode and activities");
     };
     let mode = if let MetaItemInner::MetaItem(MetaItem { path: p1, .. }) = mode {
         p1.segments.first().unwrap().ident
     } else {
-        span_bug!(attr.span, "rustc_autodiff attribute must contain mode");
+        span_bug!(attr.span(), "rustc_autodiff attribute must contain mode");
     };
 
     // parse mode
@@ -902,7 +897,7 @@ fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> {
     let ret_symbol = if let MetaItemInner::MetaItem(MetaItem { path: p1, .. }) = ret_activity {
         p1.segments.first().unwrap().ident
     } else {
-        span_bug!(attr.span, "rustc_autodiff attribute must contain the return activity");
+        span_bug!(attr.span(), "rustc_autodiff attribute must contain the return activity");
     };
 
     // Then parse it into an actual DiffActivity
@@ -937,11 +932,11 @@ fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> {
 
     for &input in &arg_activities {
         if !valid_input_activity(mode, input) {
-            span_bug!(attr.span, "Invalid input activity {} for {} mode", input, mode);
+            span_bug!(attr.span(), "Invalid input activity {} for {} mode", input, mode);
         }
     }
     if !valid_ret_activity(mode, ret_activity) {
-        span_bug!(attr.span, "Invalid return activity {} for {} mode", ret_activity, mode);
+        span_bug!(attr.span(), "Invalid return activity {} for {} mode", ret_activity, mode);
     }
 
     Some(AutoDiffAttrs { mode, ret_activity, input_activity: arg_activities })
diff --git a/compiler/rustc_const_eval/src/check_consts/mod.rs b/compiler/rustc_const_eval/src/check_consts/mod.rs
index 52e000858b4..659d4a30456 100644
--- a/compiler/rustc_const_eval/src/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/check_consts/mod.rs
@@ -4,12 +4,13 @@
 //! has interior mutability or needs to be dropped, as well as the visitor that emits errors when
 //! it finds operations that are invalid in a certain context.
 
+use rustc_attr_parsing::{AttributeKind, find_attr};
 use rustc_errors::DiagCtxtHandle;
+use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::ty::{self, PolyFnSig, TyCtxt};
 use rustc_middle::{bug, mir};
 use rustc_span::Symbol;
-use {rustc_attr_parsing as attr, rustc_hir as hir};
 
 pub use self::qualifs::Qualif;
 
@@ -81,7 +82,8 @@ pub fn rustc_allow_const_fn_unstable(
     feature_gate: Symbol,
 ) -> bool {
     let attrs = tcx.hir().attrs(tcx.local_def_id_to_hir_id(def_id));
-    attr::rustc_allow_const_fn_unstable(tcx.sess, attrs).any(|name| name == feature_gate)
+
+    find_attr!(attrs, AttributeKind::AllowConstFnUnstable(syms) if syms.contains(&feature_gate))
 }
 
 /// Returns `true` if the given `def_id` (trait or function) is "safe to expose on stable".
diff --git a/compiler/rustc_error_codes/src/error_codes/E0094.md b/compiler/rustc_error_codes/src/error_codes/E0094.md
index efbfa0851a8..909da368f2b 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0094.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0094.md
@@ -7,12 +7,8 @@ Erroneous code example:
 #![allow(internal_features)]
 
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-fn size_of<T, U>() -> usize // error: intrinsic has wrong number
-                            //        of type parameters
-{
-    loop {}
-}
+fn size_of<T, U>() -> usize; // error: intrinsic has wrong number
+                             //        of type parameters
 ```
 
 Please check that you provided the right number of type parameters
@@ -24,9 +20,5 @@ Example:
 #![allow(internal_features)]
 
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-fn size_of<T>() -> usize // ok!
-{
-    loop {}
-}
+fn size_of<T>() -> usize; // ok!
 ```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0374.md b/compiler/rustc_error_codes/src/error_codes/E0374.md
index 6d7dc88823c..63c243b54ff 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0374.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0374.md
@@ -1,5 +1,5 @@
-`CoerceUnsized` was implemented on a struct which does not contain a field with
-an unsized type.
+`CoerceUnsized` or `DispatchFromDyn` was implemented on a struct which does not
+contain a field that is being unsized.
 
 Example of erroneous code:
 
@@ -11,47 +11,20 @@ struct Foo<T: ?Sized> {
     a: i32,
 }
 
-// error: Struct `Foo` has no unsized fields that need `CoerceUnsized`.
+// error: Struct `Foo` has no unsized fields that need to be coerced.
 impl<T, U> CoerceUnsized<Foo<U>> for Foo<T>
     where T: CoerceUnsized<U> {}
 ```
 
-An [unsized type][1] is any type where the compiler does not know the length or
-alignment of at compile time. Any struct containing an unsized type is also
-unsized.
+`CoerceUnsized` is used to coerce structs that have a field that can be unsized,
+like a custom `MyBox<T>` being unsized to `MyBox<dyn Trait>`. `DispatchFromDyn`
+is used to dispatch from `MyBox<dyn Trait>` to `MyBox<Self>` in a dyn-compatible
+trait.
 
-[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait
+If the struct doesn't have any fields of unsized types then there is no
+meaningful way to implement `CoerceUnsized` or `DispatchFromDyn`, since
+there is no coercion taking place.
 
-`CoerceUnsized` is used to coerce one struct containing an unsized type
-into another struct containing a different unsized type. If the struct
-doesn't have any fields of unsized types then you don't need explicit
-coercion to get the types you want. To fix this you can either
-not try to implement `CoerceUnsized` or you can add a field that is
-unsized to the struct.
-
-Example:
-
-```
-#![feature(coerce_unsized)]
-use std::ops::CoerceUnsized;
-
-// We don't need to impl `CoerceUnsized` here.
-struct Foo {
-    a: i32,
-}
-
-// We add the unsized type field to the struct.
-struct Bar<T: ?Sized> {
-    a: i32,
-    b: T,
-}
-
-// The struct has an unsized field so we can implement
-// `CoerceUnsized` for it.
-impl<T, U> CoerceUnsized<Bar<U>> for Bar<T>
-    where T: CoerceUnsized<U> {}
-```
-
-Note that `CoerceUnsized` is mainly used by smart pointers like `Box`, `Rc`
-and `Arc` to be able to mark that they can coerce unsized types that they
-are pointing at.
+Note that `CoerceUnsized` and `DispatchFromDyn` is mainly used by smart pointers
+like `Box`, `Rc` and `Arc` to be able to mark that they can coerce unsized types
+that they are pointing at.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0375.md b/compiler/rustc_error_codes/src/error_codes/E0375.md
index 71e53057165..7abb3b6afd0 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0375.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0375.md
@@ -1,5 +1,5 @@
-`CoerceUnsized` was implemented on a struct which contains more than one field
-with an unsized type.
+`CoerceUnsized` or `DispatchFromDyn` was implemented on a struct which contains
+more than one field that is being unsized.
 
 Erroneous code example:
 
@@ -17,39 +17,14 @@ struct Foo<T: ?Sized, U: ?Sized> {
 impl<T, U> CoerceUnsized<Foo<U, T>> for Foo<T, U> {}
 ```
 
-A struct with more than one field containing an unsized type cannot implement
-`CoerceUnsized`. This only occurs when you are trying to coerce one of the
-types in your struct to another type in the struct. In this case we try to
-impl `CoerceUnsized` from `T` to `U` which are both types that the struct
-takes. An [unsized type][1] is any type that the compiler doesn't know the
-length or alignment of at compile time. Any struct containing an unsized type
-is also unsized.
+`CoerceUnsized` is used to coerce structs that have a field that can be unsized,
+like a custom `MyBox<T>` being unsized to `MyBox<dyn Trait>`. `DispatchFromDyn`
+is used to dispatch from `MyBox<dyn Trait>` to `MyBox<Self>` in a dyn-compatible
+trait.
 
-`CoerceUnsized` only allows for coercion from a structure with a single
-unsized type field to another struct with a single unsized type field.
-In fact Rust only allows for a struct to have one unsized type in a struct
-and that unsized type must be the last field in the struct. So having two
-unsized types in a single struct is not allowed by the compiler. To fix this
-use only one field containing an unsized type in the struct and then use
-multiple structs to manage each unsized type field you need.
+If the struct has multiple fields that must be unsized, then the compiler has no
+way to generate a valid implementation of `CoerceUnsized` or `DispatchFromDyn`.
 
-Example:
-
-```
-#![feature(coerce_unsized)]
-use std::ops::CoerceUnsized;
-
-struct Foo<T: ?Sized> {
-    a: i32,
-    b: T,
-}
-
-impl <T, U> CoerceUnsized<Foo<U>> for Foo<T>
-    where T: CoerceUnsized<U> {}
-
-fn coerce_foo<T: CoerceUnsized<U>, U>(t: T) -> Foo<U> {
-    Foo { a: 12i32, b: t } // we use coercion to get the `Foo<U>` type we need
-}
-```
-
-[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait
+Note that `CoerceUnsized` and `DispatchFromDyn` is mainly used by smart pointers
+like `Box`, `Rc` and `Arc` to be able to mark that they can coerce unsized types
+that they are pointing at.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0376.md b/compiler/rustc_error_codes/src/error_codes/E0376.md
index 50de15bd30f..5b564ec22fc 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0376.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0376.md
@@ -1,8 +1,11 @@
-`CoerceUnsized` was implemented on something that isn't a struct.
+#### Note: this error code is no longer emitted by the compiler.
+
+`CoerceUnsized` or `DispatchFromDyn` was implemented between two types that
+are not structs.
 
 Erroneous code example:
 
-```compile_fail,E0376
+```compile_fail,E0377
 #![feature(coerce_unsized)]
 use std::ops::CoerceUnsized;
 
@@ -14,33 +17,4 @@ struct Foo<T: ?Sized> {
 impl<T, U> CoerceUnsized<U> for Foo<T> {}
 ```
 
-`CoerceUnsized` can only be implemented for a struct. Unsized types are
-already able to be coerced without an implementation of `CoerceUnsized`
-whereas a struct containing an unsized type needs to know the unsized type
-field it's containing is able to be coerced. An [unsized type][1]
-is any type that the compiler doesn't know the length or alignment of at
-compile time. Any struct containing an unsized type is also unsized.
-
-[1]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait
-
-The `CoerceUnsized` trait takes a struct type. Make sure the type you are
-providing to `CoerceUnsized` is a struct with only the last field containing an
-unsized type.
-
-Example:
-
-```
-#![feature(coerce_unsized)]
-use std::ops::CoerceUnsized;
-
-struct Foo<T> {
-    a: T,
-}
-
-// The `Foo<U>` is a struct so `CoerceUnsized` can be implemented
-impl<T, U> CoerceUnsized<Foo<U>> for Foo<T> where T: CoerceUnsized<U> {}
-```
-
-Note that in Rust, structs can only contain an unsized type if the field
-containing the unsized type is the last and only unsized type field in the
-struct.
+`CoerceUnsized` or `DispatchFromDyn` can only be implemented between structs.
diff --git a/compiler/rustc_error_codes/src/error_codes/E0377.md b/compiler/rustc_error_codes/src/error_codes/E0377.md
index b1d36406332..cd2b26260a8 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0377.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0377.md
@@ -1,5 +1,5 @@
-The trait `CoerceUnsized` may only be implemented for a coercion between
-structures with the same definition.
+`CoerceUnsized` or `DispatchFromDyn` may only be implemented between structs
+of the same type.
 
 Example of erroneous code:
 
@@ -20,10 +20,15 @@ pub struct Bar<T: ?Sized> {
 impl<T, U> CoerceUnsized<Bar<U>> for Foo<T> where T: CoerceUnsized<U> {}
 ```
 
-When attempting to implement `CoerceUnsized`, the `impl` signature must look
-like: `impl CoerceUnsized<Type<U>> for Type<T> where T: CoerceUnsized<U>`;
-the *implementer* and *`CoerceUnsized` type parameter* must be the same
-type. In this example, `Bar` and `Foo` (even though structurally identical)
-are *not* the same type and are rejected. Learn more about the `CoerceUnsized`
-trait and DST coercion in
-[the `CoerceUnsized` docs](../std/ops/trait.CoerceUnsized.html).
+`CoerceUnsized` is used to coerce structs that have a field that can be unsized,
+like a custom `MyBox<T>` being unsized to `MyBox<dyn Trait>`. `DispatchFromDyn`
+is used to dispatch from `MyBox<dyn Trait>` to `MyBox<Self>` in a dyn-compatible
+trait.
+
+The compiler cannot support coercions between structs of different types, so
+a valid implementation of `CoerceUnsized` or `DispatchFromDyn` should be
+implemented between the same struct with different generic parameters.
+
+Note that `CoerceUnsized` and `DispatchFromDyn` is mainly used by smart pointers
+like `Box`, `Rc` and `Arc` to be able to mark that they can coerce unsized types
+that they are pointing at.
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index c1d8cd9bb9e..b11793c190a 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -10,6 +10,7 @@ derive_setters = "0.1.6"
 rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
+rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_error_codes = { path = "../rustc_error_codes" }
 rustc_error_messages = { path = "../rustc_error_messages" }
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index 7f383946c14..db6532f41ea 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -8,6 +8,7 @@ use std::process::ExitStatus;
 use rustc_abi::TargetDataLayoutErrors;
 use rustc_ast::util::parser::ExprPrecedence;
 use rustc_ast_pretty::pprust;
+use rustc_attr_data_structures::RustcVersion;
 use rustc_macros::Subdiagnostic;
 use rustc_span::edition::Edition;
 use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, Symbol};
@@ -96,6 +97,12 @@ into_diag_arg_using_display!(
     rustc_abi::ExternAbi,
 );
 
+impl IntoDiagArg for RustcVersion {
+    fn into_diag_arg(self) -> DiagArgValue {
+        DiagArgValue::Str(Cow::Owned(self.to_string()))
+    }
+}
+
 impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::TraitRef<I> {
     fn into_diag_arg(self) -> DiagArgValue {
         self.to_string().into_diag_arg()
diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml
index 33bada106ca..0ba139ea5cc 100644
--- a/compiler/rustc_expand/Cargo.toml
+++ b/compiler/rustc_expand/Cargo.toml
@@ -17,6 +17,7 @@ rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_feature = { path = "../rustc_feature" }
 rustc_fluent_macro = { path = "../rustc_fluent_macro" }
+rustc_hir = { path = "../rustc_hir" }
 rustc_lexer = { path = "../rustc_lexer" }
 rustc_lint_defs = { path = "../rustc_lint_defs" }
 rustc_macros = { path = "../rustc_macros" }
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 819694d1cdc..4a250145308 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -11,11 +11,12 @@ use rustc_ast::token::Nonterminal;
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::visit::{AssocCtxt, Visitor};
 use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind};
-use rustc_attr_parsing::{self as attr, Deprecation, Stability};
+use rustc_attr_parsing::{AttributeKind, Deprecation, Stability, find_attr};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync;
 use rustc_errors::{DiagCtxtHandle, ErrorGuaranteed, PResult};
 use rustc_feature::Features;
+use rustc_hir as hir;
 use rustc_lint_defs::{BufferedEarlyLint, RegisteredTools};
 use rustc_parse::MACRO_ARGUMENTS;
 use rustc_parse::parser::Parser;
@@ -838,19 +839,23 @@ impl SyntaxExtension {
     /// and other properties converted from attributes.
     pub fn new(
         sess: &Session,
-        features: &Features,
         kind: SyntaxExtensionKind,
         span: Span,
         helper_attrs: Vec<Symbol>,
         edition: Edition,
         name: Symbol,
-        attrs: &[impl AttributeExt],
+        attrs: &[hir::Attribute],
         is_local: bool,
     ) -> SyntaxExtension {
         let allow_internal_unstable =
-            rustc_attr_parsing::allow_internal_unstable(sess, attrs).collect::<Vec<Symbol>>();
+            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 = ast::attr::contains_name(attrs, sym::allow_internal_unsafe);
         let local_inner_macros = ast::attr::find_by_name(attrs, sym::macro_export)
             .and_then(|macro_export| macro_export.meta_item_list())
             .is_some_and(|l| ast::attr::list_contains_name(&l, sym::local_inner_macros));
@@ -867,16 +872,17 @@ impl SyntaxExtension {
                 )
             })
             .unwrap_or_else(|| (None, helper_attrs));
-        let stability = attr::find_stability(sess, attrs, span);
-        let const_stability = attr::find_const_stability(sess, attrs, span);
-        let body_stability = attr::find_body_stability(sess, attrs);
-        if let Some((_, sp)) = const_stability {
+
+        let stability = find_attr!(attrs, AttributeKind::Stability{stability, ..} => *stability);
+
+        // FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem
+        if let Some(sp) = find_attr!(attrs, AttributeKind::ConstStability{span, ..} => *span) {
             sess.dcx().emit_err(errors::MacroConstStability {
                 span: sp,
                 head_span: sess.source_map().guess_head_span(span),
             });
         }
-        if let Some((_, sp)) = body_stability {
+        if let Some(sp) = find_attr!(attrs, AttributeKind::BodyStability{span, ..} => *span) {
             sess.dcx().emit_err(errors::MacroBodyStability {
                 span: sp,
                 head_span: sess.source_map().guess_head_span(span),
@@ -887,9 +893,10 @@ impl SyntaxExtension {
             kind,
             span,
             allow_internal_unstable: (!allow_internal_unstable.is_empty())
-                .then(|| allow_internal_unstable.into()),
-            stability: stability.map(|(s, _)| s),
-            deprecation: attr::find_deprecation(sess, features, attrs).map(|(d, _)| d),
+                // FIXME(jdonszelmann): avoid the into_iter/collect?
+                .then(|| allow_internal_unstable.iter().map(|i| i.0).collect::<Vec<_>>().into()),
+            stability,
+            deprecation: find_attr!(attrs, AttributeKind::Deprecation{deprecation, ..} => *deprecation),
             helper_attrs,
             edition,
             builtin_name,
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index b02a9b93c8a..cc7e3e65105 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -3,17 +3,17 @@ use std::collections::hash_map::Entry;
 use std::{mem, slice};
 
 use ast::token::IdentIsRaw;
-use rustc_ast::attr::AttributeExt;
 use rustc_ast::token::NtPatKind::*;
 use rustc_ast::token::TokenKind::*;
 use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind};
 use rustc_ast::tokenstream::{DelimSpan, TokenStream};
 use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId};
 use rustc_ast_pretty::pprust;
-use rustc_attr_parsing::{self as attr, TransparencyError};
+use rustc_attr_parsing::{AttributeKind, find_attr};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_errors::{Applicability, ErrorGuaranteed};
 use rustc_feature::Features;
+use rustc_hir as hir;
 use rustc_lint_defs::BuiltinLintDiag;
 use rustc_lint_defs::builtin::{
     RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
@@ -371,7 +371,7 @@ pub fn compile_declarative_macro(
     features: &Features,
     macro_def: &ast::MacroDef,
     ident: Ident,
-    attrs: &[impl AttributeExt],
+    attrs: &[hir::Attribute],
     span: Span,
     node_id: NodeId,
     edition: Edition,
@@ -379,7 +379,6 @@ pub fn compile_declarative_macro(
     let mk_syn_ext = |expander| {
         SyntaxExtension::new(
             sess,
-            features,
             SyntaxExtensionKind::LegacyBang(expander),
             span,
             Vec::new(),
@@ -391,7 +390,6 @@ pub fn compile_declarative_macro(
     };
     let dummy_syn_ext = |guar| (mk_syn_ext(Box::new(DummyExpander(guar))), Vec::new());
 
-    let dcx = sess.dcx();
     let lhs_nm = Ident::new(sym::lhs, span);
     let rhs_nm = Ident::new(sym::rhs, span);
     let tt_spec = Some(NonterminalKind::TT);
@@ -542,16 +540,8 @@ pub fn compile_declarative_macro(
 
     check_emission(macro_check::check_meta_variables(&sess.psess, node_id, span, &lhses, &rhses));
 
-    let (transparency, transparency_error) = attr::find_transparency(attrs, macro_rules);
-    match transparency_error {
-        Some(TransparencyError::UnknownTransparency(value, span)) => {
-            dcx.span_err(span, format!("unknown macro transparency: `{value}`"));
-        }
-        Some(TransparencyError::MultipleTransparencyAttrs(old_span, new_span)) => {
-            dcx.span_err(vec![old_span, new_span], "multiple macro transparency attributes");
-        }
-        None => {}
-    }
+    let transparency = find_attr!(attrs, AttributeKind::MacroTransparency(x) => *x)
+        .unwrap_or(Transparency::fallback(macro_rules));
 
     if let Some(guar) = guar {
         // To avoid warning noise, only consider the rules of this
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index b2ada8fe61e..6d16dc00ef4 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -1005,10 +1005,6 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         rustc_intrinsic, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, intrinsics,
         "the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items",
     ),
-    gated!(
-        rustc_intrinsic_must_be_overridden, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, intrinsics,
-        "the `#[rustc_intrinsic_must_be_overridden]` attribute is used to declare intrinsics without real bodies",
-    ),
     rustc_attr!(
         rustc_no_mir_inline, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes,
         "#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen"
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index 60e7788f2c0..fc58b66ad35 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -100,6 +100,15 @@ declare_features! (
      Some("renamed to `doc_notable_trait`")),
     /// Allows using `#[unsafe_destructor_blind_to_params]` (RFC 1238).
     (removed, dropck_parametricity, "1.38.0", Some(28498), None),
+    /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn compatible[^1].
+    /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and
+    /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden.
+    ///
+    /// Renamed from `object_safe_for_dispatch`.
+    ///
+    /// [^1]: Formerly known as "object safe".
+    (removed, dyn_compatible_for_dispatch, "1.83.0", Some(43561),
+     Some("removed, not used heavily and represented additional complexity in dyn compatibility")),
     /// Uses generic effect parameters for ~const bounds
     (removed, effects, "1.84.0", Some(102090),
      Some("removed, redundant with `#![feature(const_trait_impl)]`")),
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index fe643e9a7d1..66c26a541f1 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -270,14 +270,6 @@ declare_features! (
     (unstable, doc_notable_trait, "1.52.0", Some(45040)),
     /// Allows using the `may_dangle` attribute (RFC 1327).
     (unstable, dropck_eyepatch, "1.10.0", Some(34761)),
-    /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn compatible[^1].
-    /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and
-    /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden.
-    ///
-    /// Renamed from `object_safe_for_dispatch`.
-    ///
-    /// [^1]: Formerly known as "object safe".
-    (unstable, dyn_compatible_for_dispatch, "1.83.0", Some(43561)),
     /// Allows using the `#[fundamental]` attribute.
     (unstable, fundamental, "1.0.0", Some(29635)),
     /// Allows using `#[link_name="llvm.*"]`.
diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml
index 98300fc40fb..7ca8539845a 100644
--- a/compiler/rustc_hir/Cargo.toml
+++ b/compiler/rustc_hir/Cargo.toml
@@ -9,6 +9,7 @@ odht = { version = "0.3.1", features = ["nightly"] }
 rustc_abi = { path = "../rustc_abi" }
 rustc_arena = { path = "../rustc_arena" }
 rustc_ast = { path = "../rustc_ast" }
+rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_hashes = { path = "../rustc_hashes" }
 rustc_index = { path = "../rustc_index" }
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 61f64e62058..f0eaec55dbd 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1,18 +1,20 @@
+// ignore-tidy-filelength
 use std::fmt;
 
 use rustc_abi::ExternAbi;
-// ignore-tidy-filelength
 use rustc_ast::attr::AttributeExt;
 use rustc_ast::token::CommentKind;
 use rustc_ast::util::parser::{AssocOp, ExprPrecedence};
 use rustc_ast::{
-    self as ast, AttrId, AttrStyle, DelimArgs, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece,
-    IntTy, Label, LitIntType, LitKind, MetaItemInner, MetaItemLit, TraitObjectSyntax, UintTy,
+    self as ast, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label, LitIntType,
+    LitKind, TraitObjectSyntax, UintTy, UnsafeBinderCastKind,
 };
 pub use rustc_ast::{
-    BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy,
-    ImplPolarity, IsAuto, Movability, Mutability, UnOp, UnsafeBinderCastKind,
+    AttrId, AttrStyle, BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity,
+    ByRef, CaptureBy, DelimArgs, ImplPolarity, IsAuto, MetaItemInner, MetaItemLit, Movability,
+    Mutability, UnOp,
 };
+use rustc_attr_data_structures::AttributeKind;
 use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::tagged_ptr::TaggedRef;
@@ -1009,174 +1011,248 @@ pub enum AttrArgs {
     },
 }
 
-#[derive(Clone, Debug, Encodable, Decodable)]
-pub enum AttrKind {
-    /// A normal attribute.
-    Normal(Box<AttrItem>),
-
-    /// A doc comment (e.g. `/// ...`, `//! ...`, `/** ... */`, `/*! ... */`).
-    /// Doc attributes (e.g. `#[doc="..."]`) are represented with the `Normal`
-    /// variant (which is much less compact and thus more expensive).
-    DocComment(CommentKind, Symbol),
-}
-
 #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)]
 pub struct AttrPath {
     pub segments: Box<[Ident]>,
     pub span: Span,
 }
 
+impl AttrPath {
+    pub fn from_ast(path: &ast::Path) -> Self {
+        AttrPath {
+            segments: path.segments.iter().map(|i| i.ident).collect::<Vec<_>>().into_boxed_slice(),
+            span: path.span,
+        }
+    }
+}
+
+impl fmt::Display for AttrPath {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{}", self.segments.iter().map(|i| i.to_string()).collect::<Vec<_>>().join("::"))
+    }
+}
+
 #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable)]
 pub struct AttrItem {
-    pub unsafety: Safety,
     // Not lowered to hir::Path because we have no NodeId to resolve to.
     pub path: AttrPath,
     pub args: AttrArgs,
-}
-
-#[derive(Clone, Debug, Encodable, Decodable)]
-pub struct Attribute {
-    pub kind: AttrKind,
-    pub id: AttrId,
+    pub id: HashIgnoredAttrId,
     /// Denotes if the attribute decorates the following construct (outer)
     /// or the construct this attribute is contained within (inner).
     pub style: AttrStyle,
+    /// Span of the entire attribute
     pub span: Span,
 }
 
+/// The derived implementation of [`HashStable_Generic`] on [`Attribute`]s shouldn't hash
+/// [`AttrId`]s. By wrapping them in this, we make sure we never do.
+#[derive(Copy, Debug, Encodable, Decodable, Clone)]
+pub struct HashIgnoredAttrId {
+    pub attr_id: AttrId,
+}
+
+#[derive(Clone, Debug, Encodable, Decodable, HashStable_Generic)]
+pub enum Attribute {
+    /// A parsed built-in attribute.
+    ///
+    /// Each attribute has a span connected to it. However, you must be somewhat careful using it.
+    /// That's because sometimes we merge multiple attributes together, like when an item has
+    /// multiple `repr` attributes. In this case the span might not be very useful.
+    Parsed(AttributeKind),
+
+    /// An attribute that could not be parsed, out of a token-like representation.
+    /// This is the case for custom tool attributes.
+    Unparsed(Box<AttrItem>),
+}
+
 impl Attribute {
     pub fn get_normal_item(&self) -> &AttrItem {
-        match &self.kind {
-            AttrKind::Normal(normal) => &normal,
-            AttrKind::DocComment(..) => panic!("unexpected doc comment"),
+        match &self {
+            Attribute::Unparsed(normal) => &normal,
+            _ => panic!("unexpected parsed attribute"),
         }
     }
 
     pub fn unwrap_normal_item(self) -> AttrItem {
-        match self.kind {
-            AttrKind::Normal(normal) => *normal,
-            AttrKind::DocComment(..) => panic!("unexpected doc comment"),
+        match self {
+            Attribute::Unparsed(normal) => *normal,
+            _ => panic!("unexpected parsed attribute"),
         }
     }
 
     pub fn value_lit(&self) -> Option<&MetaItemLit> {
-        match &self.kind {
-            AttrKind::Normal(box AttrItem { args: AttrArgs::Eq { expr, .. }, .. }) => Some(expr),
+        match &self {
+            Attribute::Unparsed(n) => match n.as_ref() {
+                AttrItem { args: AttrArgs::Eq { eq_span: _, expr }, .. } => Some(expr),
+                _ => None,
+            },
             _ => None,
         }
     }
 }
 
 impl AttributeExt for Attribute {
+    #[inline]
     fn id(&self) -> AttrId {
-        self.id
+        match &self {
+            Attribute::Unparsed(u) => u.id.attr_id,
+            _ => panic!(),
+        }
     }
 
+    #[inline]
     fn meta_item_list(&self) -> Option<ThinVec<ast::MetaItemInner>> {
-        match &self.kind {
-            AttrKind::Normal(box AttrItem { args: AttrArgs::Delimited(d), .. }) => {
-                ast::MetaItemKind::list_from_tokens(d.tokens.clone())
-            }
+        match &self {
+            Attribute::Unparsed(n) => match n.as_ref() {
+                AttrItem { args: AttrArgs::Delimited(d), .. } => {
+                    ast::MetaItemKind::list_from_tokens(d.tokens.clone())
+                }
+                _ => None,
+            },
             _ => None,
         }
     }
 
+    #[inline]
     fn value_str(&self) -> Option<Symbol> {
         self.value_lit().and_then(|x| x.value_str())
     }
 
+    #[inline]
     fn value_span(&self) -> Option<Span> {
         self.value_lit().map(|i| i.span)
     }
 
     /// For a single-segment attribute, returns its name; otherwise, returns `None`.
+    #[inline]
     fn ident(&self) -> Option<Ident> {
-        match &self.kind {
-            AttrKind::Normal(box AttrItem {
-                path: AttrPath { segments: box [ident], .. }, ..
-            }) => Some(*ident),
+        match &self {
+            Attribute::Unparsed(n) => {
+                if let [ident] = n.path.segments.as_ref() {
+                    Some(*ident)
+                } else {
+                    None
+                }
+            }
             _ => None,
         }
     }
 
+    #[inline]
     fn path_matches(&self, name: &[Symbol]) -> bool {
-        match &self.kind {
-            AttrKind::Normal(n) => n.path.segments.iter().map(|segment| &segment.name).eq(name),
-            AttrKind::DocComment(..) => false,
+        match &self {
+            Attribute::Unparsed(n) => {
+                n.path.segments.len() == name.len()
+                    && n.path.segments.iter().zip(name).all(|(s, n)| s.name == *n)
+            }
+            _ => false,
         }
     }
 
+    #[inline]
     fn is_doc_comment(&self) -> bool {
-        matches!(self.kind, AttrKind::DocComment(..))
+        matches!(self, Attribute::Parsed(AttributeKind::DocComment { .. }))
     }
 
+    #[inline]
     fn span(&self) -> Span {
-        self.span
+        match &self {
+            Attribute::Unparsed(u) => u.span,
+            // FIXME: should not be needed anymore when all attrs are parsed
+            Attribute::Parsed(AttributeKind::Deprecation { span, .. }) => *span,
+            Attribute::Parsed(AttributeKind::DocComment { span, .. }) => *span,
+            a => panic!("can't get the span of an arbitrary parsed attribute: {a:?}"),
+        }
     }
 
+    #[inline]
     fn is_word(&self) -> bool {
-        matches!(self.kind, AttrKind::Normal(box AttrItem { args: AttrArgs::Empty, .. }))
+        match &self {
+            Attribute::Unparsed(n) => {
+                matches!(n.args, AttrArgs::Empty)
+            }
+            _ => false,
+        }
     }
 
+    #[inline]
     fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
-        match &self.kind {
-            AttrKind::Normal(n) => Some(n.path.segments.iter().copied().collect()),
-            AttrKind::DocComment(..) => None,
+        match &self {
+            Attribute::Unparsed(n) => Some(n.path.segments.iter().copied().collect()),
+            _ => None,
         }
     }
 
+    #[inline]
     fn doc_str(&self) -> Option<Symbol> {
-        match &self.kind {
-            AttrKind::DocComment(.., data) => Some(*data),
-            AttrKind::Normal(_) if self.has_name(sym::doc) => self.value_str(),
+        match &self {
+            Attribute::Parsed(AttributeKind::DocComment { comment, .. }) => Some(*comment),
+            Attribute::Unparsed(_) if self.has_name(sym::doc) => self.value_str(),
             _ => None,
         }
     }
+    #[inline]
     fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
-        match &self.kind {
-            AttrKind::DocComment(kind, data) => Some((*data, *kind)),
-            AttrKind::Normal(_) if self.name_or_empty() == sym::doc => {
+        match &self {
+            Attribute::Parsed(AttributeKind::DocComment { kind, comment, .. }) => {
+                Some((*comment, *kind))
+            }
+            Attribute::Unparsed(_) if self.name_or_empty() == sym::doc => {
                 self.value_str().map(|s| (s, CommentKind::Line))
             }
             _ => None,
         }
     }
 
+    #[inline]
     fn style(&self) -> AttrStyle {
-        self.style
+        match &self {
+            Attribute::Unparsed(u) => u.style,
+            Attribute::Parsed(AttributeKind::DocComment { style, .. }) => *style,
+            _ => panic!(),
+        }
     }
 }
 
 // FIXME(fn_delegation): use function delegation instead of manually forwarding
 impl Attribute {
+    #[inline]
     pub fn id(&self) -> AttrId {
         AttributeExt::id(self)
     }
 
+    #[inline]
     pub fn name_or_empty(&self) -> Symbol {
         AttributeExt::name_or_empty(self)
     }
 
+    #[inline]
     pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
         AttributeExt::meta_item_list(self)
     }
 
+    #[inline]
     pub fn value_str(&self) -> Option<Symbol> {
         AttributeExt::value_str(self)
     }
 
+    #[inline]
     pub fn value_span(&self) -> Option<Span> {
         AttributeExt::value_span(self)
     }
 
+    #[inline]
     pub fn ident(&self) -> Option<Ident> {
         AttributeExt::ident(self)
     }
 
+    #[inline]
     pub fn path_matches(&self, name: &[Symbol]) -> bool {
         AttributeExt::path_matches(self, name)
     }
 
+    #[inline]
     pub fn is_doc_comment(&self) -> bool {
         AttributeExt::is_doc_comment(self)
     }
@@ -1186,34 +1262,42 @@ impl Attribute {
         AttributeExt::has_name(self, name)
     }
 
+    #[inline]
     pub fn span(&self) -> Span {
         AttributeExt::span(self)
     }
 
+    #[inline]
     pub fn is_word(&self) -> bool {
         AttributeExt::is_word(self)
     }
 
+    #[inline]
     pub fn path(&self) -> SmallVec<[Symbol; 1]> {
         AttributeExt::path(self)
     }
 
+    #[inline]
     pub fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
         AttributeExt::ident_path(self)
     }
 
+    #[inline]
     pub fn doc_str(&self) -> Option<Symbol> {
         AttributeExt::doc_str(self)
     }
 
+    #[inline]
     pub fn is_proc_macro_attr(&self) -> bool {
         AttributeExt::is_proc_macro_attr(self)
     }
 
+    #[inline]
     pub fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
         AttributeExt::doc_str_and_comment_kind(self)
     }
 
+    #[inline]
     pub fn style(&self) -> AttrStyle {
         AttributeExt::style(self)
     }
diff --git a/compiler/rustc_hir/src/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs
index d7c8a3d5c0a..2709a826549 100644
--- a/compiler/rustc_hir/src/stable_hash_impls.rs
+++ b/compiler/rustc_hir/src/stable_hash_impls.rs
@@ -1,17 +1,21 @@
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
 use rustc_span::def_id::DefPathHash;
 
+use crate::HashIgnoredAttrId;
 use crate::hir::{
-    Attribute, AttributeMap, BodyId, Crate, ForeignItemId, ImplItemId, ItemId, OwnerNodes,
-    TraitItemId,
+    AttributeMap, BodyId, Crate, ForeignItemId, ImplItemId, ItemId, OwnerNodes, TraitItemId,
 };
 use crate::hir_id::{HirId, ItemLocalId};
 
 /// Requirements for a `StableHashingContext` to be used in this crate.
 /// This is a hack to allow using the `HashStable_Generic` derive macro
 /// instead of implementing everything in `rustc_middle`.
-pub trait HashStableContext: rustc_ast::HashStableContext + rustc_abi::HashStableContext {
-    fn hash_attr(&mut self, _: &Attribute, hasher: &mut StableHasher);
+pub trait HashStableContext:
+    rustc_attr_data_structures::HashStableContext
+    + rustc_ast::HashStableContext
+    + rustc_abi::HashStableContext
+{
+    fn hash_attr_id(&mut self, id: &HashIgnoredAttrId, hasher: &mut StableHasher);
 }
 
 impl<HirCtx: crate::HashStableContext> ToStableHashKey<HirCtx> for HirId {
@@ -114,8 +118,8 @@ impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Crate<'_> {
     }
 }
 
-impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for Attribute {
+impl<HirCtx: crate::HashStableContext> HashStable<HirCtx> for HashIgnoredAttrId {
     fn hash_stable(&self, hcx: &mut HirCtx, hasher: &mut StableHasher) {
-        hcx.hash_attr(self, hasher)
+        hcx.hash_attr_id(self, hasher)
     }
 }
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 47d5976be09..6badd290917 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -85,6 +85,10 @@ hir_analysis_cmse_output_stack_spill =
     .note1 = functions with the `{$abi}` ABI must pass their result via the available return registers
     .note2 = the result must either be a (transparently wrapped) i64, u64 or f64, or be at most 4 bytes in size
 
+hir_analysis_coerce_multi = implementing `{$trait_name}` does not allow multiple fields to be coerced
+    .note = the trait `{$trait_name}` may only be implemented when a single field is being coerced
+    .label = these fields must be coerced for `{$trait_name}` to be valid
+
 hir_analysis_coerce_pointee_no_field = `CoercePointee` can only be derived on `struct`s with at least one field
 
 hir_analysis_coerce_pointee_no_user_validity_assertion = asserting applicability of `derive(CoercePointee)` on a target data is forbidden
@@ -95,12 +99,12 @@ hir_analysis_coerce_pointee_not_struct = `derive(CoercePointee)` is only applica
 
 hir_analysis_coerce_pointee_not_transparent = `derive(CoercePointee)` is only applicable to `struct` with `repr(transparent)` layout
 
+hir_analysis_coerce_unsized_field_validity = for `{$ty}` to have a valid implementation of `{$trait_name}`, it must be possible to coerce the field of type `{$field_ty}`
+    .label = `{$field_ty}` must be a pointer, reference, or smart pointer that is allowed to be unsized
+
 hir_analysis_coerce_unsized_may = the trait `{$trait_name}` may only be implemented for a coercion between structures
 
-hir_analysis_coerce_unsized_multi = implementing the trait `CoerceUnsized` requires multiple coercions
-    .note = `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced
-    .coercions_note = currently, {$number} fields need coercions: {$coercions}
-    .label = requires multiple coercions
+hir_analysis_coerce_zero = implementing `{$trait_name}` requires a field to be coerced
 
 hir_analysis_coercion_between_struct_same_note = expected coercion between the same definition; expected `{$source_path}`, found `{$target_path}`
 
@@ -139,10 +143,6 @@ hir_analysis_cross_crate_traits = cross-crate traits with a default impl, like `
 hir_analysis_cross_crate_traits_defined = cross-crate traits with a default impl, like `{$traits}`, can only be implemented for a struct/enum type defined in the current crate
     .label = can't implement cross-crate trait for type in another crate
 
-hir_analysis_dispatch_from_dyn_multi = implementing the `DispatchFromDyn` trait requires multiple coercions
-    .note = the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced
-    .coercions_note = currently, {$number} fields need coercions: {$coercions}
-
 hir_analysis_dispatch_from_dyn_repr = structs implementing `DispatchFromDyn` may not have `#[repr(packed)]` or `#[repr(C)]`
 
 hir_analysis_dispatch_from_dyn_zst = the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment that don't mention type/const generics, and nothing else
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 3236e0a3644..09320b86878 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -2,6 +2,8 @@ use std::cell::LazyCell;
 use std::ops::ControlFlow;
 
 use rustc_abi::FieldIdx;
+use rustc_attr_parsing::AttributeKind;
+use rustc_attr_parsing::ReprAttr::ReprPacked;
 use rustc_data_structures::unord::{UnordMap, UnordSet};
 use rustc_errors::MultiSpan;
 use rustc_errors::codes::*;
@@ -1114,7 +1116,7 @@ fn check_impl_items_against_trait<'tcx>(
         if let Some(missing_items) = must_implement_one_of {
             let attr_span = tcx
                 .get_attr(trait_ref.def_id, sym::rustc_must_implement_one_of)
-                .map(|attr| attr.span);
+                .map(|attr| attr.span());
 
             missing_items_must_implement_one_of_err(
                 tcx,
@@ -1203,11 +1205,13 @@ fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
 pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
     let repr = def.repr();
     if repr.packed() {
-        for attr in tcx.get_attrs(def.did(), sym::repr) {
-            for r in attr::parse_repr_attr(tcx.sess, attr) {
-                if let attr::ReprPacked(pack) = r
+        if let Some(reprs) =
+            attr::find_attr!(tcx.get_all_attrs(def.did()), AttributeKind::Repr(r) => r)
+        {
+            for (r, _) in reprs {
+                if let ReprPacked(pack) = r
                     && let Some(repr_pack) = repr.pack
-                    && pack != repr_pack
+                    && pack != &repr_pack
                 {
                     struct_span_code_err!(
                         tcx.dcx(),
@@ -1419,16 +1423,19 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     def.destructor(tcx); // force the destructor to be evaluated
 
     if def.variants().is_empty() {
-        if let Some(attr) = tcx.get_attrs(def_id, sym::repr).next() {
-            struct_span_code_err!(
-                tcx.dcx(),
-                attr.span,
-                E0084,
-                "unsupported representation for zero-variant enum"
-            )
-            .with_span_label(tcx.def_span(def_id), "zero-variant enum")
-            .emit();
-        }
+        attr::find_attr!(
+            tcx.get_all_attrs(def_id),
+            AttributeKind::Repr(rs) => {
+                struct_span_code_err!(
+                    tcx.dcx(),
+                    rs.first().unwrap().1,
+                    E0084,
+                    "unsupported representation for zero-variant enum"
+                )
+                .with_span_label(tcx.def_span(def_id), "zero-variant enum")
+                .emit();
+            }
+        );
     }
 
     let repr_type_ty = def.repr().discr_type().to_ty(tcx);
diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs
index 25c2f8554b7..3bad36da999 100644
--- a/compiler/rustc_hir_analysis/src/check/entry.rs
+++ b/compiler/rustc_hir_analysis/src/check/entry.rs
@@ -99,7 +99,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
     }
 
     for attr in tcx.get_attrs(main_def_id, sym::track_caller) {
-        tcx.dcx().emit_err(errors::TrackCallerOnMain { span: attr.span, annotated: main_span });
+        tcx.dcx().emit_err(errors::TrackCallerOnMain { span: attr.span(), annotated: main_span });
         error = true;
     }
 
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index d468027602c..fedc197e7ef 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -699,7 +699,7 @@ pub fn check_intrinsic_type(
             | sym::simd_reduce_min
             | sym::simd_reduce_max => (2, 0, vec![param(0)], param(1)),
             sym::simd_shuffle => (3, 0, vec![param(0), param(0), param(1)], param(2)),
-            sym::simd_shuffle_generic => (2, 1, vec![param(0), param(0)], param(1)),
+            sym::simd_shuffle_const_generic => (2, 1, vec![param(0), param(0)], param(1)),
 
             other => {
                 tcx.dcx().emit_err(UnrecognizedIntrinsicFunction { span, name: other });
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index e1727fc48a8..51194740450 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -27,20 +27,19 @@ enum NonAsmTypeReason<'tcx> {
     UnevaluatedSIMDArrayLength(DefId, ty::Const<'tcx>),
     Invalid(Ty<'tcx>),
     InvalidElement(DefId, Ty<'tcx>),
+    NotSizedPtr(Ty<'tcx>),
 }
 
 impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
     pub fn new(
         tcx: TyCtxt<'tcx>,
         def_id: LocalDefId,
+        typing_env: ty::TypingEnv<'tcx>,
         get_operand_ty: impl Fn(&hir::Expr<'tcx>) -> Ty<'tcx> + 'a,
     ) -> Self {
         InlineAsmCtxt {
             tcx,
-            typing_env: ty::TypingEnv {
-                typing_mode: ty::TypingMode::non_body_analysis(),
-                param_env: ty::ParamEnv::empty(),
-            },
+            typing_env,
             target_features: tcx.asm_target_features(def_id),
             expr_ty: Box::new(get_operand_ty),
         }
@@ -83,7 +82,13 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
             ty::Float(FloatTy::F64) => Ok(InlineAsmType::F64),
             ty::Float(FloatTy::F128) => Ok(InlineAsmType::F128),
             ty::FnPtr(..) => Ok(asm_ty_isize),
-            ty::RawPtr(ty, _) if self.is_thin_ptr_ty(ty) => Ok(asm_ty_isize),
+            ty::RawPtr(elem_ty, _) => {
+                if self.is_thin_ptr_ty(elem_ty) {
+                    Ok(asm_ty_isize)
+                } else {
+                    Err(NonAsmTypeReason::NotSizedPtr(ty))
+                }
+            }
             ty::Adt(adt, args) if adt.repr().simd() => {
                 let fields = &adt.non_enum_variant().fields;
                 let field = &fields[FieldIdx::ZERO];
@@ -189,6 +194,16 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                             can be used as arguments for inline assembly",
                         ).emit();
                     }
+                    NonAsmTypeReason::NotSizedPtr(ty) => {
+                        let msg = format!(
+                            "cannot use value of unsized pointer type `{ty}` for inline assembly"
+                        );
+                        self.tcx
+                            .dcx()
+                            .struct_span_err(expr.span, msg)
+                            .with_note("only sized pointers can be used in inline assembly")
+                            .emit();
+                    }
                     NonAsmTypeReason::InvalidElement(did, ty) => {
                         let msg = format!(
                             "cannot use SIMD vector with element type `{ty}` for inline assembly"
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index b46b805f0a9..cee2f487639 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -17,7 +17,7 @@ use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::{
     self, Ty, TyCtxt, TypeVisitableExt, TypingMode, suggest_constraining_type_params,
 };
-use rustc_span::{DUMMY_SP, Span};
+use rustc_span::{DUMMY_SP, Span, sym};
 use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
 use rustc_trait_selection::traits::misc::{
     ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason,
@@ -195,8 +195,14 @@ fn visit_implementation_of_coerce_unsized(checker: &Checker<'_>) -> Result<(), E
     // Just compute this for the side-effects, in particular reporting
     // errors; other parts of the code may demand it for the info of
     // course.
-    let span = tcx.def_span(impl_did);
-    tcx.at(span).ensure_ok().coerce_unsized_info(impl_did)
+    tcx.ensure_ok().coerce_unsized_info(impl_did)
+}
+
+fn is_from_coerce_pointee_derive(tcx: TyCtxt<'_>, span: Span) -> bool {
+    span.ctxt()
+        .outer_expn_data()
+        .macro_def_id
+        .is_some_and(|def_id| tcx.is_diagnostic_item(sym::CoercePointee, def_id))
 }
 
 fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> {
@@ -206,17 +212,29 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
     debug!("visit_implementation_of_dispatch_from_dyn: impl_did={:?}", impl_did);
 
     let span = tcx.def_span(impl_did);
+    let trait_name = "DispatchFromDyn";
 
     let dispatch_from_dyn_trait = tcx.require_lang_item(LangItem::DispatchFromDyn, Some(span));
 
     let source = trait_ref.self_ty();
-    assert!(!source.has_escaping_bound_vars());
     let target = {
         assert_eq!(trait_ref.def_id, dispatch_from_dyn_trait);
 
         trait_ref.args.type_at(1)
     };
 
+    // Check `CoercePointee` impl is WF -- if not, then there's no reason to report
+    // redundant errors for `DispatchFromDyn`. This is best effort, though.
+    let mut res = Ok(());
+    tcx.for_each_relevant_impl(
+        tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)),
+        source,
+        |impl_def_id| {
+            res = res.and(tcx.ensure_ok().coerce_unsized_info(impl_def_id));
+        },
+    );
+    res?;
+
     debug!("visit_implementation_of_dispatch_from_dyn: {:?} -> {:?}", source, target);
 
     let param_env = tcx.param_env(impl_did);
@@ -242,26 +260,25 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
             if def_a != def_b {
                 let source_path = tcx.def_path_str(def_a.did());
                 let target_path = tcx.def_path_str(def_b.did());
-
-                return Err(tcx.dcx().emit_err(errors::DispatchFromDynCoercion {
+                return Err(tcx.dcx().emit_err(errors::CoerceSameStruct {
                     span,
-                    trait_name: "DispatchFromDyn",
+                    trait_name,
                     note: true,
                     source_path,
                     target_path,
                 }));
             }
 
-            let mut res = Ok(());
             if def_a.repr().c() || def_a.repr().packed() {
-                res = Err(tcx.dcx().emit_err(errors::DispatchFromDynRepr { span }));
+                return Err(tcx.dcx().emit_err(errors::DispatchFromDynRepr { span }));
             }
 
             let fields = &def_a.non_enum_variant().fields;
 
+            let mut res = Ok(());
             let coerced_fields = fields
-                .iter()
-                .filter(|field| {
+                .iter_enumerated()
+                .filter_map(|(i, field)| {
                     // Ignore PhantomData fields
                     let unnormalized_ty = tcx.type_of(field.did).instantiate_identity();
                     if tcx
@@ -272,7 +289,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
                         .unwrap_or(unnormalized_ty)
                         .is_phantom_data()
                     {
-                        return false;
+                        return None;
                     }
 
                     let ty_a = field.ty(tcx, args_a);
@@ -290,7 +307,7 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
                             && !ty_a.has_non_region_param()
                         {
                             // ignore 1-ZST fields
-                            return false;
+                            return None;
                         }
 
                         res = Err(tcx.dcx().emit_err(errors::DispatchFromDynZST {
@@ -299,64 +316,57 @@ fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<()
                             ty: ty_a,
                         }));
 
-                        return false;
+                        None
+                    } else {
+                        Some((i, ty_a, ty_b, tcx.def_span(field.did)))
                     }
-
-                    true
                 })
                 .collect::<Vec<_>>();
+            res?;
 
             if coerced_fields.is_empty() {
-                res = Err(tcx.dcx().emit_err(errors::DispatchFromDynSingle {
+                return Err(tcx.dcx().emit_err(errors::CoerceNoField {
                     span,
-                    trait_name: "DispatchFromDyn",
+                    trait_name,
                     note: true,
                 }));
-            } else if coerced_fields.len() > 1 {
-                res = Err(tcx.dcx().emit_err(errors::DispatchFromDynMulti {
-                    span,
-                    coercions_note: true,
-                    number: coerced_fields.len(),
-                    coercions: coerced_fields
-                        .iter()
-                        .map(|field| {
-                            format!(
-                                "`{}` (`{}` to `{}`)",
-                                field.name,
-                                field.ty(tcx, args_a),
-                                field.ty(tcx, args_b),
-                            )
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", "),
-                }));
-            } else {
+            } else if let &[(_, ty_a, ty_b, field_span)] = &coerced_fields[..] {
                 let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
-                for field in coerced_fields {
-                    ocx.register_obligation(Obligation::new(
-                        tcx,
-                        cause.clone(),
-                        param_env,
-                        ty::TraitRef::new(
-                            tcx,
-                            dispatch_from_dyn_trait,
-                            [field.ty(tcx, args_a), field.ty(tcx, args_b)],
-                        ),
-                    ));
-                }
+                ocx.register_obligation(Obligation::new(
+                    tcx,
+                    cause.clone(),
+                    param_env,
+                    ty::TraitRef::new(tcx, dispatch_from_dyn_trait, [ty_a, ty_b]),
+                ));
                 let errors = ocx.select_all_or_error();
                 if !errors.is_empty() {
-                    res = Err(infcx.err_ctxt().report_fulfillment_errors(errors));
+                    if is_from_coerce_pointee_derive(tcx, span) {
+                        return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity {
+                            span,
+                            trait_name,
+                            ty: trait_ref.self_ty(),
+                            field_span,
+                            field_ty: ty_a,
+                        }));
+                    } else {
+                        return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
+                    }
                 }
 
                 // Finally, resolve all regions.
-                res = res.and(ocx.resolve_regions_and_report_errors(impl_did, param_env, []));
+                ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
+
+                Ok(())
+            } else {
+                return Err(tcx.dcx().emit_err(errors::CoerceMulti {
+                    span,
+                    trait_name,
+                    number: coerced_fields.len(),
+                    fields: coerced_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),
+                }));
             }
-            res
         }
-        _ => Err(tcx
-            .dcx()
-            .emit_err(errors::CoerceUnsizedMay { span, trait_name: "DispatchFromDyn" })),
+        _ => Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name })),
     }
 }
 
@@ -366,13 +376,14 @@ pub(crate) fn coerce_unsized_info<'tcx>(
 ) -> Result<CoerceUnsizedInfo, ErrorGuaranteed> {
     debug!("compute_coerce_unsized_info(impl_did={:?})", impl_did);
     let span = tcx.def_span(impl_did);
+    let trait_name = "CoerceUnsized";
 
     let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span));
-
     let unsize_trait = tcx.require_lang_item(LangItem::Unsize, Some(span));
 
     let source = tcx.type_of(impl_did).instantiate_identity();
     let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().instantiate_identity();
+
     assert_eq!(trait_ref.def_id, coerce_unsized_trait);
     let target = trait_ref.args.type_at(1);
     debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)", source, target);
@@ -399,9 +410,9 @@ pub(crate) fn coerce_unsized_info<'tcx>(
                 )
                 .emit();
         }
-        (mt_a.ty, mt_b.ty, unsize_trait, None)
+        (mt_a.ty, mt_b.ty, unsize_trait, None, span)
     };
-    let (source, target, trait_def_id, kind) = match (source.kind(), target.kind()) {
+    let (source, target, trait_def_id, kind, field_span) = match (source.kind(), target.kind()) {
         (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => {
             infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
             let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a };
@@ -422,9 +433,9 @@ pub(crate) fn coerce_unsized_info<'tcx>(
             if def_a != def_b {
                 let source_path = tcx.def_path_str(def_a.did());
                 let target_path = tcx.def_path_str(def_b.did());
-                return Err(tcx.dcx().emit_err(errors::DispatchFromDynSame {
+                return Err(tcx.dcx().emit_err(errors::CoerceSameStruct {
                     span,
-                    trait_name: "CoerceUnsized",
+                    trait_name,
                     note: true,
                     source_path,
                     target_path,
@@ -504,14 +515,14 @@ pub(crate) fn coerce_unsized_info<'tcx>(
 
                     // Collect up all fields that were significantly changed
                     // i.e., those that contain T in coerce_unsized T -> U
-                    Some((i, a, b))
+                    Some((i, a, b, tcx.def_span(f.did)))
                 })
                 .collect::<Vec<_>>();
 
             if diff_fields.is_empty() {
-                return Err(tcx.dcx().emit_err(errors::CoerceUnsizedOneField {
+                return Err(tcx.dcx().emit_err(errors::CoerceNoField {
                     span,
-                    trait_name: "CoerceUnsized",
+                    trait_name,
                     note: true,
                 }));
             } else if diff_fields.len() > 1 {
@@ -522,27 +533,21 @@ pub(crate) fn coerce_unsized_info<'tcx>(
                     tcx.def_span(impl_did)
                 };
 
-                return Err(tcx.dcx().emit_err(errors::CoerceUnsizedMulti {
+                return Err(tcx.dcx().emit_err(errors::CoerceMulti {
                     span,
-                    coercions_note: true,
+                    trait_name,
                     number: diff_fields.len(),
-                    coercions: diff_fields
-                        .iter()
-                        .map(|&(i, a, b)| format!("`{}` (`{}` to `{}`)", fields[i].name, a, b))
-                        .collect::<Vec<_>>()
-                        .join(", "),
+                    fields: diff_fields.iter().map(|(_, _, _, s)| *s).collect::<Vec<_>>().into(),
                 }));
             }
 
-            let (i, a, b) = diff_fields[0];
+            let (i, a, b, field_span) = diff_fields[0];
             let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
-            (a, b, coerce_unsized_trait, Some(kind))
+            (a, b, coerce_unsized_trait, Some(kind), field_span)
         }
 
         _ => {
-            return Err(tcx
-                .dcx()
-                .emit_err(errors::DispatchFromDynStruct { span, trait_name: "CoerceUnsized" }));
+            return Err(tcx.dcx().emit_err(errors::CoerceUnsizedNonStruct { span, trait_name }));
         }
     };
 
@@ -557,12 +562,23 @@ pub(crate) fn coerce_unsized_info<'tcx>(
     );
     ocx.register_obligation(obligation);
     let errors = ocx.select_all_or_error();
+
     if !errors.is_empty() {
-        infcx.err_ctxt().report_fulfillment_errors(errors);
+        if is_from_coerce_pointee_derive(tcx, span) {
+            return Err(tcx.dcx().emit_err(errors::CoerceFieldValidity {
+                span,
+                trait_name,
+                ty: trait_ref.self_ty(),
+                field_span,
+                field_ty: source,
+            }));
+        } else {
+            return Err(infcx.err_ctxt().report_fulfillment_errors(errors));
+        }
     }
 
     // Finally, resolve all regions.
-    let _ = ocx.resolve_regions_and_report_errors(impl_did, param_env, []);
+    ocx.resolve_regions_and_report_errors(impl_did, param_env, [])?;
 
     Ok(CoerceUnsizedInfo { custom_kind: kind })
 }
diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs
index 1bc60087ab5..0245d4c9fe4 100644
--- a/compiler/rustc_hir_analysis/src/coherence/mod.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs
@@ -199,11 +199,7 @@ fn check_object_overlap<'tcx>(
 
         for component_def_id in component_def_ids {
             if !tcx.is_dyn_compatible(component_def_id) {
-                // Without the 'dyn_compatible_for_dispatch' feature this is an error
-                // which will be reported by wfcheck. Ignore it here.
-                // This is tested by `coherence-impl-trait-for-trait-dyn-compatible.rs`.
-                // With the feature enabled, the trait is not implemented automatically,
-                // so this is valid.
+                // This is a WF error tested by `coherence-impl-trait-for-trait-dyn-compatible.rs`.
             } else {
                 let mut supertrait_def_ids = elaborate::supertrait_def_ids(tcx, component_def_id);
                 if supertrait_def_ids
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index dd91d70b004..2a2879c6577 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -1202,7 +1202,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
         // and that they are all identifiers
         .and_then(|attr| match attr.meta_item_list() {
             Some(items) if items.len() < 2 => {
-                tcx.dcx().emit_err(errors::MustImplementOneOfAttribute { span: attr.span });
+                tcx.dcx().emit_err(errors::MustImplementOneOfAttribute { span: attr.span() });
 
                 None
             }
@@ -1214,7 +1214,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
                     tcx.dcx().emit_err(errors::MustBeNameOfAssociatedFunction { span });
                 })
                 .ok()
-                .zip(Some(attr.span)),
+                .zip(Some(attr.span())),
             // Error is reported by `rustc_attr!`
             None => None,
         })
diff --git a/compiler/rustc_hir_analysis/src/collect/dump.rs b/compiler/rustc_hir_analysis/src/collect/dump.rs
index 63c445fa6a3..4debd3977f5 100644
--- a/compiler/rustc_hir_analysis/src/collect/dump.rs
+++ b/compiler/rustc_hir_analysis/src/collect/dump.rs
@@ -111,14 +111,14 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) {
                 let trait_ref = tcx.impl_trait_ref(def_id).unwrap().instantiate_identity();
                 if trait_ref.has_non_region_param() {
                     tcx.dcx().span_err(
-                        attr.span,
+                        attr.span(),
                         "`rustc_dump_vtable` must be applied to non-generic impl",
                     );
                     continue;
                 }
                 if !tcx.is_dyn_compatible(trait_ref.def_id) {
                     tcx.dcx().span_err(
-                        attr.span,
+                        attr.span(),
                         "`rustc_dump_vtable` must be applied to dyn-compatible trait",
                     );
                     continue;
@@ -127,7 +127,7 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) {
                     .try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), trait_ref)
                 else {
                     tcx.dcx().span_err(
-                        attr.span,
+                        attr.span(),
                         "`rustc_dump_vtable` applied to impl header that cannot be normalized",
                     );
                     continue;
@@ -138,7 +138,7 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) {
                 let ty = tcx.type_of(def_id).instantiate_identity();
                 if ty.has_non_region_param() {
                     tcx.dcx().span_err(
-                        attr.span,
+                        attr.span(),
                         "`rustc_dump_vtable` must be applied to non-generic type",
                     );
                     continue;
@@ -147,13 +147,14 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) {
                     tcx.try_normalize_erasing_regions(ty::TypingEnv::fully_monomorphized(), ty)
                 else {
                     tcx.dcx().span_err(
-                        attr.span,
+                        attr.span(),
                         "`rustc_dump_vtable` applied to type alias that cannot be normalized",
                     );
                     continue;
                 };
                 let ty::Dynamic(data, _, _) = *ty.kind() else {
-                    tcx.dcx().span_err(attr.span, "`rustc_dump_vtable` to type alias of dyn type");
+                    tcx.dcx()
+                        .span_err(attr.span(), "`rustc_dump_vtable` to type alias of dyn type");
                     continue;
                 };
                 if let Some(principal) = data.principal() {
@@ -166,7 +167,7 @@ pub(crate) fn vtables<'tcx>(tcx: TyCtxt<'tcx>) {
             }
             _ => {
                 tcx.dcx().span_err(
-                    attr.span,
+                    attr.span(),
                     "`rustc_dump_vtable` only applies to impl, or type alias of dyn type",
                 );
                 continue;
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 1a0b0edb257..99262f9871e 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1165,18 +1165,6 @@ pub(crate) struct InherentTyOutside {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis_coerce_unsized_may, code = E0378)]
-pub(crate) struct DispatchFromDynCoercion<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub trait_name: &'a str,
-    #[note(hir_analysis_coercion_between_struct_same_note)]
-    pub note: bool,
-    pub source_path: String,
-    pub target_path: String,
-}
-
-#[derive(Diagnostic)]
 #[diag(hir_analysis_dispatch_from_dyn_repr, code = E0378)]
 pub(crate) struct DispatchFromDynRepr {
     #[primary_span]
@@ -1293,41 +1281,40 @@ pub(crate) struct DispatchFromDynZST<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis_coerce_unsized_may, code = E0378)]
-pub(crate) struct DispatchFromDynSingle<'a> {
+#[diag(hir_analysis_coerce_zero, code = E0374)]
+pub(crate) struct CoerceNoField {
     #[primary_span]
     pub span: Span,
-    pub trait_name: &'a str,
+    pub trait_name: &'static str,
     #[note(hir_analysis_coercion_between_struct_single_note)]
     pub note: bool,
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis_dispatch_from_dyn_multi, code = E0378)]
-#[note]
-pub(crate) struct DispatchFromDynMulti {
+#[diag(hir_analysis_coerce_multi, code = E0375)]
+pub(crate) struct CoerceMulti {
+    pub trait_name: &'static str,
     #[primary_span]
     pub span: Span,
-    #[note(hir_analysis_coercions_note)]
-    pub coercions_note: bool,
     pub number: usize,
-    pub coercions: String,
+    #[note]
+    pub fields: MultiSpan,
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis_coerce_unsized_may, code = E0376)]
-pub(crate) struct DispatchFromDynStruct<'a> {
+#[diag(hir_analysis_coerce_unsized_may, code = E0377)]
+pub(crate) struct CoerceUnsizedNonStruct {
     #[primary_span]
     pub span: Span,
-    pub trait_name: &'a str,
+    pub trait_name: &'static str,
 }
 
 #[derive(Diagnostic)]
 #[diag(hir_analysis_coerce_unsized_may, code = E0377)]
-pub(crate) struct DispatchFromDynSame<'a> {
+pub(crate) struct CoerceSameStruct {
     #[primary_span]
     pub span: Span,
-    pub trait_name: &'a str,
+    pub trait_name: &'static str,
     #[note(hir_analysis_coercion_between_struct_same_note)]
     pub note: bool,
     pub source_path: String,
@@ -1335,34 +1322,15 @@ pub(crate) struct DispatchFromDynSame<'a> {
 }
 
 #[derive(Diagnostic)]
-#[diag(hir_analysis_coerce_unsized_may, code = E0374)]
-pub(crate) struct CoerceUnsizedOneField<'a> {
+#[diag(hir_analysis_coerce_unsized_field_validity)]
+pub(crate) struct CoerceFieldValidity<'tcx> {
     #[primary_span]
     pub span: Span,
-    pub trait_name: &'a str,
-    #[note(hir_analysis_coercion_between_struct_single_note)]
-    pub note: bool,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis_coerce_unsized_multi, code = E0375)]
-#[note]
-pub(crate) struct CoerceUnsizedMulti {
-    #[primary_span]
+    pub ty: Ty<'tcx>,
+    pub trait_name: &'static str,
     #[label]
-    pub span: Span,
-    #[note(hir_analysis_coercions_note)]
-    pub coercions_note: bool,
-    pub number: usize,
-    pub coercions: String,
-}
-
-#[derive(Diagnostic)]
-#[diag(hir_analysis_coerce_unsized_may, code = E0378)]
-pub(crate) struct CoerceUnsizedMay<'a> {
-    #[primary_span]
-    pub span: Span,
-    pub trait_name: &'a str,
+    pub field_span: Span,
+    pub field_ty: Ty<'tcx>,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_hir_pretty/Cargo.toml b/compiler/rustc_hir_pretty/Cargo.toml
index f5d7dbd3f96..86989d1e55b 100644
--- a/compiler/rustc_hir_pretty/Cargo.toml
+++ b/compiler/rustc_hir_pretty/Cargo.toml
@@ -8,6 +8,7 @@ edition = "2024"
 rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_pretty = { path = "../rustc_ast_pretty" }
+rustc_attr_parsing = { path = "../rustc_attr_parsing" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_span = { path = "../rustc_span" }
 # tidy-alphabetical-end
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 167bed5f650..5c7426d76b3 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -11,11 +11,12 @@ use std::vec;
 
 use rustc_abi::ExternAbi;
 use rustc_ast::util::parser::{self, AssocOp, ExprPrecedence, Fixity};
-use rustc_ast::{DUMMY_NODE_ID, DelimArgs};
+use rustc_ast::{AttrStyle, DUMMY_NODE_ID, DelimArgs};
 use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent};
 use rustc_ast_pretty::pp::{self, Breaks};
 use rustc_ast_pretty::pprust::state::MacHeader;
 use rustc_ast_pretty::pprust::{Comments, PrintState};
+use rustc_attr_parsing::{AttributeKind, PrintAttribute};
 use rustc_hir::{
     BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind,
     HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term,
@@ -80,65 +81,48 @@ impl<'a> State<'a> {
         (self.attrs)(id)
     }
 
-    fn print_inner_attributes(&mut self, attrs: &[hir::Attribute]) -> bool {
-        self.print_either_attributes(attrs, ast::AttrStyle::Inner, false, true)
+    fn print_attrs_as_inner(&mut self, attrs: &[hir::Attribute]) {
+        self.print_either_attributes(attrs, ast::AttrStyle::Inner)
     }
 
-    fn print_outer_attributes(&mut self, attrs: &[hir::Attribute]) -> bool {
-        self.print_either_attributes(attrs, ast::AttrStyle::Outer, false, true)
+    fn print_attrs_as_outer(&mut self, attrs: &[hir::Attribute]) {
+        self.print_either_attributes(attrs, ast::AttrStyle::Outer)
     }
 
-    fn print_either_attributes(
-        &mut self,
-        attrs: &[hir::Attribute],
-        kind: ast::AttrStyle,
-        is_inline: bool,
-        trailing_hardbreak: bool,
-    ) -> bool {
-        let mut printed = false;
-        for attr in attrs {
-            if attr.style == kind {
-                self.print_attribute_inline(attr, is_inline);
-                if is_inline {
-                    self.nbsp();
-                }
-                printed = true;
-            }
+    fn print_either_attributes(&mut self, attrs: &[hir::Attribute], style: ast::AttrStyle) {
+        if attrs.is_empty() {
+            return;
         }
-        if printed && trailing_hardbreak && !is_inline {
-            self.hardbreak_if_not_bol();
+
+        for attr in attrs {
+            self.print_attribute_inline(attr, style);
         }
-        printed
+        self.hardbreak_if_not_bol();
     }
 
-    fn print_attribute_inline(&mut self, attr: &hir::Attribute, is_inline: bool) {
-        if !is_inline {
-            self.hardbreak_if_not_bol();
-        }
-        self.maybe_print_comment(attr.span.lo());
-        match &attr.kind {
-            hir::AttrKind::Normal(normal) => {
-                match attr.style {
+    fn print_attribute_inline(&mut self, attr: &hir::Attribute, style: AttrStyle) {
+        match &attr {
+            hir::Attribute::Unparsed(unparsed) => {
+                self.maybe_print_comment(unparsed.span.lo());
+                match style {
                     ast::AttrStyle::Inner => self.word("#!["),
                     ast::AttrStyle::Outer => self.word("#["),
                 }
-                if normal.unsafety == hir::Safety::Unsafe {
-                    self.word("unsafe(");
-                }
-                self.print_attr_item(&normal, attr.span);
-                if normal.unsafety == hir::Safety::Unsafe {
-                    self.word(")");
-                }
+                self.print_attr_item(&unparsed, unparsed.span);
                 self.word("]");
             }
-            hir::AttrKind::DocComment(comment_kind, data) => {
+            hir::Attribute::Parsed(AttributeKind::DocComment { style, kind, comment, .. }) => {
                 self.word(rustc_ast_pretty::pprust::state::doc_comment_to_string(
-                    *comment_kind,
-                    attr.style,
-                    *data,
+                    *kind, *style, *comment,
                 ));
                 self.hardbreak()
             }
+            hir::Attribute::Parsed(pa) => {
+                self.word("#[attr=\"");
+                pa.print_attribute(self);
+                self.word("\")]");
+                self.hardbreak()
+            }
         }
     }
 
@@ -162,7 +146,7 @@ impl<'a> State<'a> {
                     false,
                     None,
                     *delim,
-                    tokens,
+                    &tokens,
                     true,
                     span,
                 ),
@@ -307,7 +291,7 @@ where
 }
 
 pub fn attribute_to_string(ann: &dyn PpAnn, attr: &hir::Attribute) -> String {
-    to_string(ann, |s| s.print_attribute_inline(attr, false))
+    to_string(ann, |s| s.print_attribute_inline(attr, AttrStyle::Outer))
 }
 
 pub fn ty_to_string(ann: &dyn PpAnn, ty: &hir::Ty<'_>) -> String {
@@ -370,7 +354,7 @@ impl<'a> State<'a> {
     }
 
     fn print_mod(&mut self, _mod: &hir::Mod<'_>, attrs: &[hir::Attribute]) {
-        self.print_inner_attributes(attrs);
+        self.print_attrs_as_inner(attrs);
         for &item_id in _mod.item_ids {
             self.ann.nested(self, Nested::Item(item_id));
         }
@@ -487,7 +471,7 @@ impl<'a> State<'a> {
     fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) {
         self.hardbreak_if_not_bol();
         self.maybe_print_comment(item.span.lo());
-        self.print_outer_attributes(self.attrs(item.hir_id()));
+        self.print_attrs_as_outer(self.attrs(item.hir_id()));
         match item.kind {
             hir::ForeignItemKind::Fn(sig, arg_names, generics) => {
                 self.head("");
@@ -591,7 +575,7 @@ impl<'a> State<'a> {
         self.hardbreak_if_not_bol();
         self.maybe_print_comment(item.span.lo());
         let attrs = self.attrs(item.hir_id());
-        self.print_outer_attributes(attrs);
+        self.print_attrs_as_outer(attrs);
         self.ann.pre(self, AnnNode::Item(item));
         match item.kind {
             hir::ItemKind::ExternCrate(orig_name) => {
@@ -687,7 +671,7 @@ impl<'a> State<'a> {
                 self.head("extern");
                 self.word_nbsp(abi.to_string());
                 self.bopen();
-                self.print_inner_attributes(self.attrs(item.hir_id()));
+                self.print_attrs_as_inner(self.attrs(item.hir_id()));
                 for item in items {
                     self.ann.nested(self, Nested::ForeignItem(item.id));
                 }
@@ -755,7 +739,7 @@ impl<'a> State<'a> {
 
                 self.space();
                 self.bopen();
-                self.print_inner_attributes(attrs);
+                self.print_attrs_as_inner(attrs);
                 for impl_item in items {
                     self.ann.nested(self, Nested::ImplItem(impl_item.id));
                 }
@@ -847,7 +831,7 @@ impl<'a> State<'a> {
         for v in variants {
             self.space_if_not_bol();
             self.maybe_print_comment(v.span.lo());
-            self.print_outer_attributes(self.attrs(v.hir_id));
+            self.print_attrs_as_outer(self.attrs(v.hir_id));
             self.ibox(INDENT_UNIT);
             self.print_variant(v);
             self.word(",");
@@ -880,7 +864,7 @@ impl<'a> State<'a> {
                     self.popen();
                     self.commasep(Inconsistent, struct_def.fields(), |s, field| {
                         s.maybe_print_comment(field.span.lo());
-                        s.print_outer_attributes(s.attrs(field.hir_id));
+                        s.print_attrs_as_outer(s.attrs(field.hir_id));
                         s.print_type(field.ty);
                     });
                     self.pclose();
@@ -907,7 +891,7 @@ impl<'a> State<'a> {
         for field in fields {
             self.hardbreak_if_not_bol();
             self.maybe_print_comment(field.span.lo());
-            self.print_outer_attributes(self.attrs(field.hir_id));
+            self.print_attrs_as_outer(self.attrs(field.hir_id));
             self.print_ident(field.ident);
             self.word_nbsp(":");
             self.print_type(field.ty);
@@ -943,7 +927,7 @@ impl<'a> State<'a> {
         self.ann.pre(self, AnnNode::SubItem(ti.hir_id()));
         self.hardbreak_if_not_bol();
         self.maybe_print_comment(ti.span.lo());
-        self.print_outer_attributes(self.attrs(ti.hir_id()));
+        self.print_attrs_as_outer(self.attrs(ti.hir_id()));
         match ti.kind {
             hir::TraitItemKind::Const(ty, default) => {
                 self.print_associated_const(ti.ident, ti.generics, ty, default);
@@ -971,7 +955,7 @@ impl<'a> State<'a> {
         self.ann.pre(self, AnnNode::SubItem(ii.hir_id()));
         self.hardbreak_if_not_bol();
         self.maybe_print_comment(ii.span.lo());
-        self.print_outer_attributes(self.attrs(ii.hir_id()));
+        self.print_attrs_as_outer(self.attrs(ii.hir_id()));
 
         match ii.kind {
             hir::ImplItemKind::Const(ty, expr) => {
@@ -1074,7 +1058,7 @@ impl<'a> State<'a> {
         self.ann.pre(self, AnnNode::Block(blk));
         self.bopen();
 
-        self.print_inner_attributes(attrs);
+        self.print_attrs_as_inner(attrs);
 
         for st in blk.stmts {
             self.print_stmt(st);
@@ -1264,7 +1248,7 @@ impl<'a> State<'a> {
             self.space();
         }
         self.cbox(INDENT_UNIT);
-        self.print_outer_attributes(self.attrs(field.hir_id));
+        self.print_attrs_as_outer(self.attrs(field.hir_id));
         if !field.is_shorthand {
             self.print_ident(field.ident);
             self.word_space(":");
@@ -1461,7 +1445,7 @@ impl<'a> State<'a> {
 
     fn print_expr(&mut self, expr: &hir::Expr<'_>) {
         self.maybe_print_comment(expr.span.lo());
-        self.print_outer_attributes(self.attrs(expr.hir_id));
+        self.print_attrs_as_outer(self.attrs(expr.hir_id));
         self.ibox(INDENT_UNIT);
         self.ann.pre(self, AnnNode::Expr(expr));
         match expr.kind {
@@ -1677,8 +1661,8 @@ impl<'a> State<'a> {
             }
             hir::ExprKind::UnsafeBinderCast(kind, expr, ty) => {
                 match kind {
-                    hir::UnsafeBinderCastKind::Wrap => self.word("wrap_binder!("),
-                    hir::UnsafeBinderCastKind::Unwrap => self.word("unwrap_binder!("),
+                    ast::UnsafeBinderCastKind::Wrap => self.word("wrap_binder!("),
+                    ast::UnsafeBinderCastKind::Unwrap => self.word("unwrap_binder!("),
                 }
                 self.print_expr(expr);
                 if let Some(ty) = ty {
@@ -2073,7 +2057,7 @@ impl<'a> State<'a> {
             self.space();
         }
         self.cbox(INDENT_UNIT);
-        self.print_outer_attributes(self.attrs(field.hir_id));
+        self.print_attrs_as_outer(self.attrs(field.hir_id));
         if !field.is_shorthand {
             self.print_ident(field.ident);
             self.word_nbsp(":");
@@ -2083,7 +2067,7 @@ impl<'a> State<'a> {
     }
 
     fn print_param(&mut self, arg: &hir::Param<'_>) {
-        self.print_outer_attributes(self.attrs(arg.hir_id));
+        self.print_attrs_as_outer(self.attrs(arg.hir_id));
         self.print_pat(arg.pat);
     }
 
@@ -2118,7 +2102,7 @@ impl<'a> State<'a> {
         self.cbox(INDENT_UNIT);
         self.ann.pre(self, AnnNode::Arm(arm));
         self.ibox(0);
-        self.print_outer_attributes(self.attrs(arm.hir_id));
+        self.print_attrs_as_outer(self.attrs(arm.hir_id));
         self.print_pat(arm.pat);
         self.space();
         if let Some(ref g) = arm.guard {
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 0c71ef4655c..4815627a0ce 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -1656,13 +1656,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn check_expr_unsafe_binder_cast(
         &self,
         span: Span,
-        kind: hir::UnsafeBinderCastKind,
+        kind: ast::UnsafeBinderCastKind,
         inner_expr: &'tcx hir::Expr<'tcx>,
         hir_ty: Option<&'tcx hir::Ty<'tcx>>,
         expected: Expectation<'tcx>,
     ) -> Ty<'tcx> {
         match kind {
-            hir::UnsafeBinderCastKind::Wrap => {
+            ast::UnsafeBinderCastKind::Wrap => {
                 let ascribed_ty =
                     hir_ty.map(|hir_ty| self.lower_ty_saving_user_provided_ty(hir_ty));
                 let expected_ty = expected.only_has_type(self);
@@ -1706,7 +1706,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 binder_ty
             }
-            hir::UnsafeBinderCastKind::Unwrap => {
+            ast::UnsafeBinderCastKind::Unwrap => {
                 let ascribed_ty =
                     hir_ty.map(|hir_ty| self.lower_ty_saving_user_provided_ty(hir_ty));
                 let hint_ty = ascribed_ty.unwrap_or_else(|| self.next_ty_var(inner_expr.span));
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index edd740d8d8f..63c1c060827 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -110,7 +110,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     self.tcx.erase_regions(ty)
                 }
             };
-            InlineAsmCtxt::new(self.tcx, enclosing_id, expr_ty).check_asm(asm);
+            InlineAsmCtxt::new(self.tcx, enclosing_id, self.typing_env(self.param_env), expr_ty)
+                .check_asm(asm);
         }
     }
 
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 8438a92219e..18218a7a0a6 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -9,7 +9,7 @@ use std::path::PathBuf;
 
 use hir::Expr;
 use rustc_ast::ast::Mutability;
-use rustc_attr_parsing::parse_confusables;
+use rustc_attr_parsing::{AttributeKind, find_attr};
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::unord::UnordSet;
@@ -1884,9 +1884,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 for inherent_method in
                     self.tcx.associated_items(inherent_impl_did).in_definition_order()
                 {
-                    if let Some(attr) =
-                        self.tcx.get_attr(inherent_method.def_id, sym::rustc_confusables)
-                        && let Some(candidates) = parse_confusables(attr)
+                    if let Some(candidates) = find_attr!(self.tcx.get_all_attrs(inherent_method.def_id), AttributeKind::Confusables{symbols, ..} => symbols)
                         && candidates.contains(&item_name.name)
                         && let ty::AssocKind::Fn = inherent_method.kind
                     {
diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs
index d4407559202..8f2ca6babea 100644
--- a/compiler/rustc_incremental/src/assert_dep_graph.rs
+++ b/compiler/rustc_incremental/src/assert_dep_graph.rs
@@ -137,13 +137,13 @@ impl<'tcx> IfThisChanged<'tcx> {
                         match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) {
                             Ok(n) => n,
                             Err(()) => self.tcx.dcx().emit_fatal(errors::UnrecognizedDepNode {
-                                span: attr.span,
+                                span: attr.span(),
                                 name: n,
                             }),
                         }
                     }
                 };
-                self.if_this_changed.push((attr.span, def_id.to_def_id(), dep_node));
+                self.if_this_changed.push((attr.span(), def_id.to_def_id(), dep_node));
             } else if attr.has_name(sym::rustc_then_this_would_need) {
                 let dep_node_interned = self.argument(attr);
                 let dep_node = match dep_node_interned {
@@ -151,17 +151,17 @@ impl<'tcx> IfThisChanged<'tcx> {
                         match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) {
                             Ok(n) => n,
                             Err(()) => self.tcx.dcx().emit_fatal(errors::UnrecognizedDepNode {
-                                span: attr.span,
+                                span: attr.span(),
                                 name: n,
                             }),
                         }
                     }
                     None => {
-                        self.tcx.dcx().emit_fatal(errors::MissingDepNode { span: attr.span });
+                        self.tcx.dcx().emit_fatal(errors::MissingDepNode { span: attr.span() });
                     }
                 };
                 self.then_this_would_need.push((
-                    attr.span,
+                    attr.span(),
                     dep_node_interned.unwrap(),
                     hir_id,
                     dep_node,
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index 56858679af6..d40a0d514f6 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -199,7 +199,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
         let loaded_from_disk = self.loaded_from_disk(attr);
         for e in except.items().into_sorted_stable_ord() {
             if !auto.remove(e) {
-                self.tcx.dcx().emit_fatal(errors::AssertionAuto { span: attr.span, name, e });
+                self.tcx.dcx().emit_fatal(errors::AssertionAuto { span: attr.span(), name, e });
             }
         }
         Assertion { clean: auto, dirty: except, loaded_from_disk }
@@ -282,7 +282,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
                     HirItem::Impl { .. } => ("ItemKind::Impl", LABELS_IMPL),
 
                     _ => self.tcx.dcx().emit_fatal(errors::UndefinedCleanDirtyItem {
-                        span: attr.span,
+                        span: attr.span(),
                         kind: format!("{:?}", item.kind),
                     }),
                 }
@@ -298,7 +298,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
                 ImplItemKind::Type(..) => ("NodeImplType", LABELS_CONST_IN_IMPL),
             },
             _ => self.tcx.dcx().emit_fatal(errors::UndefinedCleanDirty {
-                span: attr.span,
+                span: attr.span(),
                 kind: format!("{node:?}"),
             }),
         };
@@ -375,7 +375,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
             let Some(assertion) = self.assertion_maybe(item_id, attr) else {
                 continue;
             };
-            self.checked_attrs.insert(attr.id);
+            self.checked_attrs.insert(attr.id());
             for label in assertion.clean.items().into_sorted_stable_ord() {
                 let dep_node = DepNode::from_label_string(self.tcx, label, def_path_hash).unwrap();
                 self.assert_clean(item_span, dep_node);
@@ -405,12 +405,13 @@ fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool {
             debug!("check_config: searching for cfg {:?}", value);
             cfg = Some(config.contains(&(value, None)));
         } else if !(item.has_name(EXCEPT) || item.has_name(LOADED_FROM_DISK)) {
-            tcx.dcx().emit_err(errors::UnknownItem { span: attr.span, name: item.name_or_empty() });
+            tcx.dcx()
+                .emit_err(errors::UnknownItem { span: attr.span(), name: item.name_or_empty() });
         }
     }
 
     match cfg {
-        None => tcx.dcx().emit_fatal(errors::NoCfg { span: attr.span }),
+        None => tcx.dcx().emit_fatal(errors::NoCfg { span: attr.span() }),
         Some(c) => c,
     }
 }
@@ -444,9 +445,9 @@ impl<'tcx> FindAllAttrs<'tcx> {
 
     fn report_unchecked_attrs(&self, mut checked_attrs: FxHashSet<ast::AttrId>) {
         for attr in &self.found_attrs {
-            if !checked_attrs.contains(&attr.id) {
-                self.tcx.dcx().emit_err(errors::UncheckedClean { span: attr.span });
-                checked_attrs.insert(attr.id);
+            if !checked_attrs.contains(&attr.id()) {
+                self.tcx.dcx().emit_err(errors::UncheckedClean { span: attr.span() });
+                checked_attrs.insert(attr.id());
             }
         }
     }
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 5e44583b297..f7be37dc4a2 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1011,7 +1011,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
                         cx.emit_span_lint(
                             NO_MANGLE_GENERIC_ITEMS,
                             span,
-                            BuiltinNoMangleGeneric { suggestion: no_mangle_attr.span },
+                            BuiltinNoMangleGeneric { suggestion: no_mangle_attr.span() },
                         );
                         break;
                     }
@@ -1226,7 +1226,7 @@ impl<'tcx> LateLintPass<'tcx> for UngatedAsyncFnTrackCaller {
         {
             cx.emit_span_lint(
                 UNGATED_ASYNC_FN_TRACK_CALLER,
-                attr.span,
+                attr.span(),
                 BuiltinUngatedAsyncFnTrackCaller { label: span, session: &cx.tcx.sess },
             );
         }
diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs
index ef79f1301e5..9ca148e1f25 100644
--- a/compiler/rustc_lint/src/expect.rs
+++ b/compiler/rustc_lint/src/expect.rs
@@ -38,7 +38,8 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
             }
             LintExpectationId::Stable { hir_id, attr_index, lint_index: Some(lint_index) } => {
                 // We are an `eval_always` query, so looking at the attribute's `AttrId` is ok.
-                let attr_id = tcx.hir().attrs(hir_id)[attr_index as usize].id;
+                let attr_id = tcx.hir().attrs(hir_id)[attr_index as usize].id();
+
                 (attr_id, lint_index)
             }
             _ => panic!("fulfilled expectations must have a lint index"),
diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs
index 49c34d0edcc..6175415c31f 100644
--- a/compiler/rustc_lint/src/foreign_modules.rs
+++ b/compiler/rustc_lint/src/foreign_modules.rs
@@ -182,7 +182,7 @@ fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: hir::OwnerId) -> SymbolName {
             // information, we could have codegen_fn_attrs also give span information back for
             // where the attribute was defined. However, until this is found to be a
             // bottleneck, this does just fine.
-            (overridden_link_name, tcx.get_attr(fi, sym::link_name).unwrap().span)
+            (overridden_link_name, tcx.get_attr(fi, sym::link_name).unwrap().span())
         })
     {
         SymbolName::Link(overridden_link_name, overridden_link_name_span)
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index bc35e2f0538..49f9ad39780 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -1,13 +1,14 @@
 use rustc_abi::ExternAbi;
+use rustc_attr_parsing::{AttributeKind, AttributeParser, ReprAttr};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{AttrArgs, AttrItem, AttrKind, GenericParamKind, PatExprKind, PatKind};
+use rustc_hir::{AttrArgs, AttrItem, Attribute, GenericParamKind, PatExprKind, PatKind};
 use rustc_middle::ty;
 use rustc_session::config::CrateType;
 use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{BytePos, Ident, Span, sym};
-use {rustc_ast as ast, rustc_attr_parsing as attr, rustc_hir as hir};
+use {rustc_ast as ast, rustc_hir as hir};
 
 use crate::lints::{
     NonCamelCaseType, NonCamelCaseTypeSub, NonSnakeCaseDiag, NonSnakeCaseDiagSub,
@@ -161,10 +162,10 @@ impl NonCamelCaseTypes {
 
 impl EarlyLintPass for NonCamelCaseTypes {
     fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
-        let has_repr_c = it
-            .attrs
-            .iter()
-            .any(|attr| attr::find_repr_attrs(cx.sess(), attr).contains(&attr::ReprC));
+        let has_repr_c = matches!(
+            AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, true),
+            Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(r, _)| r == &ReprAttr::ReprC)
+        );
 
         if has_repr_c {
             return;
@@ -343,7 +344,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
         } else {
             ast::attr::find_by_name(cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name)
                 .and_then(|attr| {
-                    if let AttrKind::Normal(n) = &attr.kind
+                    if let Attribute::Unparsed(n) = attr
                         && let AttrItem { args: AttrArgs::Eq { eq_span: _, expr: lit }, .. } =
                             n.as_ref()
                         && let ast::LitKind::Str(name, ..) = lit.kind
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index ff3dae08ffc..e564235c41a 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -251,19 +251,23 @@ impl Level {
 
     /// Converts an `Attribute` to a level.
     pub fn from_attr(attr: &impl AttributeExt) -> Option<Self> {
-        Self::from_symbol(attr.name_or_empty(), Some(attr.id()))
+        Self::from_symbol(attr.name_or_empty(), || Some(attr.id()))
     }
 
     /// Converts a `Symbol` to a level.
-    pub fn from_symbol(s: Symbol, id: Option<AttrId>) -> Option<Self> {
-        match (s, id) {
-            (sym::allow, _) => Some(Level::Allow),
-            (sym::expect, Some(attr_id)) => {
-                Some(Level::Expect(LintExpectationId::Unstable { attr_id, lint_index: None }))
+    pub fn from_symbol(s: Symbol, id: impl FnOnce() -> Option<AttrId>) -> Option<Self> {
+        match s {
+            sym::allow => Some(Level::Allow),
+            sym::expect => {
+                if let Some(attr_id) = id() {
+                    Some(Level::Expect(LintExpectationId::Unstable { attr_id, lint_index: None }))
+                } else {
+                    None
+                }
             }
-            (sym::warn, _) => Some(Level::Warn),
-            (sym::deny, _) => Some(Level::Deny),
-            (sym::forbid, _) => Some(Level::Forbid),
+            sym::warn => Some(Level::Warn),
+            sym::deny => Some(Level::Deny),
+            sym::forbid => Some(Level::Forbid),
             _ => None,
         }
     }
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index 0df674eb4c9..34fc0f00320 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -17,6 +17,7 @@ mod diagnostics;
 mod extension;
 mod hash_stable;
 mod lift;
+mod print_attribute;
 mod query;
 mod serialize;
 mod symbols;
@@ -175,3 +176,11 @@ decl_derive! {
     /// The error type is `u32`.
     try_from::try_from_u32
 }
+decl_derive! {
+    [PrintAttribute] =>
+    /// Derives `PrintAttribute` for `AttributeKind`.
+    /// This macro is pretty specific to `rustc_attr_data_structures` and likely not that useful in
+    /// other places. It's deriving something close to `Debug` without printing some extraenous
+    /// things like spans.
+    print_attribute::print_attribute
+}
diff --git a/compiler/rustc_macros/src/print_attribute.rs b/compiler/rustc_macros/src/print_attribute.rs
new file mode 100644
index 00000000000..3c6e30b851b
--- /dev/null
+++ b/compiler/rustc_macros/src/print_attribute.rs
@@ -0,0 +1,145 @@
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote, quote_spanned};
+use syn::spanned::Spanned;
+use syn::{Data, Fields, Ident};
+use synstructure::Structure;
+
+fn print_fields(name: &Ident, fields: &Fields) -> (TokenStream, TokenStream, TokenStream) {
+    let string_name = name.to_string();
+    let mut disps = vec![quote! {let mut __printed_anything = false;}];
+
+    match fields {
+        Fields::Named(fields_named) => {
+            let mut field_names = Vec::new();
+
+            for field in &fields_named.named {
+                let name = field.ident.as_ref().unwrap();
+                let string_name = name.to_string();
+                disps.push(quote! {
+                    if __printed_anything && #name.print_something() {
+                        __p.word_space(",");
+                        __printed_anything = true;
+                    }
+                    __p.word(#string_name);
+                    __p.word_space(":");
+                    #name.print_attribute(__p);
+                });
+                field_names.push(name);
+            }
+
+            (
+                quote! { {#(#field_names),*} },
+                quote! {
+                    __p.word(#string_name);
+                    if true #(&& !#field_names.print_something())* {
+                        return;
+                    }
+
+                    __p.word("{");
+                    #(#disps)*
+                    __p.word("}");
+                },
+                quote! { true },
+            )
+        }
+        Fields::Unnamed(fields_unnamed) => {
+            let mut field_names = Vec::new();
+
+            for idx in 0..fields_unnamed.unnamed.len() {
+                let name = format_ident!("f{idx}");
+                disps.push(quote! {
+                    if __printed_anything && #name.print_something() {
+                        __p.word_space(",");
+                        __printed_anything = true;
+                    }
+                    #name.print_attribute(__p);
+                });
+                field_names.push(name);
+            }
+
+            (
+                quote! { (#(#field_names),*) },
+                quote! {
+                    __p.word(#string_name);
+
+                    if true #(&& !#field_names.print_something())* {
+                        return;
+                    }
+
+                    __p.word("(");
+                    #(#disps)*
+                    __p.word(")");
+                },
+                quote! { true },
+            )
+        }
+        Fields::Unit => (quote! {}, quote! { __p.word(#string_name) }, quote! { true }),
+    }
+}
+
+pub(crate) fn print_attribute(input: Structure<'_>) -> TokenStream {
+    let span_error = |span, message: &str| {
+        quote_spanned! { span => const _: () = ::core::compile_error!(#message); }
+    };
+
+    // Must be applied to an enum type.
+    let (code, printed) = match &input.ast().data {
+        Data::Enum(e) => {
+            let (arms, printed) = e
+                .variants
+                .iter()
+                .map(|x| {
+                    let ident = &x.ident;
+                    let (pat, code, printed) = print_fields(ident, &x.fields);
+
+                    (
+                        quote! {
+                            Self::#ident #pat => {#code}
+                        },
+                        quote! {
+                            Self::#ident #pat => {#printed}
+                        },
+                    )
+                })
+                .unzip::<_, _, Vec<_>, Vec<_>>();
+
+            (
+                quote! {
+                    match self {
+                        #(#arms)*
+                    }
+                },
+                quote! {
+                    match self {
+                        #(#printed)*
+                    }
+                },
+            )
+        }
+        Data::Struct(s) => {
+            let (pat, code, printed) = print_fields(&input.ast().ident, &s.fields);
+            (
+                quote! {
+                    let Self #pat = self;
+                    #code
+                },
+                quote! {
+                    let Self #pat = self;
+                    #printed
+                },
+            )
+        }
+        Data::Union(u) => {
+            return span_error(u.union_token.span(), "can't derive PrintAttribute on unions");
+        }
+    };
+
+    #[allow(keyword_idents_2024)]
+    input.gen_impl(quote! {
+        #[allow(unused)]
+        gen impl PrintAttribute for @Self {
+            fn print_something(&self) -> bool { #printed }
+            fn print_attribute(&self, __p: &mut rustc_ast_pretty::pp::Printer) { #code }
+        }
+    })
+}
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index 2a1e4b261e7..e2d043f47c0 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -450,7 +450,7 @@ impl<'tcx> Collector<'tcx> {
                 (name, kind) = (wasm_import_module, Some(NativeLibKind::WasmImportModule));
             }
             let Some((name, name_span)) = name else {
-                sess.dcx().emit_err(errors::LinkRequiresName { span: m.span });
+                sess.dcx().emit_err(errors::LinkRequiresName { span: m.span() });
                 continue;
             };
 
@@ -485,7 +485,7 @@ impl<'tcx> Collector<'tcx> {
                             let link_ordinal_attr =
                                 self.tcx.get_attr(child_item, sym::link_ordinal).unwrap();
                             sess.dcx().emit_err(errors::LinkOrdinalRawDylib {
-                                span: link_ordinal_attr.span,
+                                span: link_ordinal_attr.span(),
                             });
                         }
                     }
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 591c8ed50d5..16149198303 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1071,7 +1071,6 @@ impl<'a> CrateMetadataRef<'a> {
         let attrs: Vec<_> = self.get_item_attrs(id, sess).collect();
         SyntaxExtension::new(
             sess,
-            tcx.features(),
             kind,
             self.get_span(id, sess),
             helper_attrs,
diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs
index ed7c98ee0e0..9ce5373b031 100644
--- a/compiler/rustc_middle/src/traits/specialization_graph.rs
+++ b/compiler/rustc_middle/src/traits/specialization_graph.rs
@@ -75,7 +75,7 @@ impl OverlapMode {
                         tcx.hir().attrs(tcx.local_def_id_to_hir_id(local_def_id))
                     })
                     .find(|attr| attr.has_name(sym::rustc_strict_coherence))
-                    .map(|attr| attr.span);
+                    .map(|attr| attr.span());
                 tcx.dcx().emit_err(StrictCoherenceNeedsNegativeCoherence {
                     span: tcx.def_span(trait_id),
                     attr_span,
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 238ba127e2e..62a384af12f 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -1542,7 +1542,7 @@ impl<'tcx> TyCtxt<'tcx> {
                 Bound::Included(a.get())
             } else {
                 self.dcx().span_delayed_bug(
-                    attr.span,
+                    attr.span(),
                     "invalid rustc_layout_scalar_valid_range attribute",
                 );
                 Bound::Unbounded
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index dbbbdc606bb..9208c2a65a1 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -27,6 +27,7 @@ pub use intrinsic::IntrinsicDef;
 use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx};
 use rustc_ast::expand::StrippedCfgItem;
 use rustc_ast::node_id::NodeMap;
+use rustc_attr_parsing::AttributeKind;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::intern::Interned;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -1495,9 +1496,10 @@ impl<'tcx> TyCtxt<'tcx> {
             field_shuffle_seed ^= user_seed;
         }
 
-        for attr in self.get_attrs(did, sym::repr) {
-            for r in attr::parse_repr_attr(self.sess, attr) {
-                flags.insert(match r {
+        if let Some(reprs) = attr::find_attr!(self.get_all_attrs(did), AttributeKind::Repr(r) => r)
+        {
+            for (r, _) in reprs {
+                flags.insert(match *r {
                     attr::ReprRust => ReprFlags::empty(),
                     attr::ReprC => ReprFlags::IS_C,
                     attr::ReprPacked(pack) => {
@@ -1535,6 +1537,10 @@ impl<'tcx> TyCtxt<'tcx> {
                         max_align = max_align.max(Some(align));
                         ReprFlags::empty()
                     }
+                    attr::ReprEmpty => {
+                        /* skip these, they're just for diagnostics */
+                        ReprFlags::empty()
+                    }
                 });
             }
         }
@@ -1757,13 +1763,21 @@ impl<'tcx> TyCtxt<'tcx> {
         did: impl Into<DefId>,
         attr: Symbol,
     ) -> impl Iterator<Item = &'tcx hir::Attribute> {
+        self.get_all_attrs(did).filter(move |a: &&hir::Attribute| a.has_name(attr))
+    }
+
+    /// Gets all attributes.
+    ///
+    /// To see if an item has a specific attribute, you should use [`rustc_attr_parsing::find_attr!`] so you can use matching.
+    pub fn get_all_attrs(
+        self,
+        did: impl Into<DefId>,
+    ) -> impl Iterator<Item = &'tcx hir::Attribute> {
         let did: DefId = did.into();
-        let filter_fn = move |a: &&hir::Attribute| a.has_name(attr);
         if let Some(did) = did.as_local() {
-            self.hir().attrs(self.local_def_id_to_hir_id(did)).iter().filter(filter_fn)
+            self.hir().attrs(self.local_def_id_to_hir_id(did)).iter()
         } else {
-            debug_assert!(rustc_feature::encode_cross_crate(attr));
-            self.attrs_for_def(did).iter().filter(filter_fn)
+            self.attrs_for_def(did).iter()
         }
     }
 
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 88d57498542..c153f6bb7d7 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -1755,13 +1755,12 @@ pub fn intrinsic_raw(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<ty::Intrinsi
         && (matches!(tcx.fn_sig(def_id).skip_binder().abi(), ExternAbi::RustIntrinsic)
             || tcx.has_attr(def_id, sym::rustc_intrinsic))
     {
-        let must_be_overridden = tcx.has_attr(def_id, sym::rustc_intrinsic_must_be_overridden)
-            || match tcx.hir_node_by_def_id(def_id) {
-                hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { has_body, .. }, .. }) => {
-                    !has_body
-                }
-                _ => true,
-            };
+        let must_be_overridden = match tcx.hir_node_by_def_id(def_id) {
+            hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { has_body, .. }, .. }) => {
+                !has_body
+            }
+            _ => true,
+        };
         Some(ty::IntrinsicDef {
             name: tcx.item_name(def_id.into()),
             must_be_overridden,
diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
index 58461be01f1..ccf76dc7108 100644
--- a/compiler/rustc_mir_transform/src/coverage/query.rs
+++ b/compiler/rustc_mir_transform/src/coverage/query.rs
@@ -65,7 +65,7 @@ fn coverage_attr_on(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
             Some(_) | None => {
                 // Other possibilities should have been rejected by `rustc_parse::validate_attr`.
                 // Use `span_delayed_bug` to avoid an ICE in failing builds (#127880).
-                tcx.dcx().span_delayed_bug(attr.span, "unexpected value of coverage attribute");
+                tcx.dcx().span_delayed_bug(attr.span(), "unexpected value of coverage attribute");
             }
         }
     }
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 978cb7af242..bc43580a7f0 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -311,9 +311,6 @@ passes_duplicate_lang_item_crate_depends =
     .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path}
     .second_definition_path = second definition in `{$crate_name}` loaded from {$path}
 
-passes_empty_confusables =
-    expected at least one confusable name
-
 passes_export_name =
     attribute should be applied to a free function, impl method or static
     .label = not a free function, impl method or static
@@ -365,9 +362,6 @@ passes_incorrect_do_not_recommend_args =
 passes_incorrect_do_not_recommend_location =
     `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
 
-passes_incorrect_meta_item = expected a quoted string literal
-passes_incorrect_meta_item_suggestion = consider surrounding this with quotes
-
 passes_incorrect_target =
     `{$name}` lang item must be applied to a {$kind} with {$at_least ->
         [true] at least {$num}
@@ -641,13 +635,12 @@ passes_repr_align_greater_than_target_max =
 passes_repr_conflicting =
     conflicting representation hints
 
-passes_repr_ident =
-    meta item in `repr` must be an identifier
-
 passes_rustc_allow_const_fn_unstable =
     attribute should be applied to `const fn`
     .label = not a `const fn`
 
+passes_rustc_const_stable_indirect_pairing =
+    `const_stable_indirect` attribute does not make sense on `rustc_const_stable` function, its behavior is already implied
 passes_rustc_dirty_clean =
     attribute requires -Z query-dep-graph to be enabled
 
@@ -774,10 +767,6 @@ passes_unreachable_due_to_uninhabited = unreachable {$descr}
 passes_unrecognized_field =
     unrecognized field name `{$name}`
 
-passes_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`
-
 passes_unstable_attr_for_already_stable_feature =
     can't mark as unstable using an already stable feature
     .label = this feature is already stable
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 9a4db612cfe..9be86812287 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -1,3 +1,4 @@
+// FIXME(jdonszelmann): should become rustc_attr_validation
 //! This module implements some validity checks for attributes.
 //! In particular it verifies that `#[inline]` and `#[repr]` attributes are
 //! attached to items that actually support them and if there are
@@ -7,16 +8,17 @@
 use std::cell::Cell;
 use std::collections::hash_map::Entry;
 
-use rustc_abi::{ExternAbi, Size};
+use rustc_abi::{Align, ExternAbi, Size};
 use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast};
+use rustc_attr_parsing::{AttributeKind, ReprAttr, find_attr};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey};
 use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
 use rustc_hir::def_id::LocalModDefId;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{
-    self as hir, self, AssocItemKind, AttrKind, Attribute, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig,
-    ForeignItem, HirId, Item, ItemKind, MethodKind, Safety, Target, TraitItem,
+    self as hir, self, AssocItemKind, Attribute, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig, ForeignItem,
+    HirId, Item, ItemKind, MethodKind, Safety, Target, TraitItem,
 };
 use rustc_macros::LintDiagnostic;
 use rustc_middle::hir::nested_filter;
@@ -113,190 +115,201 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         let mut seen = FxHashMap::default();
         let attrs = self.tcx.hir().attrs(hir_id);
         for attr in attrs {
-            match attr.path().as_slice() {
-                [sym::diagnostic, sym::do_not_recommend, ..] => {
-                    self.check_do_not_recommend(attr.span, hir_id, target, attr, item)
-                }
-                [sym::diagnostic, sym::on_unimplemented, ..] => {
-                    self.check_diagnostic_on_unimplemented(attr.span, hir_id, target)
-                }
-                [sym::inline, ..] => self.check_inline(hir_id, attr, span, target),
-                [sym::coverage, ..] => self.check_coverage(attr, span, target),
-                [sym::optimize, ..] => self.check_optimize(hir_id, attr, span, target),
-                [sym::no_sanitize, ..] => self.check_no_sanitize(attr, span, target),
-                [sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target, item),
-                [sym::marker, ..] => self.check_marker(hir_id, attr, span, target),
-                [sym::target_feature, ..] => {
-                    self.check_target_feature(hir_id, attr, span, target, attrs)
-                }
-                [sym::thread_local, ..] => self.check_thread_local(attr, span, target),
-                [sym::track_caller, ..] => {
-                    self.check_track_caller(hir_id, attr.span, attrs, span, target)
-                }
-                [sym::doc, ..] => self.check_doc_attrs(
-                    attr,
-                    hir_id,
-                    target,
-                    &mut specified_inline,
-                    &mut doc_aliases,
-                ),
-                [sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target),
-                [sym::export_name, ..] => self.check_export_name(hir_id, attr, span, target),
-                [sym::rustc_layout_scalar_valid_range_start, ..]
-                | [sym::rustc_layout_scalar_valid_range_end, ..] => {
-                    self.check_rustc_layout_scalar_valid_range(attr, span, target)
-                }
-                [sym::allow_internal_unstable, ..] => {
-                    self.check_allow_internal_unstable(hir_id, attr, span, target, attrs)
-                }
-                [sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target),
-                [sym::rustc_allow_const_fn_unstable, ..] => {
-                    self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target)
-                }
-                [sym::rustc_std_internal_symbol, ..] => {
-                    self.check_rustc_std_internal_symbol(attr, span, target)
-                }
-                [sym::naked, ..] => self.check_naked(hir_id, attr, span, target, attrs),
-                [sym::rustc_as_ptr, ..] => {
-                    self.check_applied_to_fn_or_method(hir_id, attr, span, target)
-                }
-                [sym::rustc_never_returns_null_ptr, ..] => {
-                    self.check_applied_to_fn_or_method(hir_id, attr, span, target)
-                }
-                [sym::rustc_legacy_const_generics, ..] => {
-                    self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item)
-                }
-                [sym::rustc_lint_query_instability, ..] => {
-                    self.check_applied_to_fn_or_method(hir_id, attr, span, target)
-                }
-                [sym::rustc_lint_untracked_query_information, ..] => {
-                    self.check_applied_to_fn_or_method(hir_id, attr, span, target)
-                }
-                [sym::rustc_lint_diagnostics, ..] => {
-                    self.check_applied_to_fn_or_method(hir_id, attr, span, target)
-                }
-                [sym::rustc_lint_opt_ty, ..] => self.check_rustc_lint_opt_ty(attr, span, target),
-                [sym::rustc_lint_opt_deny_field_access, ..] => {
-                    self.check_rustc_lint_opt_deny_field_access(attr, span, target)
-                }
-                [sym::rustc_clean, ..]
-                | [sym::rustc_dirty, ..]
-                | [sym::rustc_if_this_changed, ..]
-                | [sym::rustc_then_this_would_need, ..] => self.check_rustc_dirty_clean(attr),
-                [sym::rustc_coinductive, ..]
-                | [sym::rustc_must_implement_one_of, ..]
-                | [sym::rustc_deny_explicit_impl, ..]
-                | [sym::rustc_do_not_implement_via_object, ..]
-                | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target),
-                [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target),
-                [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target),
-                [sym::must_use, ..] => self.check_must_use(hir_id, attr, target),
-                [sym::may_dangle, ..] => self.check_may_dangle(hir_id, attr),
-                [sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target),
-                [sym::rustc_allow_incoherent_impl, ..] => {
-                    self.check_allow_incoherent_impl(attr, span, target)
-                }
-                [sym::rustc_has_incoherent_inherent_impls, ..] => {
-                    self.check_has_incoherent_inherent_impls(attr, span, target)
-                }
-                [sym::ffi_pure, ..] => self.check_ffi_pure(attr.span, attrs, target),
-                [sym::ffi_const, ..] => self.check_ffi_const(attr.span, target),
-                [sym::rustc_const_unstable, ..]
-                | [sym::rustc_const_stable, ..]
-                | [sym::unstable, ..]
-                | [sym::stable, ..]
-                | [sym::rustc_allowed_through_unstable_modules, ..]
-                | [sym::rustc_promotable, ..] => self.check_stability_promotable(attr, target),
-                [sym::link_ordinal, ..] => self.check_link_ordinal(attr, span, target),
-                [sym::rustc_confusables, ..] => self.check_confusables(attr, target),
-                [sym::cold, ..] => self.check_cold(hir_id, attr, span, target),
-                [sym::link, ..] => self.check_link(hir_id, attr, span, target),
-                [sym::link_name, ..] => self.check_link_name(hir_id, attr, span, target),
-                [sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target),
-                [sym::no_mangle, ..] => self.check_no_mangle(hir_id, attr, span, target),
-                [sym::deprecated, ..] => self.check_deprecated(hir_id, attr, span, target),
-                [sym::macro_use, ..] | [sym::macro_escape, ..] => {
-                    self.check_macro_use(hir_id, attr, target)
-                }
-                [sym::path, ..] => self.check_generic_attr(hir_id, attr, target, Target::Mod),
-                [sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target),
-                [sym::ignore, ..] | [sym::should_panic, ..] => {
-                    self.check_generic_attr(hir_id, attr, target, Target::Fn)
-                }
-                [sym::automatically_derived, ..] => {
-                    self.check_generic_attr(hir_id, attr, target, Target::Impl)
-                }
-                [sym::no_implicit_prelude, ..] => {
-                    self.check_generic_attr(hir_id, attr, target, Target::Mod)
-                }
-                [sym::rustc_object_lifetime_default, ..] => self.check_object_lifetime_default(hir_id),
-                [sym::proc_macro, ..] => {
-                    self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike)
-                }
-                [sym::proc_macro_attribute, ..] => {
-                    self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute);
-                }
-                [sym::proc_macro_derive, ..] => {
-                    self.check_generic_attr(hir_id, attr, target, Target::Fn);
-                    self.check_proc_macro(hir_id, target, ProcMacroKind::Derive)
-                }
-                [sym::autodiff, ..] => {
-                    self.check_autodiff(hir_id, attr, span, target)
-                }
-                [sym::coroutine, ..] => {
-                    self.check_coroutine(attr, target);
-                }
-                [sym::linkage, ..] => self.check_linkage(attr, span, target),
-                [sym::rustc_pub_transparent, ..] => self.check_rustc_pub_transparent(attr.span, span, attrs),
-                [
-                    // ok
-                    sym::allow
-                    | sym::expect
-                    | sym::warn
-                    | sym::deny
-                    | sym::forbid
-                    | sym::cfg
-                    | sym::cfg_attr
-                    // need to be fixed
-                    | sym::cfi_encoding // FIXME(cfi_encoding)
-                    | sym::pointee // FIXME(derive_coerce_pointee)
-                    | sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section)
-                    | sym::used // handled elsewhere to restrict to static items
-                    | sym::repr // handled elsewhere to restrict to type decls items
-                    | sym::instruction_set // broken on stable!!!
-                    | sym::windows_subsystem // broken on stable!!!
-                    | sym::patchable_function_entry // FIXME(patchable_function_entry)
-                    | sym::deprecated_safe // FIXME(deprecated_safe)
-                    // internal
-                    | sym::prelude_import
-                    | sym::panic_handler
-                    | sym::allow_internal_unsafe
-                    | sym::fundamental
-                    | sym::lang
-                    | sym::needs_allocator
-                    | sym::default_lib_allocator
-                    | sym::custom_mir,
-                    ..
-                ] => {}
-                [name, ..] => {
-                    match BUILTIN_ATTRIBUTE_MAP.get(name) {
-                        // checked below
-                        Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) => {}
-                        Some(_) => {
-                            // FIXME: differentiate between unstable and internal attributes just
-                            // like we do with features instead of just accepting `rustc_`
-                            // attributes by name. That should allow trimming the above list, too.
-                            if !name.as_str().starts_with("rustc_") {
-                                span_bug!(
-                                    attr.span,
-                                    "builtin attribute {name:?} not handled by `CheckAttrVisitor`"
-                                )
+            match attr {
+                Attribute::Parsed(AttributeKind::Confusables { first_span, .. }) => {
+                    self.check_confusables(*first_span, target);
+                }
+                Attribute::Parsed(
+                    AttributeKind::Stability { span, .. }
+                    | AttributeKind::ConstStability { span, .. },
+                ) => self.check_stability_promotable(*span, target),
+                Attribute::Parsed(AttributeKind::AllowInternalUnstable(syms)) => self
+                    .check_allow_internal_unstable(
+                        hir_id,
+                        syms.first().unwrap().1,
+                        span,
+                        target,
+                        attrs,
+                    ),
+                _ => {
+                    match attr.path().as_slice() {
+                        [sym::diagnostic, sym::do_not_recommend, ..] => {
+                            self.check_do_not_recommend(attr.span(), hir_id, target, attr, item)
+                        }
+                        [sym::diagnostic, sym::on_unimplemented, ..] => {
+                            self.check_diagnostic_on_unimplemented(attr.span(), hir_id, target)
+                        }
+                        [sym::inline, ..] => self.check_inline(hir_id, attr, span, target),
+                        [sym::coverage, ..] => self.check_coverage(attr, span, target),
+                        [sym::optimize, ..] => self.check_optimize(hir_id, attr, span, target),
+                        [sym::no_sanitize, ..] => {
+                            self.check_no_sanitize(attr, span, target)
+                        }
+                        [sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target, item),
+                        [sym::marker, ..] => self.check_marker(hir_id, attr, span, target),
+                        [sym::target_feature, ..] => {
+                            self.check_target_feature(hir_id, attr, span, target, attrs)
+                        }
+                        [sym::thread_local, ..] => self.check_thread_local(attr, span, target),
+                        [sym::track_caller, ..] => {
+                            self.check_track_caller(hir_id, attr.span(), attrs, span, target)
+                        }
+                        [sym::doc, ..] => self.check_doc_attrs(
+                            attr,
+                            hir_id,
+                            target,
+                            &mut specified_inline,
+                            &mut doc_aliases,
+                        ),
+                        [sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target),
+                        [sym::export_name, ..] => self.check_export_name(hir_id, attr, span, target),
+                        [sym::rustc_layout_scalar_valid_range_start, ..]
+                        | [sym::rustc_layout_scalar_valid_range_end, ..] => {
+                            self.check_rustc_layout_scalar_valid_range(attr, span, target)
+                        }
+                        [sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target),
+                        [sym::rustc_allow_const_fn_unstable, ..] => {
+                            self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target)
+                        }
+                        [sym::rustc_std_internal_symbol, ..] => {
+                            self.check_rustc_std_internal_symbol(attr, span, target)
+                        }
+                        [sym::naked, ..] => self.check_naked(hir_id, attr, span, target, attrs),
+                        [sym::rustc_as_ptr, ..] => {
+                            self.check_applied_to_fn_or_method(hir_id, attr, span, target)
+                        }
+                        [sym::rustc_never_returns_null_ptr, ..] => {
+                            self.check_applied_to_fn_or_method(hir_id, attr, span, target)
+                        }
+                        [sym::rustc_legacy_const_generics, ..] => {
+                            self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item)
+                        }
+                        [sym::rustc_lint_query_instability, ..] => {
+                            self.check_applied_to_fn_or_method(hir_id, attr, span, target)
+                        }
+                        [sym::rustc_lint_untracked_query_information, ..] => {
+                            self.check_applied_to_fn_or_method(hir_id, attr, span, target)
+                        }
+                        [sym::rustc_lint_diagnostics, ..] => {
+                            self.check_applied_to_fn_or_method(hir_id, attr, span, target)
+                        }
+                        [sym::rustc_lint_opt_ty, ..] => self.check_rustc_lint_opt_ty(attr, span, target),
+                        [sym::rustc_lint_opt_deny_field_access, ..] => {
+                            self.check_rustc_lint_opt_deny_field_access(attr, span, target)
+                        }
+                        [sym::rustc_clean, ..]
+                        | [sym::rustc_dirty, ..]
+                        | [sym::rustc_if_this_changed, ..]
+                        | [sym::rustc_then_this_would_need, ..] => self.check_rustc_dirty_clean(attr),
+                        [sym::rustc_coinductive, ..]
+                        | [sym::rustc_must_implement_one_of, ..]
+                        | [sym::rustc_deny_explicit_impl, ..]
+                        | [sym::rustc_do_not_implement_via_object, ..]
+                        | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target),
+                        [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target),
+                        [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target),
+                        [sym::must_use, ..] => self.check_must_use(hir_id, attr, target),
+                        [sym::may_dangle, ..] => self.check_may_dangle(hir_id, attr),
+                        [sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target),
+                        [sym::rustc_allow_incoherent_impl, ..] => {
+                            self.check_allow_incoherent_impl(attr, span, target)
+                        }
+                        [sym::rustc_has_incoherent_inherent_impls, ..] => {
+                            self.check_has_incoherent_inherent_impls(attr, span, target)
+                        }
+                        [sym::ffi_pure, ..] => self.check_ffi_pure(attr.span(), attrs, target),
+                        [sym::ffi_const, ..] => self.check_ffi_const(attr.span(), target),
+                        [sym::link_ordinal, ..] => self.check_link_ordinal(attr, span, target),
+                        [sym::cold, ..] => self.check_cold(hir_id, attr, span, target),
+                        [sym::link, ..] => self.check_link(hir_id, attr, span, target),
+                        [sym::link_name, ..] => self.check_link_name(hir_id, attr, span, target),
+                        [sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target),
+                        [sym::no_mangle, ..] => self.check_no_mangle(hir_id, attr, span, target),
+                        [sym::deprecated, ..] => self.check_deprecated(hir_id, attr, span, target),
+                        [sym::macro_use, ..] | [sym::macro_escape, ..] => {
+                            self.check_macro_use(hir_id, attr, target)
+                        }
+                        [sym::path, ..] => self.check_generic_attr(hir_id, attr, target, Target::Mod),
+                        [sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target),
+                        [sym::ignore, ..] | [sym::should_panic, ..] => {
+                            self.check_generic_attr(hir_id, attr, target, Target::Fn)
+                        }
+                        [sym::automatically_derived, ..] => {
+                            self.check_generic_attr(hir_id, attr, target, Target::Impl)
+                        }
+                        [sym::no_implicit_prelude, ..] => {
+                            self.check_generic_attr(hir_id, attr, target, Target::Mod)
+                        }
+                        [sym::rustc_object_lifetime_default, ..] => self.check_object_lifetime_default(hir_id),
+                        [sym::proc_macro, ..] => {
+                            self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike)
+                        }
+                        [sym::proc_macro_attribute, ..] => {
+                            self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute);
+                        }
+                        [sym::proc_macro_derive, ..] => {
+                            self.check_generic_attr(hir_id, attr, target, Target::Fn);
+                            self.check_proc_macro(hir_id, target, ProcMacroKind::Derive)
+                        }
+                        [sym::autodiff, ..] => {
+                            self.check_autodiff(hir_id, attr, span, target)
+                        }
+                        [sym::coroutine, ..] => {
+                            self.check_coroutine(attr, target);
+                        }
+                        [sym::linkage, ..] => self.check_linkage(attr, span, target),
+                        [sym::rustc_pub_transparent, ..] => self.check_rustc_pub_transparent(attr.span(), span, attrs),
+                        [
+                            // ok
+                            sym::allow
+                            | sym::expect
+                            | sym::warn
+                            | sym::deny
+                            | sym::forbid
+                            | sym::cfg
+                            | sym::cfg_attr
+                            // need to be fixed
+                            | sym::cfi_encoding // FIXME(cfi_encoding)
+                            | sym::pointee // FIXME(derive_coerce_pointee)
+                            | sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section)
+                            | sym::used // handled elsewhere to restrict to static items
+                            | sym::repr // handled elsewhere to restrict to type decls items
+                            | sym::instruction_set // broken on stable!!!
+                            | sym::windows_subsystem // broken on stable!!!
+                            | sym::patchable_function_entry // FIXME(patchable_function_entry)
+                            | sym::deprecated_safe // FIXME(deprecated_safe)
+                            // internal
+                            | sym::prelude_import
+                            | sym::panic_handler
+                            | sym::allow_internal_unsafe
+                            | sym::fundamental
+                            | sym::lang
+                            | sym::needs_allocator
+                            | sym::default_lib_allocator
+                            | sym::custom_mir,
+                            ..
+                        ] => {}
+                        [name, ..] => {
+                            match BUILTIN_ATTRIBUTE_MAP.get(name) {
+                                // checked below
+                                Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) => {}
+                                Some(_) => {
+                                    // FIXME: differentiate between unstable and internal attributes just
+                                    // like we do with features instead of just accepting `rustc_`
+                                    // attributes by name. That should allow trimming the above list, too.
+                                    if !name.as_str().starts_with("rustc_") {
+                                        span_bug!(
+                                            attr.span(),
+                                            "builtin attribute {name:?} not handled by `CheckAttrVisitor`"
+                                        )
+                                    }
+                                }
+                                None => (),
                             }
                         }
-                        None => (),
+                        [] => unreachable!(),
                     }
                 }
-                [] => unreachable!(),
             }
 
             let builtin = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
@@ -305,17 +318,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) =
                     attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name))
                 {
-                    match attr.style {
+                    match attr.style() {
                         ast::AttrStyle::Outer => self.tcx.emit_node_span_lint(
                             UNUSED_ATTRIBUTES,
                             hir_id,
-                            attr.span,
+                            attr.span(),
                             errors::OuterCrateLevelAttr,
                         ),
                         ast::AttrStyle::Inner => self.tcx.emit_node_span_lint(
                             UNUSED_ATTRIBUTES,
                             hir_id,
-                            attr.span,
+                            attr.span(),
                             errors::InnerCrateLevelAttr,
                         ),
                     }
@@ -338,16 +351,16 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         self.tcx.emit_node_span_lint(
             UNUSED_ATTRIBUTES,
             hir_id,
-            attr.span,
+            attr.span(),
             errors::IgnoredAttrWithMacro { sym },
         );
     }
 
-    fn inline_attr_str_error_without_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) {
+    fn inline_attr_str_error_without_macro_def(&self, hir_id: HirId, attr_span: Span, sym: &str) {
         self.tcx.emit_node_span_lint(
             UNUSED_ATTRIBUTES,
             hir_id,
-            attr.span,
+            attr_span,
             errors::IgnoredAttr { sym },
         );
     }
@@ -407,7 +420,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 self.tcx.emit_node_span_lint(
                     UNUSED_ATTRIBUTES,
                     hir_id,
-                    attr.span,
+                    attr.span(),
                     errors::IgnoredInlineAttrFnProto,
                 )
             }
@@ -418,7 +431,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             Target::AssocConst => self.tcx.emit_node_span_lint(
                 UNUSED_ATTRIBUTES,
                 hir_id,
-                attr.span,
+                attr.span(),
                 errors::IgnoredInlineAttrConstants,
             ),
             // FIXME(#80564): Same for fields, arms, and macro defs
@@ -427,7 +440,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             }
             _ => {
                 self.dcx().emit_err(errors::InlineNotFnOrClosure {
-                    attr_span: attr.span,
+                    attr_span: attr.span(),
                     defn_span: span,
                 });
             }
@@ -459,7 +472,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
 
         self.dcx().emit_err(errors::CoverageAttributeNotAllowed {
-            attr_span: attr.span,
+            attr_span: attr.span(),
             not_fn_impl_mod,
             no_body,
             help: (),
@@ -477,7 +490,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         );
         if !is_valid {
             self.dcx().emit_err(errors::OptimizeInvalidTarget {
-                attr_span: attr.span,
+                attr_span: attr.span(),
                 defn_span: span,
                 on_crate: hir_id == CRATE_HIR_ID,
             });
@@ -528,7 +541,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             self.tcx.emit_node_span_lint(
                 UNUSED_ATTRIBUTES,
                 hir_id,
-                attr.span,
+                attr.span(),
                 errors::OnlyHasEffectOn {
                     attr_name: attr.name_or_empty(),
                     target_name: allowed_target.name().replace(' ', "_"),
@@ -568,6 +581,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             sym::warn,
             sym::deny,
             sym::forbid,
+            // FIXME(jdonszelmann): not used, because already a new-style attr (ugh)
             sym::deprecated,
             sym::must_use,
             // abi, linking and FFI
@@ -595,10 +609,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         continue;
                     }
 
+                    // FIXME(jdonszelmann): once naked uses new-style parsing,
+                    // this check can be part of the parser and be removed here
+                    match other_attr {
+                        Attribute::Parsed(
+                            AttributeKind::Deprecation { .. } | AttributeKind::Repr { .. },
+                        ) => {
+                            continue;
+                        }
+                        _ => {}
+                    }
+
                     if !ALLOW_LIST.iter().any(|name| other_attr.has_name(*name)) {
                         self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute {
-                            span: other_attr.span,
-                            naked_span: attr.span,
+                            span: other_attr.span(),
+                            naked_span: attr.span(),
                             attr: other_attr.name_or_empty(),
                         });
 
@@ -615,7 +640,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             }
             _ => {
                 self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
-                    attr_span: attr.span,
+                    attr_span: attr.span(),
                     defn_span: span,
                     on_crate: hir_id == CRATE_HIR_ID,
                 });
@@ -648,9 +673,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         match target {
             Target::MacroDef => {}
             _ => {
-                self.tcx
-                    .dcx()
-                    .emit_err(errors::CollapseDebuginfo { attr_span: attr.span, defn_span: span });
+                self.tcx.dcx().emit_err(errors::CollapseDebuginfo {
+                    attr_span: attr.span(),
+                    defn_span: span,
+                });
             }
         }
     }
@@ -720,7 +746,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     && fields.iter().any(|f| f.default.is_some())
                 {
                     self.dcx().emit_err(errors::NonExhaustiveWithDefaultFieldValues {
-                        attr_span: attr.span,
+                        attr_span: attr.span(),
                         defn_span: span,
                     });
                 }
@@ -735,7 +761,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             }
             _ => {
                 self.dcx().emit_err(errors::NonExhaustiveWrongLocation {
-                    attr_span: attr.span,
+                    attr_span: attr.span(),
                     defn_span: span,
                 });
             }
@@ -755,7 +781,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             }
             _ => {
                 self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait {
-                    attr_span: attr.span,
+                    attr_span: attr.span(),
                     defn_span: span,
                 });
             }
@@ -784,7 +810,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap();
 
                     self.dcx().emit_err(errors::LangItemWithTargetFeature {
-                        attr_span: attr.span,
+                        attr_span: attr.span(),
                         name: lang_item,
                         sig_span: sig.span,
                     });
@@ -796,7 +822,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 self.tcx.emit_node_span_lint(
                     UNUSED_ATTRIBUTES,
                     hir_id,
-                    attr.span,
+                    attr.span(),
                     errors::TargetFeatureOnStatement,
                 );
             }
@@ -809,7 +835,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             }
             _ => {
                 self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
-                    attr_span: attr.span,
+                    attr_span: attr.span(),
                     defn_span: span,
                     on_crate: hir_id == CRATE_HIR_ID,
                 });
@@ -823,7 +849,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             Target::ForeignStatic | Target::Static => {}
             _ => {
                 self.dcx().emit_err(errors::AttrShouldBeAppliedToStatic {
-                    attr_span: attr.span,
+                    attr_span: attr.span(),
                     defn_span: span,
                 });
             }
@@ -1093,7 +1119,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     meta.span(),
                     errors::DocInlineOnlyUse {
                         attr_span: meta.span(),
-                        item_span: (attr.style == AttrStyle::Outer)
+                        item_span: (attr.style() == AttrStyle::Outer)
                             .then(|| self.tcx.hir().span(hir_id)),
                     },
                 );
@@ -1115,7 +1141,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 meta.span(),
                 errors::DocMaskedOnlyExternCrate {
                     attr_span: meta.span(),
-                    item_span: (attr.style == AttrStyle::Outer)
+                    item_span: (attr.style() == AttrStyle::Outer)
                         .then(|| self.tcx.hir().span(hir_id)),
                 },
             );
@@ -1129,7 +1155,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 meta.span(),
                 errors::DocMaskedNotExternCrateSelf {
                     attr_span: meta.span(),
-                    item_span: (attr.style == AttrStyle::Outer)
+                    item_span: (attr.style() == AttrStyle::Outer)
                         .then(|| self.tcx.hir().span(hir_id)),
                 },
             );
@@ -1159,11 +1185,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
     ) -> bool {
         if hir_id != CRATE_HIR_ID {
             // insert a bang between `#` and `[...`
-            let bang_span = attr.span.lo() + BytePos(1);
-            let sugg = (attr.style == AttrStyle::Outer
+            let bang_span = attr.span().lo() + BytePos(1);
+            let sugg = (attr.style() == AttrStyle::Outer
                 && self.tcx.hir_get_parent_item(hir_id) == CRATE_OWNER_ID)
                 .then_some(errors::AttrCrateLevelOnlySugg {
-                    attr: attr.span.with_lo(bang_span).with_hi(bang_span),
+                    attr: attr.span().with_lo(bang_span).with_hi(bang_span),
                 });
             self.tcx.emit_node_span_lint(
                 INVALID_DOC_ATTRIBUTES,
@@ -1337,11 +1363,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                                     errors::DocTestUnknownInclude {
                                         path,
                                         value: value.to_string(),
-                                        inner: match attr.style {
+                                        inner: match attr.style() {
                                             AttrStyle::Inner => "!",
                                             AttrStyle::Outer => "",
                                         },
-                                        sugg: (attr.span, applicability),
+                                        sugg: (attr.span(), applicability),
                                     },
                                 );
                             } else if i_meta.has_name(sym::passes)
@@ -1387,7 +1413,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         match target {
             Target::Struct | Target::Enum | Target::TyAlias => {}
             _ => {
-                self.dcx().emit_err(errors::PassByValue { attr_span: attr.span, span });
+                self.dcx().emit_err(errors::PassByValue { attr_span: attr.span(), span });
             }
         }
     }
@@ -1396,7 +1422,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         match target {
             Target::Method(MethodKind::Inherent) => {}
             _ => {
-                self.dcx().emit_err(errors::AllowIncoherentImpl { attr_span: attr.span, span });
+                self.dcx().emit_err(errors::AllowIncoherentImpl { attr_span: attr.span(), span });
             }
         }
     }
@@ -1407,7 +1433,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             _ => {
                 self.tcx
                     .dcx()
-                    .emit_err(errors::HasIncoherentInherentImpl { attr_span: attr.span, span });
+                    .emit_err(errors::HasIncoherentInherentImpl { attr_span: attr.span(), span });
             }
         }
     }
@@ -1470,7 +1496,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         self.tcx.emit_node_span_lint(
             UNUSED_ATTRIBUTES,
             hir_id,
-            attr.span,
+            attr.span(),
             errors::MustUseNoEffect { article, target },
         );
     }
@@ -1480,7 +1506,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         match target {
             Target::Struct | Target::Enum | Target::Union | Target::Trait => {}
             _ => {
-                self.dcx().emit_err(errors::MustNotSuspend { attr_span: attr.span, span });
+                self.dcx().emit_err(errors::MustNotSuspend { attr_span: attr.span(), span });
             }
         }
     }
@@ -1503,7 +1529,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             return;
         }
 
-        self.dcx().emit_err(errors::InvalidMayDangle { attr_span: attr.span });
+        self.dcx().emit_err(errors::InvalidMayDangle { attr_span: attr.span() });
     }
 
     /// Checks if `#[cold]` is applied to a non-function.
@@ -1523,7 +1549,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 self.tcx.emit_node_span_lint(
                     UNUSED_ATTRIBUTES,
                     hir_id,
-                    attr.span,
+                    attr.span(),
                     errors::Cold { span, on_crate: hir_id == CRATE_HIR_ID },
                 );
             }
@@ -1543,7 +1569,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         self.tcx.emit_node_span_lint(
             UNUSED_ATTRIBUTES,
             hir_id,
-            attr.span,
+            attr.span(),
             errors::Link { span: (target != Target::ForeignMod).then_some(span) },
         );
     }
@@ -1562,19 +1588,19 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             _ => {
                 // FIXME: #[cold] was previously allowed on non-functions/statics and some crates
                 // used this, so only emit a warning.
-                let attr_span = matches!(target, Target::ForeignMod).then_some(attr.span);
+                let attr_span = matches!(target, Target::ForeignMod).then_some(attr.span());
                 if let Some(s) = attr.value_str() {
                     self.tcx.emit_node_span_lint(
                         UNUSED_ATTRIBUTES,
                         hir_id,
-                        attr.span,
+                        attr.span(),
                         errors::LinkName { span, attr_span, value: s.as_str() },
                     );
                 } else {
                     self.tcx.emit_node_span_lint(
                         UNUSED_ATTRIBUTES,
                         hir_id,
-                        attr.span,
+                        attr.span(),
                         errors::LinkName { span, attr_span, value: "..." },
                     );
                 };
@@ -1594,7 +1620,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_link");
             }
             _ => {
-                self.dcx().emit_err(errors::NoLink { attr_span: attr.span, span });
+                self.dcx().emit_err(errors::NoLink { attr_span: attr.span(), span });
             }
         }
     }
@@ -1616,7 +1642,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "export_name");
             }
             _ => {
-                self.dcx().emit_err(errors::ExportName { attr_span: attr.span, span });
+                self.dcx().emit_err(errors::ExportName { attr_span: attr.span(), span });
             }
         }
     }
@@ -1624,7 +1650,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
     fn check_rustc_layout_scalar_valid_range(&self, attr: &Attribute, span: Span, target: Target) {
         if target != Target::Struct {
             self.dcx().emit_err(errors::RustcLayoutScalarValidRangeNotStruct {
-                attr_span: attr.span,
+                attr_span: attr.span(),
                 span,
             });
             return;
@@ -1637,7 +1663,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         if !matches!(&list[..], &[MetaItemInner::Lit(MetaItemLit { kind: LitKind::Int(..), .. })]) {
             self.tcx
                 .dcx()
-                .emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span });
+                .emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span() });
         }
     }
 
@@ -1653,7 +1679,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         let is_function = matches!(target, Target::Fn);
         if !is_function {
             self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
-                attr_span: attr.span,
+                attr_span: attr.span(),
                 defn_span: span,
                 on_crate: hir_id == CRATE_HIR_ID,
             });
@@ -1678,7 +1704,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 hir::GenericParamKind::Const { .. } => {}
                 _ => {
                     self.dcx().emit_err(errors::RustcLegacyConstGenericsOnly {
-                        attr_span: attr.span,
+                        attr_span: attr.span(),
                         param_span: param.span,
                     });
                     return;
@@ -1688,7 +1714,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
 
         if list.len() != generics.params.len() {
             self.dcx().emit_err(errors::RustcLegacyConstGenericsIndex {
-                attr_span: attr.span,
+                attr_span: attr.span(),
                 generics_span: generics.span,
             });
             return;
@@ -1728,7 +1754,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         let is_function = matches!(target, Target::Fn | Target::Method(..));
         if !is_function {
             self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
-                attr_span: attr.span,
+                attr_span: attr.span(),
                 defn_span: span,
                 on_crate: hir_id == CRATE_HIR_ID,
             });
@@ -1740,7 +1766,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         match target {
             Target::Struct => {}
             _ => {
-                self.dcx().emit_err(errors::RustcLintOptTy { attr_span: attr.span, span });
+                self.dcx().emit_err(errors::RustcLintOptTy { attr_span: attr.span(), span });
             }
         }
     }
@@ -1752,7 +1778,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             _ => {
                 self.tcx
                     .dcx()
-                    .emit_err(errors::RustcLintOptDenyFieldAccess { attr_span: attr.span, span });
+                    .emit_err(errors::RustcLintOptDenyFieldAccess { attr_span: attr.span(), span });
             }
         }
     }
@@ -1761,7 +1787,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
     /// option is passed to the compiler.
     fn check_rustc_dirty_clean(&self, attr: &Attribute) {
         if !self.tcx.sess.opts.unstable_opts.query_dep_graph {
-            self.dcx().emit_err(errors::RustcDirtyClean { span: attr.span });
+            self.dcx().emit_err(errors::RustcDirtyClean { span: attr.span() });
         }
     }
 
@@ -1771,7 +1797,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             Target::Trait => {}
             _ => {
                 self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait {
-                    attr_span: attr.span,
+                    attr_span: attr.span(),
                     defn_span: span,
                 });
             }
@@ -1795,7 +1821,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 self.tcx.emit_node_span_lint(
                     UNUSED_ATTRIBUTES,
                     hir_id,
-                    attr.span,
+                    attr.span(),
                     errors::LinkSection { span },
                 );
             }
@@ -1826,8 +1852,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 self.tcx.emit_node_span_lint(
                     UNUSED_ATTRIBUTES,
                     hir_id,
-                    attr.span,
-                    errors::NoMangleForeign { span, attr_span: attr.span, foreign_item_kind },
+                    attr.span(),
+                    errors::NoMangleForeign { span, attr_span: attr.span(), foreign_item_kind },
                 );
             }
             _ => {
@@ -1836,7 +1862,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 self.tcx.emit_node_span_lint(
                     UNUSED_ATTRIBUTES,
                     hir_id,
-                    attr.span,
+                    attr.span(),
                     errors::NoMangle { span },
                 );
             }
@@ -1857,12 +1883,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         // #[repr(foo)]
         // #[repr(bar, align(8))]
         // ```
-        let hints: Vec<_> = attrs
-            .iter()
-            .filter(|attr| attr.has_name(sym::repr))
-            .filter_map(|attr| attr.meta_item_list())
-            .flatten()
-            .collect();
+        let reprs = find_attr!(attrs, AttributeKind::Repr(r) => r.as_slice()).unwrap_or(&[]);
 
         let mut int_reprs = 0;
         let mut is_explicit_rust = false;
@@ -1870,66 +1891,33 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         let mut is_simd = false;
         let mut is_transparent = false;
 
-        // catch `repr()` with no arguments, applied to an item (i.e. not `#![repr()]`)
-        if hints.is_empty() && item.is_some() {
-            for attr in attrs.iter().filter(|attr| attr.has_name(sym::repr)) {
-                match target {
-                    Target::Struct | Target::Union | Target::Enum => {}
-                    Target::Fn | Target::Method(_) => {
-                        feature_err(
-                            &self.tcx.sess,
-                            sym::fn_align,
-                            attr.span,
-                            fluent::passes_repr_align_function,
-                        )
-                        .emit();
-                    }
-                    _ => {
-                        self.dcx().emit_err(
-                            errors::AttrApplication::StructEnumFunctionMethodUnion {
-                                hint_span: attr.span,
-                                span,
-                            },
-                        );
-                    }
-                }
-            }
-
-            return;
-        }
-
-        for hint in &hints {
-            if !hint.is_meta_item() {
-                self.dcx().emit_err(errors::ReprIdent { span: hint.span() });
-                continue;
-            }
-
-            match hint.name_or_empty() {
-                sym::Rust => {
+        for (repr, repr_span) in reprs {
+            match repr {
+                ReprAttr::ReprRust => {
                     is_explicit_rust = true;
                     match target {
                         Target::Struct | Target::Union | Target::Enum => continue,
                         _ => {
                             self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
-                                hint_span: hint.span(),
+                                hint_span: *repr_span,
                                 span,
                             });
                         }
                     }
                 }
-                sym::C => {
+                ReprAttr::ReprC => {
                     is_c = true;
                     match target {
                         Target::Struct | Target::Union | Target::Enum => continue,
                         _ => {
                             self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
-                                hint_span: hint.span(),
+                                hint_span: *repr_span,
                                 span,
                             });
                         }
                     }
                 }
-                sym::align => {
+                ReprAttr::ReprAlign(align) => {
                     match target {
                         Target::Struct | Target::Union | Target::Enum => {}
                         Target::Fn | Target::Method(_) => {
@@ -1937,7 +1925,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                                 feature_err(
                                     &self.tcx.sess,
                                     sym::fn_align,
-                                    hint.span(),
+                                    *repr_span,
                                     fluent::passes_repr_align_function,
                                 )
                                 .emit();
@@ -1946,83 +1934,97 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         _ => {
                             self.dcx().emit_err(
                                 errors::AttrApplication::StructEnumFunctionMethodUnion {
-                                    hint_span: hint.span(),
+                                    hint_span: *repr_span,
                                     span,
                                 },
                             );
                         }
                     }
 
-                    self.check_align_value(hint);
+                    self.check_align_value(*align, *repr_span);
                 }
-                sym::packed => {
+                ReprAttr::ReprPacked(_) => {
                     if target != Target::Struct && target != Target::Union {
                         self.dcx().emit_err(errors::AttrApplication::StructUnion {
-                            hint_span: hint.span(),
+                            hint_span: *repr_span,
                             span,
                         });
                     } else {
                         continue;
                     }
                 }
-                sym::simd => {
+                ReprAttr::ReprSimd => {
                     is_simd = true;
                     if target != Target::Struct {
                         self.dcx().emit_err(errors::AttrApplication::Struct {
-                            hint_span: hint.span(),
+                            hint_span: *repr_span,
                             span,
                         });
                     } else {
                         continue;
                     }
                 }
-                sym::transparent => {
+                ReprAttr::ReprTransparent => {
                     is_transparent = true;
                     match target {
                         Target::Struct | Target::Union | Target::Enum => continue,
                         _ => {
                             self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
-                                hint_span: hint.span(),
+                                hint_span: *repr_span,
                                 span,
                             });
                         }
                     }
                 }
-                sym::i8
-                | sym::u8
-                | sym::i16
-                | sym::u16
-                | sym::i32
-                | sym::u32
-                | sym::i64
-                | sym::u64
-                | sym::i128
-                | sym::u128
-                | sym::isize
-                | sym::usize => {
+                ReprAttr::ReprInt(_) => {
                     int_reprs += 1;
                     if target != Target::Enum {
                         self.dcx().emit_err(errors::AttrApplication::Enum {
-                            hint_span: hint.span(),
+                            hint_span: *repr_span,
                             span,
                         });
                     } else {
                         continue;
                     }
                 }
-                _ => {
-                    self.dcx().emit_err(errors::UnrecognizedReprHint { span: hint.span() });
-                    continue;
+                // FIXME(jdonszelmann): move the diagnostic for unused repr attrs here, I think
+                // it's a better place for it.
+                ReprAttr::ReprEmpty => {
+                    // catch `repr()` with no arguments, applied to an item (i.e. not `#![repr()]`)
+                    if item.is_some() {
+                        match target {
+                            Target::Struct | Target::Union | Target::Enum => {}
+                            Target::Fn | Target::Method(_) => {
+                                feature_err(
+                                    &self.tcx.sess,
+                                    sym::fn_align,
+                                    *repr_span,
+                                    fluent::passes_repr_align_function,
+                                )
+                                .emit();
+                            }
+                            _ => {
+                                self.dcx().emit_err(
+                                    errors::AttrApplication::StructEnumFunctionMethodUnion {
+                                        hint_span: *repr_span,
+                                        span,
+                                    },
+                                );
+                            }
+                        }
+                    }
+
+                    return;
                 }
             };
         }
 
         // Just point at all repr hints if there are any incompatibilities.
         // This is not ideal, but tracking precisely which ones are at fault is a huge hassle.
-        let hint_spans = hints.iter().map(|hint| hint.span());
+        let hint_spans = reprs.iter().map(|(_, span)| *span);
 
         // Error on repr(transparent, <anything else>).
-        if is_transparent && hints.len() > 1 {
+        if is_transparent && reprs.len() > 1 {
             let hint_spans = hint_spans.clone().collect();
             self.dcx().emit_err(errors::TransparentIncompatible {
                 hint_spans,
@@ -2051,41 +2053,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
     }
 
-    fn check_align_value(&self, item: &MetaItemInner) {
-        match item.singleton_lit_list() {
-            Some((
-                _,
-                MetaItemLit {
-                    kind: ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed), ..
-                },
-            )) => {
-                let val = literal.get() as u64;
-                if val > 2_u64.pow(29) {
-                    // for values greater than 2^29, a different error will be emitted, make sure that happens
-                    self.dcx().span_delayed_bug(
-                        item.span(),
-                        "alignment greater than 2^29 should be errored on elsewhere",
-                    );
-                } else {
-                    // only do this check when <= 2^29 to prevent duplicate errors:
-                    // alignment greater than 2^29 not supported
-                    // alignment is too large for the current target
-
-                    let max =
-                        Size::from_bits(self.tcx.sess.target.pointer_width).signed_int_max() as u64;
-                    if val > max {
-                        self.dcx().emit_err(errors::InvalidReprAlignForTarget {
-                            span: item.span(),
-                            size: max,
-                        });
-                    }
-                }
-            }
+    fn check_align_value(&self, align: Align, span: Span) {
+        if align.bytes() > 2_u64.pow(29) {
+            // for values greater than 2^29, a different error will be emitted, make sure that happens
+            self.dcx().span_delayed_bug(
+                span,
+                "alignment greater than 2^29 should be errored on elsewhere",
+            );
+        } else {
+            // only do this check when <= 2^29 to prevent duplicate errors:
+            // alignment greater than 2^29 not supported
+            // alignment is too large for the current target
 
-            // if the attribute is malformed, singleton_lit_list may not be of the expected type or may be None
-            // but an error will have already been emitted, so this code should just skip such attributes
-            Some((_, _)) | None => {
-                self.dcx().span_delayed_bug(item.span(), "malformed repr(align(N))");
+            let max = Size::from_bits(self.tcx.sess.target.pointer_width).signed_int_max() as u64;
+            if align.bytes() > max {
+                self.dcx().emit_err(errors::InvalidReprAlignForTarget { span, size: max });
             }
         }
     }
@@ -2096,7 +2078,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         for attr in attrs.iter().filter(|attr| attr.has_name(sym::used)) {
             if target != Target::Static {
                 self.dcx().emit_err(errors::UsedStatic {
-                    attr_span: attr.span,
+                    attr_span: attr.span(),
                     span: target_span,
                     target: target.name(),
                 });
@@ -2105,12 +2087,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             match inner.as_deref() {
                 Some([item]) if item.has_name(sym::linker) => {
                     if used_linker_span.is_none() {
-                        used_linker_span = Some(attr.span);
+                        used_linker_span = Some(attr.span());
                     }
                 }
                 Some([item]) if item.has_name(sym::compiler) => {
                     if used_compiler_span.is_none() {
-                        used_compiler_span = Some(attr.span);
+                        used_compiler_span = Some(attr.span());
                     }
                 }
                 Some(_) => {
@@ -2119,7 +2101,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 None => {
                     // Default case (compiler) when arg isn't defined.
                     if used_compiler_span.is_none() {
-                        used_compiler_span = Some(attr.span);
+                        used_compiler_span = Some(attr.span());
                     }
                 }
             }
@@ -2133,41 +2115,44 @@ 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,
-        attr: &Attribute,
+        attr_span: Span,
         span: Span,
         target: Target,
         attrs: &[Attribute],
     ) {
-        debug!("Checking target: {:?}", target);
         match target {
             Target::Fn => {
                 for attr in attrs {
                     if attr.is_proc_macro_attr() {
-                        debug!("Is proc macro attr");
+                        // return on proc macros
                         return;
                     }
                 }
-                debug!("Is not proc macro attr");
+                // continue out of the match
             }
-            Target::MacroDef => {}
+            // return on decl macros
+            Target::MacroDef => return,
             // FIXME(#80564): We permit struct fields and match arms to have an
             // `#[allow_internal_unstable]` attribute with just a lint, because we previously
             // 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,
-                "allow_internal_unstable",
-            ),
-            _ => {
-                self.tcx
-                    .dcx()
-                    .emit_err(errors::AllowInternalUnstable { attr_span: attr.span, span });
+            Target::Field | Target::Arm => {
+                self.inline_attr_str_error_without_macro_def(
+                    hir_id,
+                    attr_span,
+                    "allow_internal_unstable",
+                );
+                return;
             }
+            // otherwise continue out of the match
+            _ => {}
         }
+
+        self.tcx.dcx().emit_err(errors::AllowInternalUnstable { attr_span, span });
     }
 
     /// Checks if the items on the `#[debugger_visualizer]` attribute are valid.
@@ -2179,7 +2164,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         match target {
             Target::Mod => {}
             _ => {
-                self.dcx().emit_err(errors::DebugVisualizerPlacement { span: attr.span });
+                self.dcx().emit_err(errors::DebugVisualizerPlacement { span: attr.span() });
             }
         }
     }
@@ -2206,7 +2191,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             _ => {
                 self.tcx
                     .dcx()
-                    .emit_err(errors::RustcAllowConstFnUnstable { attr_span: attr.span, span });
+                    .emit_err(errors::RustcAllowConstFnUnstable { attr_span: attr.span(), span });
             }
         }
     }
@@ -2217,15 +2202,15 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             _ => {
                 self.tcx
                     .dcx()
-                    .emit_err(errors::RustcStdInternalSymbol { attr_span: attr.span, span });
+                    .emit_err(errors::RustcStdInternalSymbol { attr_span: attr.span(), span });
             }
         }
     }
 
-    fn check_stability_promotable(&self, attr: &Attribute, target: Target) {
+    fn check_stability_promotable(&self, span: Span, target: Target) {
         match target {
             Target::Expression => {
-                self.dcx().emit_err(errors::StabilityPromotable { attr_span: attr.span });
+                self.dcx().emit_err(errors::StabilityPromotable { attr_span: span });
             }
             _ => {}
         }
@@ -2235,41 +2220,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         match target {
             Target::ForeignFn | Target::ForeignStatic => {}
             _ => {
-                self.dcx().emit_err(errors::LinkOrdinal { attr_span: attr.span });
+                self.dcx().emit_err(errors::LinkOrdinal { attr_span: attr.span() });
             }
         }
     }
 
-    fn check_confusables(&self, attr: &Attribute, target: Target) {
-        match target {
-            Target::Method(MethodKind::Inherent) => {
-                let Some(metas) = attr.meta_item_list() else {
-                    return;
-                };
-
-                let mut candidates = Vec::new();
-
-                for meta in metas {
-                    let MetaItemInner::Lit(meta_lit) = meta else {
-                        self.dcx().emit_err(errors::IncorrectMetaItem {
-                            span: meta.span(),
-                            suggestion: errors::IncorrectMetaItemSuggestion {
-                                lo: meta.span().shrink_to_lo(),
-                                hi: meta.span().shrink_to_hi(),
-                            },
-                        });
-                        return;
-                    };
-                    candidates.push(meta_lit.symbol);
-                }
-
-                if candidates.is_empty() {
-                    self.dcx().emit_err(errors::EmptyConfusables { span: attr.span });
-                }
-            }
-            _ => {
-                self.dcx().emit_err(errors::Confusables { attr_span: attr.span });
-            }
+    fn check_confusables(&self, span: Span, target: Target) {
+        if !matches!(target, Target::Method(MethodKind::Inherent)) {
+            self.dcx().emit_err(errors::Confusables { attr_span: span });
         }
     }
 
@@ -2279,7 +2237,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 self.tcx.emit_node_span_lint(
                     UNUSED_ATTRIBUTES,
                     hir_id,
-                    attr.span,
+                    attr.span(),
                     errors::Deprecated,
                 );
             }
@@ -2295,7 +2253,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 self.tcx.emit_node_span_lint(
                     UNUSED_ATTRIBUTES,
                     hir_id,
-                    attr.span,
+                    attr.span(),
                     errors::MacroUse { name },
                 );
             }
@@ -2307,7 +2265,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             self.tcx.emit_node_span_lint(
                 UNUSED_ATTRIBUTES,
                 hir_id,
-                attr.span,
+                attr.span(),
                 errors::MacroExport::Normal,
             );
         } else if let Some(meta_item_list) = attr.meta_item_list()
@@ -2317,7 +2275,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 self.tcx.emit_node_span_lint(
                     INVALID_MACRO_EXPORT_ARGUMENTS,
                     hir_id,
-                    attr.span,
+                    attr.span(),
                     errors::MacroExport::TooManyItems,
                 );
             } else if meta_item_list[0].name_or_empty() != sym::local_inner_macros {
@@ -2337,7 +2295,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 self.tcx.emit_node_span_lint(
                     UNUSED_ATTRIBUTES,
                     hir_id,
-                    attr.span,
+                    attr.span(),
                     errors::MacroExport::OnDeclMacro,
                 );
             }
@@ -2345,8 +2303,32 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
     }
 
     fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) {
+        // FIXME(jdonszelmann): deduplicate these checks after more attrs are parsed. This is very
+        // ugly now but can 100% be removed later.
+        if let Attribute::Parsed(p) = attr {
+            match p {
+                AttributeKind::Repr(reprs) => {
+                    for (r, span) in reprs {
+                        if let ReprAttr::ReprEmpty = r {
+                            self.tcx.emit_node_span_lint(
+                                UNUSED_ATTRIBUTES,
+                                hir_id,
+                                *span,
+                                errors::Unused {
+                                    attr_span: *span,
+                                    note: errors::UnusedNote::EmptyList { name: sym::repr },
+                                },
+                            );
+                        }
+                    }
+                    return;
+                }
+                _ => {}
+            }
+        }
+
         // Warn on useless empty attributes.
-        let note = if matches!(
+        let note = if (matches!(
             attr.name_or_empty(),
             sym::macro_use
                 | sym::allow
@@ -2355,9 +2337,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 | sym::deny
                 | sym::forbid
                 | sym::feature
-                | sym::repr
                 | sym::target_feature
-        ) && attr.meta_item_list().is_some_and(|list| list.is_empty())
+        ) && attr.meta_item_list().is_some_and(|list| list.is_empty()))
         {
             errors::UnusedNote::EmptyList { name: attr.name_or_empty() }
         } else if matches!(
@@ -2379,17 +2360,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             })
         {
             if hir_id != CRATE_HIR_ID {
-                match attr.style {
+                match attr.style() {
                     ast::AttrStyle::Outer => self.tcx.emit_node_span_lint(
                         UNUSED_ATTRIBUTES,
                         hir_id,
-                        attr.span,
+                        attr.span(),
                         errors::OuterCrateLevelAttr,
                     ),
                     ast::AttrStyle::Inner => self.tcx.emit_node_span_lint(
                         UNUSED_ATTRIBUTES,
                         hir_id,
-                        attr.span,
+                        attr.span(),
                         errors::InnerCrateLevelAttr,
                     ),
                 };
@@ -2415,8 +2396,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         self.tcx.emit_node_span_lint(
             UNUSED_ATTRIBUTES,
             hir_id,
-            attr.span,
-            errors::Unused { attr_span: attr.span, note },
+            attr.span(),
+            errors::Unused { attr_span: attr.span(), note },
         );
     }
 
@@ -2532,7 +2513,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         match target {
             Target::Closure => return,
             _ => {
-                self.dcx().emit_err(errors::CoroutineOnNonClosure { span: attr.span });
+                self.dcx().emit_err(errors::CoroutineOnNonClosure { span: attr.span() });
             }
         }
     }
@@ -2545,18 +2526,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             | Target::ForeignStatic
             | Target::ForeignFn => {}
             _ => {
-                self.dcx().emit_err(errors::Linkage { attr_span: attr.span, span });
+                self.dcx().emit_err(errors::Linkage { attr_span: attr.span(), span });
             }
         }
     }
 
     fn check_rustc_pub_transparent(&self, attr_span: Span, span: Span, attrs: &[Attribute]) {
-        if !attrs
-            .iter()
-            .filter(|attr| attr.has_name(sym::repr))
-            .filter_map(|attr| attr.meta_item_list())
-            .flatten()
-            .any(|nmi| nmi.has_name(sym::transparent))
+        if !find_attr!(attrs, AttributeKind::Repr(r) => r.iter().any(|(r, _)| r == &ReprAttr::ReprTransparent))
+            .unwrap_or(false)
         {
             self.dcx().emit_err(errors::RustcPubTransparent { span, attr_span });
         }
@@ -2588,14 +2565,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     && is_coro
                 {
                     self.dcx().emit_err(errors::RustcForceInlineCoro {
-                        attr_span: attr.span,
+                        attr_span: attr.span(),
                         span: parent_span,
                     });
                 }
             }
             (Target::Fn, _) => (),
             (_, Some(attr)) => {
-                self.dcx().emit_err(errors::RustcForceInline { attr_span: attr.span, span });
+                self.dcx().emit_err(errors::RustcForceInline { attr_span: attr.span(), span });
             }
             (_, None) => (),
         }
@@ -2733,7 +2710,6 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
     // resolution for the attribute macro error.
     const ATTRS_TO_CHECK: &[Symbol] = &[
         sym::macro_export,
-        sym::repr,
         sym::path,
         sym::automatically_derived,
         sym::rustc_main,
@@ -2745,47 +2721,46 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
     ];
 
     for attr in attrs {
-        // This function should only be called with crate attributes
-        // which are inner attributes always but lets check to make sure
-        if attr.style == AttrStyle::Inner {
-            for attr_to_check in ATTRS_TO_CHECK {
-                if attr.has_name(*attr_to_check) {
-                    let item = tcx
-                        .hir_free_items()
-                        .map(|id| tcx.hir_item(id))
-                        .find(|item| !item.span.is_dummy()) // Skip prelude `use`s
-                        .map(|item| errors::ItemFollowingInnerAttr {
-                            span: item.ident.span,
-                            kind: item.kind.descr(),
-                        });
-                    let err = tcx.dcx().create_err(errors::InvalidAttrAtCrateLevel {
-                        span: attr.span,
-                        sugg_span: tcx
-                            .sess
-                            .source_map()
-                            .span_to_snippet(attr.span)
-                            .ok()
-                            .filter(|src| src.starts_with("#!["))
-                            .map(|_| {
-                                attr.span
-                                    .with_lo(attr.span.lo() + BytePos(1))
-                                    .with_hi(attr.span.lo() + BytePos(2))
-                            }),
-                        name: *attr_to_check,
-                        item,
-                    });
+        // FIXME(jdonszelmann): all attrs should be combined here cleaning this up some day.
+        let (span, name) = if let Some(a) =
+            ATTRS_TO_CHECK.iter().find(|attr_to_check| attr.has_name(**attr_to_check))
+        {
+            (attr.span(), *a)
+        } else if let Attribute::Parsed(AttributeKind::Repr(r)) = attr {
+            (r.first().unwrap().1, sym::repr)
+        } else {
+            continue;
+        };
 
-                    if let AttrKind::Normal(ref p) = attr.kind {
-                        tcx.dcx().try_steal_replace_and_emit_err(
-                            p.path.span,
-                            StashKey::UndeterminedMacroResolution,
-                            err,
-                        );
-                    } else {
-                        err.emit();
-                    }
-                }
-            }
+        let item = tcx
+            .hir_free_items()
+            .map(|id| tcx.hir_item(id))
+            .find(|item| !item.span.is_dummy()) // Skip prelude `use`s
+            .map(|item| errors::ItemFollowingInnerAttr {
+                span: item.ident.span,
+                kind: item.kind.descr(),
+            });
+        let err = tcx.dcx().create_err(errors::InvalidAttrAtCrateLevel {
+            span,
+            sugg_span: tcx
+                .sess
+                .source_map()
+                .span_to_snippet(span)
+                .ok()
+                .filter(|src| src.starts_with("#!["))
+                .map(|_| span.with_lo(span.lo() + BytePos(1)).with_hi(span.lo() + BytePos(2))),
+            name,
+            item,
+        });
+
+        if let Attribute::Unparsed(p) = attr {
+            tcx.dcx().try_steal_replace_and_emit_err(
+                p.path.span,
+                StashKey::UndeterminedMacroResolution,
+                err,
+            );
+        } else {
+            err.emit();
         }
     }
 }
@@ -2795,7 +2770,7 @@ fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>)
 
     for attr in attrs {
         if attr.has_name(sym::inline) {
-            tcx.dcx().emit_err(errors::NonExportedMacroInvalidAttrs { attr_span: attr.span });
+            tcx.dcx().emit_err(errors::NonExportedMacroInvalidAttrs { attr_span: attr.span() });
         }
     }
 }
@@ -2833,10 +2808,10 @@ fn check_duplicates(
             match seen.entry(attr.name_or_empty()) {
                 Entry::Occupied(mut entry) => {
                     let (this, other) = if matches!(duplicates, FutureWarnPreceding) {
-                        let to_remove = entry.insert(attr.span);
-                        (to_remove, attr.span)
+                        let to_remove = entry.insert(attr.span());
+                        (to_remove, attr.span())
                     } else {
-                        (attr.span, *entry.get())
+                        (attr.span(), *entry.get())
                     };
                     tcx.emit_node_span_lint(
                         UNUSED_ATTRIBUTES,
@@ -2853,17 +2828,17 @@ fn check_duplicates(
                     );
                 }
                 Entry::Vacant(entry) => {
-                    entry.insert(attr.span);
+                    entry.insert(attr.span());
                 }
             }
         }
         ErrorFollowing | ErrorPreceding => match seen.entry(attr.name_or_empty()) {
             Entry::Occupied(mut entry) => {
                 let (this, other) = if matches!(duplicates, ErrorPreceding) {
-                    let to_remove = entry.insert(attr.span);
-                    (to_remove, attr.span)
+                    let to_remove = entry.insert(attr.span());
+                    (to_remove, attr.span())
                 } else {
-                    (attr.span, *entry.get())
+                    (attr.span(), *entry.get())
                 };
                 tcx.dcx().emit_err(errors::UnusedMultiple {
                     this,
@@ -2872,7 +2847,7 @@ fn check_duplicates(
                 });
             }
             Entry::Vacant(entry) => {
-                entry.insert(attr.span);
+                entry.insert(attr.span());
             }
         },
     }
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index c2225ea1e64..25e679a8460 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -46,7 +46,7 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> {
 
 fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Option<Span> {
     let attrs = ctxt.tcx.hir().attrs(id.hir_id());
-    attr::find_by_name(attrs, sym).map(|attr| attr.span)
+    attr::find_by_name(attrs, sym).map(|attr| attr.span())
 }
 
 fn check_and_search_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 9bcdd238547..5f686f38bab 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -583,13 +583,6 @@ pub(crate) struct NoMangle {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_repr_ident, code = E0565)]
-pub(crate) struct ReprIdent {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(passes_repr_conflicting, code = E0566)]
 pub(crate) struct ReprConflicting {
     #[primary_span]
@@ -737,31 +730,6 @@ pub(crate) struct Linkage {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_empty_confusables)]
-pub(crate) struct EmptyConfusables {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
-#[diag(passes_incorrect_meta_item, code = E0539)]
-pub(crate) struct IncorrectMetaItem {
-    #[primary_span]
-    pub span: Span,
-    #[subdiagnostic]
-    pub suggestion: IncorrectMetaItemSuggestion,
-}
-
-#[derive(Subdiagnostic)]
-#[multipart_suggestion(passes_incorrect_meta_item_suggestion, applicability = "maybe-incorrect")]
-pub(crate) struct IncorrectMetaItemSuggestion {
-    #[suggestion_part(code = "\"")]
-    pub lo: Span,
-    #[suggestion_part(code = "\"")]
-    pub hi: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(passes_stability_promotable)]
 pub(crate) struct StabilityPromotable {
     #[primary_span]
@@ -1476,14 +1444,6 @@ pub(crate) struct ObjectLifetimeErr {
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_unrecognized_repr_hint, code = E0552)]
-#[help]
-pub(crate) struct UnrecognizedReprHint {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 pub(crate) enum AttrApplication {
     #[diag(passes_attr_application_enum, code = E0517)]
     Enum {
@@ -1902,3 +1862,11 @@ pub(crate) struct NoSanitize<'a> {
     pub accepted_kind: &'a str,
     pub attr_str: &'a str,
 }
+
+// FIXME(jdonszelmann): move back to rustc_attr
+#[derive(Diagnostic)]
+#[diag(passes_rustc_const_stable_indirect_pairing)]
+pub(crate) struct RustcConstStableIndirectPairing {
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs
index e123fbac1be..7353c1ead5a 100644
--- a/compiler/rustc_passes/src/lib_features.rs
+++ b/compiler/rustc_passes/src/lib_features.rs
@@ -4,7 +4,7 @@
 //! but are not declared in one single location (unlike lang features), which means we need to
 //! collect them instead.
 
-use rustc_attr_parsing::VERSION_PLACEHOLDER;
+use rustc_attr_parsing::{AttributeKind, StabilityLevel, StableSince};
 use rustc_hir::Attribute;
 use rustc_hir::intravisit::Visitor;
 use rustc_middle::hir::nested_filter;
@@ -26,62 +26,29 @@ impl<'tcx> LibFeatureCollector<'tcx> {
     }
 
     fn extract(&self, attr: &Attribute) -> Option<(Symbol, FeatureStability, Span)> {
-        let stab_attrs = [
-            sym::stable,
-            sym::unstable,
-            sym::rustc_const_stable,
-            sym::rustc_const_unstable,
-            sym::rustc_default_body_unstable,
-        ];
-
-        // Find a stability attribute: one of #[stable(…)], #[unstable(…)],
-        // #[rustc_const_stable(…)], #[rustc_const_unstable(…)] or #[rustc_default_body_unstable].
-        if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| attr.has_name(**stab_attr)) {
-            if let Some(metas) = attr.meta_item_list() {
-                let mut feature = None;
-                let mut since = None;
-                for meta in metas {
-                    if let Some(mi) = meta.meta_item() {
-                        // Find the `feature = ".."` meta-item.
-                        match (mi.name_or_empty(), mi.value_str()) {
-                            (sym::feature, val) => feature = val,
-                            (sym::since, val) => since = val,
-                            _ => {}
-                        }
-                    }
-                }
-
-                if let Some(s) = since
-                    && s.as_str() == VERSION_PLACEHOLDER
-                {
-                    since = Some(sym::env_CFG_RELEASE);
-                }
-
-                if let Some(feature) = feature {
-                    // This additional check for stability is to make sure we
-                    // don't emit additional, irrelevant errors for malformed
-                    // attributes.
-                    let is_unstable = matches!(
-                        *stab_attr,
-                        sym::unstable
-                            | sym::rustc_const_unstable
-                            | sym::rustc_default_body_unstable
-                    );
-                    if is_unstable {
-                        return Some((feature, FeatureStability::Unstable, attr.span));
-                    }
-                    if let Some(since) = since {
-                        return Some((feature, FeatureStability::AcceptedSince(since), attr.span));
-                    }
-                }
-                // We need to iterate over the other attributes, because
-                // `rustc_const_unstable` is not mutually exclusive with
-                // the other stability attributes, so we can't just `break`
-                // here.
+        let (feature, level, span) = match attr {
+            Attribute::Parsed(AttributeKind::Stability { stability, span }) => {
+                (stability.feature, stability.level, *span)
             }
-        }
-
-        None
+            Attribute::Parsed(AttributeKind::ConstStability { stability, span }) => {
+                (stability.feature, stability.level, *span)
+            }
+            Attribute::Parsed(AttributeKind::BodyStability { stability, span }) => {
+                (stability.feature, stability.level, *span)
+            }
+            _ => return None,
+        };
+
+        let feature_stability = match level {
+            StabilityLevel::Unstable { .. } => FeatureStability::Unstable,
+            StabilityLevel::Stable { since, .. } => FeatureStability::AcceptedSince(match since {
+                StableSince::Version(v) => Symbol::intern(&v.to_string()),
+                StableSince::Current => sym::env_CFG_RELEASE,
+                StableSince::Err => return None,
+            }),
+        };
+
+        Some((feature, feature_stability, span))
     }
 
     fn collect_feature(&mut self, feature: Symbol, stability: FeatureStability, span: Span) {
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index d92edf959af..8a4bdf3875c 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -6,8 +6,8 @@ use std::num::NonZero;
 
 use rustc_ast_lowering::stability::extern_abi_stability;
 use rustc_attr_parsing::{
-    self as attr, ConstStability, DeprecatedSince, Stability, StabilityLevel, StableSince,
-    UnstableReason, VERSION_PLACEHOLDER,
+    self as attr, AttributeKind, ConstStability, DeprecatedSince, PartialConstStability, Stability,
+    StabilityLevel, StableSince, UnstableReason, VERSION_PLACEHOLDER, find_attr,
 };
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::unord::{ExtendUnord, UnordMap, UnordSet};
@@ -121,7 +121,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
         let attrs = self.tcx.hir().attrs(self.tcx.local_def_id_to_hir_id(def_id));
         debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs);
 
-        let depr = attr::find_deprecation(self.tcx.sess, self.tcx.features(), attrs);
+        let depr = attr::find_attr!(attrs, AttributeKind::Deprecation{deprecation, span} => (*deprecation, *span));
+        let const_stability_indirect = find_attr!(attrs, AttributeKind::ConstStabilityIndirect);
+
         let mut is_deprecated = false;
         if let Some((depr, span)) = &depr {
             is_deprecated = true;
@@ -154,9 +156,10 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
                 if inherit_deprecation.yes() && stab.is_unstable() {
                     self.index.stab_map.insert(def_id, stab);
                     if fn_sig.is_some_and(|s| s.header.is_const()) {
-                        let const_stab =
-                            attr::unmarked_crate_const_stab(self.tcx.sess, attrs, stab);
-                        self.index.const_stab_map.insert(def_id, const_stab);
+                        self.index.const_stab_map.insert(
+                            def_id,
+                            ConstStability::unmarked(const_stability_indirect, stab),
+                        );
                     }
                 }
             }
@@ -171,9 +174,9 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
         }
 
         // # Regular and body stability
-
-        let stab = attr::find_stability(self.tcx.sess, attrs, item_sp);
-        let body_stab = attr::find_body_stability(self.tcx.sess, attrs);
+        let stab = attr::find_attr!(attrs, AttributeKind::Stability { stability, span } => (*stability, *span));
+        let body_stab =
+            attr::find_attr!(attrs, AttributeKind::BodyStability { stability, .. } => *stability);
 
         if let Some((depr, span)) = &depr
             && depr.is_since_rustc_version()
@@ -182,7 +185,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
             self.tcx.dcx().emit_err(errors::DeprecatedAttribute { span: *span });
         }
 
-        if let Some((body_stab, _span)) = body_stab {
+        if let Some(body_stab) = body_stab {
             // FIXME: check that this item can have body stability
 
             self.index.default_body_stab_map.insert(def_id, body_stab);
@@ -260,10 +263,10 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
 
         // # Const stability
 
-        let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item_sp);
+        let const_stab = attr::find_attr!(attrs, AttributeKind::ConstStability { stability, span } => (*stability, *span));
 
         // If the current node is a function with const stability attributes (directly given or
-        // implied), check if the function/method is const.
+        // implied), check if the function/method is const or the parent impl block is const.
         if let Some(fn_sig) = fn_sig
             && !fn_sig.header.is_const()
             && const_stab.is_some()
@@ -285,7 +288,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
         // Stable *language* features shouldn't be used as unstable library features.
         // (Not doing this for stable library features is checked by tidy.)
         if let Some((
-            ConstStability { level: StabilityLevel::Unstable { .. }, feature, .. },
+            PartialConstStability { level: StabilityLevel::Unstable { .. }, feature, .. },
             const_span,
         )) = const_stab
         {
@@ -297,9 +300,17 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
             }
         }
 
+        if let Some((stab, span)) = &const_stab
+            && stab.is_const_stable()
+            && const_stability_indirect
+        {
+            self.tcx.dcx().emit_err(errors::RustcConstStableIndirectPairing { span: *span });
+        }
+
         // After checking the immediate attributes, get rid of the span and compute implied
         // const stability: inherit feature gate from regular stability.
-        let mut const_stab = const_stab.map(|(stab, _span)| stab);
+        let mut const_stab = const_stab
+            .map(|(stab, _span)| ConstStability::from_partial(stab, const_stability_indirect));
 
         // If this is a const fn but not annotated with stability markers, see if we can inherit regular stability.
         if fn_sig.is_some_and(|s| s.header.is_const())  && const_stab.is_none() &&
@@ -785,8 +796,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                 let features = self.tcx.features();
                 if features.staged_api() {
                     let attrs = self.tcx.hir().attrs(item.hir_id());
-                    let stab = attr::find_stability(self.tcx.sess, attrs, item.span);
-                    let const_stab = attr::find_const_stability(self.tcx.sess, attrs, item.span);
+                    let stab = attr::find_attr!(attrs, AttributeKind::Stability{stability, span} => (*stability, *span));
+
+                    // FIXME(jdonszelmann): make it impossible to miss the or_else in the typesystem
+                    let const_stab = attr::find_attr!(attrs, AttributeKind::ConstStability{stability, ..} => *stability);
 
                     // If this impl block has an #[unstable] attribute, give an
                     // error if all involved types and traits are stable, because
@@ -817,7 +830,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                     // needs to have an error emitted.
                     if features.const_trait_impl()
                         && self.tcx.is_const_trait_impl(item.owner_id.to_def_id())
-                        && const_stab.is_some_and(|(stab, _)| stab.is_const_stable())
+                        && const_stab.is_some_and(|stab| stab.is_const_stable())
                     {
                         self.tcx.dcx().emit_err(errors::TraitImplConstStable { span: item.span });
                     }
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 41725d0c6a4..5271d03a6f6 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -22,6 +22,7 @@ use errors::{
 };
 use rustc_ast::MacroDef;
 use rustc_ast::visit::{VisitorResult, try_visit};
+use rustc_attr_parsing::AttributeKind;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::intern::Interned;
 use rustc_errors::{MultiSpan, listify};
@@ -493,7 +494,11 @@ impl<'tcx> EmbargoVisitor<'tcx> {
         // Non-opaque macros cannot make other items more accessible than they already are.
         let hir_id = self.tcx.local_def_id_to_hir_id(local_def_id);
         let attrs = self.tcx.hir().attrs(hir_id);
-        if attr::find_transparency(attrs, md.macro_rules).0 != Transparency::Opaque {
+
+        if attr::find_attr!(attrs, AttributeKind::MacroTransparency(x) => *x)
+            .unwrap_or(Transparency::fallback(md.macro_rules))
+            != Transparency::Opaque
+        {
             return;
         }
 
diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml
index d89e1355ca6..c85156e059e 100644
--- a/compiler/rustc_query_impl/Cargo.toml
+++ b/compiler/rustc_query_impl/Cargo.toml
@@ -6,6 +6,7 @@ edition = "2024"
 [dependencies]
 # tidy-alphabetical-start
 measureme = "11"
+rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_hashes = { path = "../rustc_hashes" }
diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml
index 839465f9273..3e8ccb51021 100644
--- a/compiler/rustc_query_system/Cargo.toml
+++ b/compiler/rustc_query_system/Cargo.toml
@@ -9,6 +9,7 @@ parking_lot = "0.12"
 rustc-rayon-core = { version = "0.5.0" }
 rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
+rustc_attr_data_structures = { path = "../rustc_attr_data_structures" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_feature = { path = "../rustc_feature" }
diff --git a/compiler/rustc_query_system/src/ich/hcx.rs b/compiler/rustc_query_system/src/ich/hcx.rs
index cf50e61e72b..e1b6adc6cc1 100644
--- a/compiler/rustc_query_system/src/ich/hcx.rs
+++ b/compiler/rustc_query_system/src/ich/hcx.rs
@@ -129,3 +129,4 @@ impl<'a> rustc_span::HashStableContext for StableHashingContext<'a> {
 }
 
 impl<'a> rustc_session::HashStableContext for StableHashingContext<'a> {}
+impl<'a> rustc_attr_data_structures::HashStableContext for StableHashingContext<'a> {}
diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs
index 7d508b8201b..1dcd5d9058f 100644
--- a/compiler/rustc_query_system/src/ich/impls_syntax.rs
+++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs
@@ -2,7 +2,7 @@
 //! from various crates in no particular order.
 
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_hir as hir;
+use rustc_hir::{self as hir, HashIgnoredAttrId};
 use rustc_span::SourceFile;
 use smallvec::SmallVec;
 
@@ -23,6 +23,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for [hir::Attribute] {
             .iter()
             .filter(|attr| {
                 !attr.is_doc_comment()
+                    // FIXME(jdonszelmann) have a better way to handle ignored attrs
                     && !attr.ident().is_some_and(|ident| hcx.is_ignored_attr(ident.name))
             })
             .collect();
@@ -35,19 +36,8 @@ impl<'a> HashStable<StableHashingContext<'a>> for [hir::Attribute] {
 }
 
 impl<'ctx> rustc_hir::HashStableContext for StableHashingContext<'ctx> {
-    fn hash_attr(&mut self, attr: &hir::Attribute, hasher: &mut StableHasher) {
-        // Make sure that these have been filtered out.
-        debug_assert!(!attr.ident().is_some_and(|ident| self.is_ignored_attr(ident.name)));
-        debug_assert!(!attr.is_doc_comment());
-
-        let hir::Attribute { kind, id: _, style, span } = attr;
-        if let hir::AttrKind::Normal(item) = kind {
-            item.hash_stable(self, hasher);
-            style.hash_stable(self, hasher);
-            span.hash_stable(self, hasher);
-        } else {
-            unreachable!();
-        }
+    fn hash_attr_id(&mut self, _id: &HashIgnoredAttrId, _hasher: &mut StableHasher) {
+        /* we don't hash HashIgnoredAttrId, we ignore them */
     }
 }
 
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 5eb8e420fa4..75972a71c8e 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -3,6 +3,7 @@ use std::mem;
 use rustc_ast::visit::FnKind;
 use rustc_ast::*;
 use rustc_ast_pretty::pprust;
+use rustc_attr_parsing::{AttributeParser, OmitDoc};
 use rustc_expand::expand::AstFragment;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind};
@@ -132,8 +133,24 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
             ItemKind::Fn(..) | ItemKind::Delegation(..) => DefKind::Fn,
             ItemKind::MacroDef(def) => {
                 let edition = i.span.edition();
+
+                // FIXME(jdonszelmann) make one of these in the resolver?
+                // FIXME(jdonszelmann) don't care about tools here maybe? Just parse what we can.
+                // Does that prevents errors from happening? maybe
+                let parser = AttributeParser::new(
+                    &self.resolver.tcx.sess,
+                    self.resolver.tcx.features(),
+                    Vec::new(),
+                );
+                let attrs = parser.parse_attribute_list(
+                    &i.attrs,
+                    i.span,
+                    OmitDoc::Skip,
+                    std::convert::identity,
+                );
+
                 let macro_data =
-                    self.resolver.compile_macro(def, i.ident, &i.attrs, i.span, i.id, edition);
+                    self.resolver.compile_macro(def, i.ident, &attrs, i.span, i.id, edition);
                 let macro_kind = macro_data.ext.macro_kind();
                 opt_macro_data = Some(macro_data);
                 DefKind::Macro(macro_kind)
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 5db6f83f3ee..55db336d85f 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -1806,7 +1806,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
             && !def_id.is_local()
             && let Some(attr) = self.tcx.get_attr(def_id, sym::non_exhaustive)
         {
-            non_exhaustive = Some(attr.span);
+            non_exhaustive = Some(attr.span());
         } else if let Some(span) = ctor_fields_span {
             let label = errors::ConstructorPrivateIfAnyFieldPrivate { span };
             err.subdiagnostic(label);
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index a70def2f6c9..984dfff3ea5 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -5,7 +5,6 @@ use std::cell::Cell;
 use std::mem;
 use std::sync::Arc;
 
-use rustc_ast::attr::AttributeExt;
 use rustc_ast::expand::StrippedCfgItem;
 use rustc_ast::{self as ast, Crate, NodeId, attr};
 use rustc_ast_pretty::pprust;
@@ -1112,7 +1111,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
         &mut self,
         macro_def: &ast::MacroDef,
         ident: Ident,
-        attrs: &[impl AttributeExt],
+        attrs: &[rustc_hir::Attribute],
         span: Span,
         node_id: NodeId,
         edition: Edition,
diff --git a/compiler/rustc_sanitizers/Cargo.toml b/compiler/rustc_sanitizers/Cargo.toml
index 66488bc9625..900cd4243b1 100644
--- a/compiler/rustc_sanitizers/Cargo.toml
+++ b/compiler/rustc_sanitizers/Cargo.toml
@@ -8,6 +8,7 @@ bitflags = "2.5.0"
 tracing = "0.1"
 twox-hash = "1.6.3"
 rustc_abi = { path = "../rustc_abi" }
+rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_hir = { path = "../rustc_hir" }
 rustc_middle = { path = "../rustc_middle" }
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
index 5f0c1afdf64..e088417d72e 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs
@@ -468,7 +468,7 @@ pub(crate) fn encode_ty<'tcx>(
                         )]
                         tcx.dcx()
                             .struct_span_err(
-                                cfi_encoding.span,
+                                cfi_encoding.span(),
                                 format!("invalid `cfi_encoding` for `{:?}`", ty.kind()),
                             )
                             .emit();
@@ -519,7 +519,7 @@ pub(crate) fn encode_ty<'tcx>(
                         )]
                         tcx.dcx()
                             .struct_span_err(
-                                cfi_encoding.span,
+                                cfi_encoding.span(),
                                 format!("invalid `cfi_encoding` for `{:?}`", ty.kind()),
                             )
                             .emit();
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
index 71e7b9c04ca..acd3b758351 100644
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -9,7 +9,7 @@ use std::cell::RefCell;
 use std::iter;
 
 use rustc_abi::HasDataLayout;
-use rustc_hir::LangItem;
+use rustc_hir::{Attribute, LangItem};
 use rustc_middle::ty::layout::{
     FnAbiOf, FnAbiOfHelpers, HasTyCtxt, HasTypingEnv, LayoutOf, LayoutOfHelpers,
 };
@@ -243,7 +243,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         }
     }
 
-    fn get_attrs_by_path(
+    fn tool_attrs(
         &self,
         def_id: stable_mir::DefId,
         attr: &[stable_mir::Symbol],
@@ -253,30 +253,40 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
         let did = tables[def_id];
         let attr_name: Vec<_> = attr.iter().map(|seg| rustc_span::Symbol::intern(&seg)).collect();
         tcx.get_attrs_by_path(did, &attr_name)
-            .map(|attribute| {
-                let attr_str = rustc_hir_pretty::attribute_to_string(&tcx, attribute);
-                let span = attribute.span;
-                stable_mir::crate_def::Attribute::new(attr_str, span.stable(&mut *tables))
+            .filter_map(|attribute| {
+                if let Attribute::Unparsed(u) = attribute {
+                    let attr_str = rustc_hir_pretty::attribute_to_string(&tcx, attribute);
+                    Some(stable_mir::crate_def::Attribute::new(
+                        attr_str,
+                        u.span.stable(&mut *tables),
+                    ))
+                } else {
+                    None
+                }
             })
             .collect()
     }
 
-    fn get_all_attrs(&self, def_id: stable_mir::DefId) -> Vec<stable_mir::crate_def::Attribute> {
+    fn all_tool_attrs(&self, def_id: stable_mir::DefId) -> Vec<stable_mir::crate_def::Attribute> {
         let mut tables = self.0.borrow_mut();
         let tcx = tables.tcx;
         let did = tables[def_id];
-        let filter_fn =
-            move |a: &&rustc_hir::Attribute| matches!(a.kind, rustc_hir::AttrKind::Normal(_));
         let attrs_iter = if let Some(did) = did.as_local() {
-            tcx.hir().attrs(tcx.local_def_id_to_hir_id(did)).iter().filter(filter_fn)
+            tcx.hir().attrs(tcx.local_def_id_to_hir_id(did)).iter()
         } else {
-            tcx.attrs_for_def(did).iter().filter(filter_fn)
+            tcx.attrs_for_def(did).iter()
         };
         attrs_iter
-            .map(|attribute| {
-                let attr_str = rustc_hir_pretty::attribute_to_string(&tcx, attribute);
-                let span = attribute.span;
-                stable_mir::crate_def::Attribute::new(attr_str, span.stable(&mut *tables))
+            .filter_map(|attribute| {
+                if let Attribute::Unparsed(u) = attribute {
+                    let attr_str = rustc_hir_pretty::attribute_to_string(&tcx, attribute);
+                    Some(stable_mir::crate_def::Attribute::new(
+                        attr_str,
+                        u.span.stable(&mut *tables),
+                    ))
+                } else {
+                    None
+                }
             })
             .collect()
     }
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 9bf1d305e54..84e89ff4b7d 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -175,6 +175,12 @@ pub enum Transparency {
     Opaque,
 }
 
+impl Transparency {
+    pub fn fallback(macro_rules: bool) -> Self {
+        if macro_rules { Transparency::SemiTransparent } else { Transparency::Opaque }
+    }
+}
+
 impl LocalExpnId {
     /// The ID of the theoretical expansion that generates freshly parsed, unexpanded AST.
     pub const ROOT: LocalExpnId = LocalExpnId::ZERO;
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 10c79b1be82..172c2faca96 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1764,7 +1764,6 @@ symbols! {
         rustc_insignificant_dtor,
         rustc_intrinsic,
         rustc_intrinsic_const_stable_indirect,
-        rustc_intrinsic_must_be_overridden,
         rustc_layout,
         rustc_layout_scalar_valid_range_end,
         rustc_layout_scalar_valid_range_start,
@@ -1916,7 +1915,7 @@ symbols! {
         simd_shl,
         simd_shr,
         simd_shuffle,
-        simd_shuffle_generic,
+        simd_shuffle_const_generic,
         simd_sub,
         simd_trunc,
         simd_with_exposed_provenance,
diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml
index 12fe6b719f9..90ddf4c8a04 100644
--- a/compiler/rustc_symbol_mangling/Cargo.toml
+++ b/compiler/rustc_symbol_mangling/Cargo.toml
@@ -9,6 +9,7 @@ punycode = "0.4.0"
 rustc-demangle = "0.1.21"
 
 rustc_abi = { path = "../rustc_abi" }
+rustc_ast = { path = "../rustc_ast" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
 rustc_hashes = { path = "../rustc_hashes" }
diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs
index 7fda81126c4..ddeeadff13d 100644
--- a/compiler/rustc_symbol_mangling/src/test.rs
+++ b/compiler/rustc_symbol_mangling/src/test.rs
@@ -62,18 +62,18 @@ impl SymbolNamesTest<'_> {
             );
             let mangled = tcx.symbol_name(instance);
             tcx.dcx().emit_err(TestOutput {
-                span: attr.span,
+                span: attr.span(),
                 kind: Kind::SymbolName,
                 content: format!("{mangled}"),
             });
             if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) {
                 tcx.dcx().emit_err(TestOutput {
-                    span: attr.span,
+                    span: attr.span(),
                     kind: Kind::Demangling,
                     content: format!("{demangling}"),
                 });
                 tcx.dcx().emit_err(TestOutput {
-                    span: attr.span,
+                    span: attr.span(),
                     kind: Kind::DemanglingAlt,
                     content: format!("{demangling:#}"),
                 });
@@ -82,7 +82,7 @@ impl SymbolNamesTest<'_> {
 
         for attr in tcx.get_attrs(def_id, DEF_PATH) {
             tcx.dcx().emit_err(TestOutput {
-                span: attr.span,
+                span: attr.span(),
                 kind: Kind::DefPath,
                 content: with_no_trimmed_paths!(tcx.def_path_str(def_id)),
             });
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index b98bca60c9d..65a85151bef 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -497,9 +497,14 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     ("relax", Unstable(sym::riscv_target_feature), &[]),
     ("unaligned-scalar-mem", Unstable(sym::riscv_target_feature), &[]),
     ("v", Unstable(sym::riscv_target_feature), &[]),
+    ("za128rs", Unstable(sym::riscv_target_feature), &[]),
+    ("za64rs", Unstable(sym::riscv_target_feature), &[]),
     ("zaamo", Unstable(sym::riscv_target_feature), &[]),
     ("zabha", Unstable(sym::riscv_target_feature), &["zaamo"]),
+    ("zacas", Unstable(sym::riscv_target_feature), &["zaamo"]),
     ("zalrsc", Unstable(sym::riscv_target_feature), &[]),
+    ("zama16b", Unstable(sym::riscv_target_feature), &[]),
+    ("zawrs", Unstable(sym::riscv_target_feature), &[]),
     ("zba", Stable, &[]),
     ("zbb", Stable, &[]),
     ("zbc", Stable, &[]),
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 36726cc6cae..514615735a5 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
@@ -522,7 +522,8 @@ impl<T> Trait<T> for X {
                 }
             }
             TypeError::TargetFeatureCast(def_id) => {
-                let target_spans = tcx.get_attrs(def_id, sym::target_feature).map(|attr| attr.span);
+                let target_spans =
+                    tcx.get_attrs(def_id, sym::target_feature).map(|attr| attr.span());
                 diag.note(
                     "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers"
                 );
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
index 518323f6526..f0c6e51f2a4 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
@@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::codes::*;
 use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::{AttrArgs, AttrKind, Attribute};
+use rustc_hir::{AttrArgs, Attribute};
 use rustc_macros::LintDiagnostic;
 use rustc_middle::bug;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
@@ -622,7 +622,14 @@ impl<'tcx> OnUnimplementedDirective {
         item_def_id: DefId,
     ) -> Result<Option<Self>, ErrorGuaranteed> {
         let result = if let Some(items) = attr.meta_item_list() {
-            Self::parse(tcx, item_def_id, &items, attr.span, true, is_diagnostic_namespace_variant)
+            Self::parse(
+                tcx,
+                item_def_id,
+                &items,
+                attr.span(),
+                true,
+                is_diagnostic_namespace_variant,
+            )
         } else if let Some(value) = attr.value_str() {
             if !is_diagnostic_namespace_variant {
                 Ok(Some(OnUnimplementedDirective {
@@ -633,7 +640,7 @@ impl<'tcx> OnUnimplementedDirective {
                         tcx,
                         item_def_id,
                         value,
-                        attr.span,
+                        attr.span(),
                         is_diagnostic_namespace_variant,
                     )?),
                     notes: Vec::new(),
@@ -659,14 +666,14 @@ impl<'tcx> OnUnimplementedDirective {
                 Ok(None)
             }
         } else if is_diagnostic_namespace_variant {
-            match &attr.kind {
-                AttrKind::Normal(p) if !matches!(p.args, AttrArgs::Empty) => {
+            match attr {
+                Attribute::Unparsed(p) if !matches!(p.args, AttrArgs::Empty) => {
                     if let Some(item_def_id) = item_def_id.as_local() {
                         tcx.emit_node_span_lint(
                             UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
                             tcx.local_def_id_to_hir_id(item_def_id),
-                            attr.span,
-                            MalformedOnUnimplementedAttrLint::new(attr.span),
+                            attr.span(),
+                            MalformedOnUnimplementedAttrLint::new(attr.span()),
                         );
                     }
                 }
@@ -675,7 +682,7 @@ impl<'tcx> OnUnimplementedDirective {
                         tcx.emit_node_span_lint(
                             UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
                             tcx.local_def_id_to_hir_id(item_def_id),
-                            attr.span,
+                            attr.span(),
                             MissingOptionsForOnUnimplementedAttr,
                         )
                     }
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index 740f44ebcad..d4502be6ccf 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -538,10 +538,10 @@ fn receiver_for_self_ty<'tcx>(
 /// a pointer.
 ///
 /// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result in
-/// a new check that `Trait` is dyn-compatible, creating a cycle (until dyn_compatible_for_dispatch
-/// is stabilized, see tracking issue <https://github.com/rust-lang/rust/issues/43561>).
-/// Instead, we fudge a little by introducing a new type parameter `U` such that
+/// a new check that `Trait` is dyn-compatible, creating a cycle.
+/// Instead, we emulate a placeholder by introducing a new type parameter `U` such that
 /// `Self: Unsize<U>` and `U: Trait + ?Sized`, and use `U` in place of `dyn Trait`.
+///
 /// Written as a chalk-style query:
 /// ```ignore (not-rust)
 /// forall (U: Trait + ?Sized) {
@@ -572,8 +572,6 @@ fn receiver_is_dispatchable<'tcx>(
 
     // the type `U` in the query
     // use a bogus type parameter to mimic a forall(U) query using u32::MAX for now.
-    // FIXME(mikeyhew) this is a total hack. Once dyn_compatible_for_dispatch is stabilized, we can
-    // replace this with `dyn Trait`
     let unsized_self_ty: Ty<'tcx> =
         Ty::new_param(tcx, u32::MAX, rustc_span::sym::RustaceansAreAwesome);
 
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 5b362b2356e..11b6b826efe 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -859,13 +859,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         }
 
                         if let Some(principal) = data.principal() {
-                            if !self.infcx.tcx.features().dyn_compatible_for_dispatch() {
-                                principal.with_self_ty(self.tcx(), self_ty)
-                            } else if self.tcx().is_dyn_compatible(principal.def_id()) {
-                                principal.with_self_ty(self.tcx(), self_ty)
-                            } else {
-                                return;
-                            }
+                            principal.with_self_ty(self.tcx(), self_ty)
                         } else {
                             // Only auto trait bounds exist.
                             return;
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 7f3e3ce4781..18906a6a8ce 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -904,19 +904,14 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
                 // FIXME(#27579) RFC also considers adding trait
                 // obligations that don't refer to Self and
                 // checking those
-
-                let defer_to_coercion = tcx.features().dyn_compatible_for_dispatch();
-
-                if !defer_to_coercion {
-                    if let Some(principal) = data.principal_def_id() {
-                        self.out.push(traits::Obligation::with_depth(
-                            tcx,
-                            self.cause(ObligationCauseCode::WellFormed(None)),
-                            self.recursion_depth,
-                            self.param_env,
-                            ty::Binder::dummy(ty::PredicateKind::DynCompatible(principal)),
-                        ));
-                    }
+                if let Some(principal) = data.principal_def_id() {
+                    self.out.push(traits::Obligation::with_depth(
+                        tcx,
+                        self.cause(ObligationCauseCode::WellFormed(None)),
+                        self.recursion_depth,
+                        self.param_env,
+                        ty::Binder::dummy(ty::PredicateKind::DynCompatible(principal)),
+                    ));
                 }
             }
 
diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs
index a6f7c254583..e82c957c34e 100644
--- a/compiler/stable_mir/src/compiler_interface.rs
+++ b/compiler/stable_mir/src/compiler_interface.rs
@@ -62,14 +62,17 @@ pub trait Context {
     /// Returns the name of given `DefId`
     fn def_name(&self, def_id: DefId, trimmed: bool) -> Symbol;
 
-    /// Return attributes with the given attribute name.
+    /// Return registered tool attributes with the given attribute name.
     ///
-    /// Single segmented name like `#[inline]` is specified as `&["inline".to_string()]`.
+    /// FIXME(jdonszelmann): may panic on non-tool attributes. After more attribute work, non-tool
+    /// attributes will simply return an empty list.
+    ///
+    /// Single segmented name like `#[clippy]` is specified as `&["clippy".to_string()]`.
     /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`.
-    fn get_attrs_by_path(&self, def_id: DefId, attr: &[Symbol]) -> Vec<Attribute>;
+    fn tool_attrs(&self, def_id: DefId, attr: &[Symbol]) -> Vec<Attribute>;
 
-    /// Get all attributes of a definition.
-    fn get_all_attrs(&self, def_id: DefId) -> Vec<Attribute>;
+    /// Get all tool attributes of a definition.
+    fn all_tool_attrs(&self, def_id: DefId) -> Vec<Attribute>;
 
     /// Returns printable, human readable form of `Span`
     fn span_to_string(&self, span: Span) -> String;
diff --git a/compiler/stable_mir/src/crate_def.rs b/compiler/stable_mir/src/crate_def.rs
index cf29176dbbd..8c6fd99f98a 100644
--- a/compiler/stable_mir/src/crate_def.rs
+++ b/compiler/stable_mir/src/crate_def.rs
@@ -53,19 +53,22 @@ pub trait CrateDef {
         with(|cx| cx.span_of_an_item(def_id))
     }
 
-    /// Return attributes with the given attribute name.
+    /// Return registered tool attributes with the given attribute name.
     ///
-    /// Single segmented name like `#[inline]` is specified as `&["inline".to_string()]`.
+    /// FIXME(jdonszelmann): may panic on non-tool attributes. After more attribute work, non-tool
+    /// attributes will simply return an empty list.
+    ///
+    /// Single segmented name like `#[clippy]` is specified as `&["clippy".to_string()]`.
     /// Multi-segmented name like `#[rustfmt::skip]` is specified as `&["rustfmt".to_string(), "skip".to_string()]`.
-    fn attrs_by_path(&self, attr: &[Symbol]) -> Vec<Attribute> {
+    fn tool_attrs(&self, attr: &[Symbol]) -> Vec<Attribute> {
         let def_id = self.def_id();
-        with(|cx| cx.get_attrs_by_path(def_id, attr))
+        with(|cx| cx.tool_attrs(def_id, attr))
     }
 
-    /// Return all attributes of this definition.
-    fn all_attrs(&self) -> Vec<Attribute> {
+    /// Return all tool attributes of this definition.
+    fn all_tool_attrs(&self) -> Vec<Attribute> {
         let def_id = self.def_id();
-        with(|cx| cx.get_all_attrs(def_id))
+        with(|cx| cx.all_tool_attrs(def_id))
     }
 }
 
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index e2a55d31395..c3f5806e1aa 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -238,11 +238,8 @@ pub struct Box<
 ///
 /// This is the surface syntax for `box <expr>` expressions.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[unstable(feature = "liballoc_internals", issue = "none")]
-pub fn box_new<T>(_x: T) -> Box<T> {
-    unreachable!()
-}
+pub fn box_new<T>(_x: T) -> Box<T>;
 
 impl<T> Box<T> {
     /// Allocates memory on the heap and then places `x` into it.
diff --git a/library/core/src/ffi/va_list.rs b/library/core/src/ffi/va_list.rs
index cceb186b31e..cefa0e3950c 100644
--- a/library/core/src/ffi/va_list.rs
+++ b/library/core/src/ffi/va_list.rs
@@ -305,25 +305,16 @@ impl<'f> Drop for VaListImpl<'f> {
 /// Destroy the arglist `ap` after initialization with `va_start` or
 /// `va_copy`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-unsafe fn va_end(_ap: &mut VaListImpl<'_>) {
-    unreachable!()
-}
+unsafe fn va_end(_ap: &mut VaListImpl<'_>);
 
 /// Copies the current location of arglist `src` to the arglist `dst`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-unsafe fn va_copy<'f>(_dest: *mut VaListImpl<'f>, _src: &VaListImpl<'f>) {
-    unreachable!()
-}
+unsafe fn va_copy<'f>(_dest: *mut VaListImpl<'f>, _src: &VaListImpl<'f>);
 
 /// Loads an argument of type `T` from the `va_list` `ap` and increment the
 /// argument `ap` points to.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-unsafe fn va_arg<T: sealed_trait::VaArgSafe>(_ap: &mut VaListImpl<'_>) -> T {
-    unreachable!()
-}
+unsafe fn va_arg<T: sealed_trait::VaArgSafe>(_ap: &mut VaListImpl<'_>) -> T;
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index ae2b3b92b82..38a60338e74 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -96,11 +96,8 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
 /// [`Ordering::Relaxed`] as both the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchg_relaxed_relaxed<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchg_relaxed_relaxed<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -108,11 +105,8 @@ pub unsafe fn atomic_cxchg_relaxed_relaxed<T: Copy>(_dst: *mut T, _old: T, _src:
 /// [`Ordering::Relaxed`] and [`Ordering::Acquire`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchg_relaxed_acquire<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchg_relaxed_acquire<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -120,11 +114,8 @@ pub unsafe fn atomic_cxchg_relaxed_acquire<T: Copy>(_dst: *mut T, _old: T, _src:
 /// [`Ordering::Relaxed`] and [`Ordering::SeqCst`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchg_relaxed_seqcst<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchg_relaxed_seqcst<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -132,11 +123,8 @@ pub unsafe fn atomic_cxchg_relaxed_seqcst<T: Copy>(_dst: *mut T, _old: T, _src:
 /// [`Ordering::Acquire`] and [`Ordering::Relaxed`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchg_acquire_relaxed<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchg_acquire_relaxed<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -144,11 +132,8 @@ pub unsafe fn atomic_cxchg_acquire_relaxed<T: Copy>(_dst: *mut T, _old: T, _src:
 /// [`Ordering::Acquire`] as both the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchg_acquire_acquire<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchg_acquire_acquire<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -156,11 +141,8 @@ pub unsafe fn atomic_cxchg_acquire_acquire<T: Copy>(_dst: *mut T, _old: T, _src:
 /// [`Ordering::Acquire`] and [`Ordering::SeqCst`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchg_acquire_seqcst<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchg_acquire_seqcst<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -168,11 +150,8 @@ pub unsafe fn atomic_cxchg_acquire_seqcst<T: Copy>(_dst: *mut T, _old: T, _src:
 /// [`Ordering::Release`] and [`Ordering::Relaxed`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchg_release_relaxed<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchg_release_relaxed<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -180,11 +159,8 @@ pub unsafe fn atomic_cxchg_release_relaxed<T: Copy>(_dst: *mut T, _old: T, _src:
 /// [`Ordering::Release`] and [`Ordering::Acquire`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchg_release_acquire<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchg_release_acquire<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -192,11 +168,8 @@ pub unsafe fn atomic_cxchg_release_acquire<T: Copy>(_dst: *mut T, _old: T, _src:
 /// [`Ordering::Release`] and [`Ordering::SeqCst`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchg_release_seqcst<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchg_release_seqcst<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -204,11 +177,8 @@ pub unsafe fn atomic_cxchg_release_seqcst<T: Copy>(_dst: *mut T, _old: T, _src:
 /// [`Ordering::AcqRel`] and [`Ordering::Relaxed`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchg_acqrel_relaxed<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchg_acqrel_relaxed<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -216,11 +186,8 @@ pub unsafe fn atomic_cxchg_acqrel_relaxed<T: Copy>(_dst: *mut T, _old: T, _src:
 /// [`Ordering::AcqRel`] and [`Ordering::Acquire`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchg_acqrel_acquire<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchg_acqrel_acquire<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -228,11 +195,8 @@ pub unsafe fn atomic_cxchg_acqrel_acquire<T: Copy>(_dst: *mut T, _old: T, _src:
 /// [`Ordering::AcqRel`] and [`Ordering::SeqCst`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchg_acqrel_seqcst<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchg_acqrel_seqcst<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -240,11 +204,8 @@ pub unsafe fn atomic_cxchg_acqrel_seqcst<T: Copy>(_dst: *mut T, _old: T, _src: T
 /// [`Ordering::SeqCst`] and [`Ordering::Relaxed`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchg_seqcst_relaxed<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchg_seqcst_relaxed<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -252,11 +213,8 @@ pub unsafe fn atomic_cxchg_seqcst_relaxed<T: Copy>(_dst: *mut T, _old: T, _src:
 /// [`Ordering::SeqCst`] and [`Ordering::Acquire`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchg_seqcst_acquire<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchg_seqcst_acquire<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -264,11 +222,8 @@ pub unsafe fn atomic_cxchg_seqcst_acquire<T: Copy>(_dst: *mut T, _old: T, _src:
 /// [`Ordering::SeqCst`] as both the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchg_seqcst_seqcst<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchg_seqcst_seqcst<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool);
 
 /// Stores a value if the current value is the same as the `old` value.
 ///
@@ -277,15 +232,12 @@ pub unsafe fn atomic_cxchg_seqcst_seqcst<T: Copy>(_dst: *mut T, _old: T, _src: T
 /// [`Ordering::Relaxed`] as both the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange_weak`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
 pub unsafe fn atomic_cxchgweak_relaxed_relaxed<T: Copy>(
     _dst: *mut T,
     _old: T,
     _src: T,
-) -> (T, bool) {
-    unreachable!()
-}
+) -> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -293,15 +245,12 @@ pub unsafe fn atomic_cxchgweak_relaxed_relaxed<T: Copy>(
 /// [`Ordering::Relaxed`] and [`Ordering::Acquire`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange_weak`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
 pub unsafe fn atomic_cxchgweak_relaxed_acquire<T: Copy>(
     _dst: *mut T,
     _old: T,
     _src: T,
-) -> (T, bool) {
-    unreachable!()
-}
+) -> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -309,15 +258,9 @@ pub unsafe fn atomic_cxchgweak_relaxed_acquire<T: Copy>(
 /// [`Ordering::Relaxed`] and [`Ordering::SeqCst`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange_weak`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchgweak_relaxed_seqcst<T: Copy>(
-    _dst: *mut T,
-    _old: T,
-    _src: T,
-) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchgweak_relaxed_seqcst<T: Copy>(_dst: *mut T, _old: T, _src: T)
+-> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -325,15 +268,12 @@ pub unsafe fn atomic_cxchgweak_relaxed_seqcst<T: Copy>(
 /// [`Ordering::Acquire`] and [`Ordering::Relaxed`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange_weak`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
 pub unsafe fn atomic_cxchgweak_acquire_relaxed<T: Copy>(
     _dst: *mut T,
     _old: T,
     _src: T,
-) -> (T, bool) {
-    unreachable!()
-}
+) -> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -341,15 +281,12 @@ pub unsafe fn atomic_cxchgweak_acquire_relaxed<T: Copy>(
 /// [`Ordering::Acquire`] as both the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange_weak`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
 pub unsafe fn atomic_cxchgweak_acquire_acquire<T: Copy>(
     _dst: *mut T,
     _old: T,
     _src: T,
-) -> (T, bool) {
-    unreachable!()
-}
+) -> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -357,15 +294,9 @@ pub unsafe fn atomic_cxchgweak_acquire_acquire<T: Copy>(
 /// [`Ordering::Acquire`] and [`Ordering::SeqCst`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange_weak`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchgweak_acquire_seqcst<T: Copy>(
-    _dst: *mut T,
-    _old: T,
-    _src: T,
-) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchgweak_acquire_seqcst<T: Copy>(_dst: *mut T, _old: T, _src: T)
+-> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -373,15 +304,12 @@ pub unsafe fn atomic_cxchgweak_acquire_seqcst<T: Copy>(
 /// [`Ordering::Release`] and [`Ordering::Relaxed`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange_weak`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
 pub unsafe fn atomic_cxchgweak_release_relaxed<T: Copy>(
     _dst: *mut T,
     _old: T,
     _src: T,
-) -> (T, bool) {
-    unreachable!()
-}
+) -> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -389,15 +317,12 @@ pub unsafe fn atomic_cxchgweak_release_relaxed<T: Copy>(
 /// [`Ordering::Release`] and [`Ordering::Acquire`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange_weak`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
 pub unsafe fn atomic_cxchgweak_release_acquire<T: Copy>(
     _dst: *mut T,
     _old: T,
     _src: T,
-) -> (T, bool) {
-    unreachable!()
-}
+) -> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -405,15 +330,9 @@ pub unsafe fn atomic_cxchgweak_release_acquire<T: Copy>(
 /// [`Ordering::Release`] and [`Ordering::SeqCst`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange_weak`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchgweak_release_seqcst<T: Copy>(
-    _dst: *mut T,
-    _old: T,
-    _src: T,
-) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchgweak_release_seqcst<T: Copy>(_dst: *mut T, _old: T, _src: T)
+-> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -421,15 +340,9 @@ pub unsafe fn atomic_cxchgweak_release_seqcst<T: Copy>(
 /// [`Ordering::AcqRel`] and [`Ordering::Relaxed`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange_weak`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchgweak_acqrel_relaxed<T: Copy>(
-    _dst: *mut T,
-    _old: T,
-    _src: T,
-) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchgweak_acqrel_relaxed<T: Copy>(_dst: *mut T, _old: T, _src: T)
+-> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -437,15 +350,9 @@ pub unsafe fn atomic_cxchgweak_acqrel_relaxed<T: Copy>(
 /// [`Ordering::AcqRel`] and [`Ordering::Acquire`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange_weak`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchgweak_acqrel_acquire<T: Copy>(
-    _dst: *mut T,
-    _old: T,
-    _src: T,
-) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchgweak_acqrel_acquire<T: Copy>(_dst: *mut T, _old: T, _src: T)
+-> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -453,11 +360,8 @@ pub unsafe fn atomic_cxchgweak_acqrel_acquire<T: Copy>(
 /// [`Ordering::AcqRel`] and [`Ordering::SeqCst`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange_weak`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchgweak_acqrel_seqcst<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchgweak_acqrel_seqcst<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -465,15 +369,9 @@ pub unsafe fn atomic_cxchgweak_acqrel_seqcst<T: Copy>(_dst: *mut T, _old: T, _sr
 /// [`Ordering::SeqCst`] and [`Ordering::Relaxed`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange_weak`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchgweak_seqcst_relaxed<T: Copy>(
-    _dst: *mut T,
-    _old: T,
-    _src: T,
-) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchgweak_seqcst_relaxed<T: Copy>(_dst: *mut T, _old: T, _src: T)
+-> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -481,15 +379,9 @@ pub unsafe fn atomic_cxchgweak_seqcst_relaxed<T: Copy>(
 /// [`Ordering::SeqCst`] and [`Ordering::Acquire`] as the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange_weak`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchgweak_seqcst_acquire<T: Copy>(
-    _dst: *mut T,
-    _old: T,
-    _src: T,
-) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchgweak_seqcst_acquire<T: Copy>(_dst: *mut T, _old: T, _src: T)
+-> (T, bool);
 /// Stores a value if the current value is the same as the `old` value.
 ///
 /// The stabilized version of this intrinsic is available on the
@@ -497,11 +389,8 @@ pub unsafe fn atomic_cxchgweak_seqcst_acquire<T: Copy>(
 /// [`Ordering::SeqCst`] as both the success and failure parameters.
 /// For example, [`AtomicBool::compare_exchange_weak`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_cxchgweak_seqcst_seqcst<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool) {
-    unreachable!()
-}
+pub unsafe fn atomic_cxchgweak_seqcst_seqcst<T: Copy>(_dst: *mut T, _old: T, _src: T) -> (T, bool);
 
 /// Loads the current value of the pointer.
 ///
@@ -509,42 +398,30 @@ pub unsafe fn atomic_cxchgweak_seqcst_seqcst<T: Copy>(_dst: *mut T, _old: T, _sr
 /// [`atomic`] types via the `load` method by passing
 /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::load`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_load_seqcst<T: Copy>(_src: *const T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_load_seqcst<T: Copy>(_src: *const T) -> T;
 /// Loads the current value of the pointer.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `load` method by passing
 /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::load`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_load_acquire<T: Copy>(_src: *const T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_load_acquire<T: Copy>(_src: *const T) -> T;
 /// Loads the current value of the pointer.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `load` method by passing
 /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::load`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_load_relaxed<T: Copy>(_src: *const T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_load_relaxed<T: Copy>(_src: *const T) -> T;
 /// Do NOT use this intrinsic; "unordered" operations do not exist in our memory model!
 /// In terms of the Rust Abstract Machine, this operation is equivalent to `src.read()`,
 /// i.e., it performs a non-atomic read.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_load_unordered<T: Copy>(_src: *const T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_load_unordered<T: Copy>(_src: *const T) -> T;
 
 /// Stores the value at the specified memory location.
 ///
@@ -552,42 +429,30 @@ pub unsafe fn atomic_load_unordered<T: Copy>(_src: *const T) -> T {
 /// [`atomic`] types via the `store` method by passing
 /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::store`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_store_seqcst<T: Copy>(_dst: *mut T, _val: T) {
-    unreachable!()
-}
+pub unsafe fn atomic_store_seqcst<T: Copy>(_dst: *mut T, _val: T);
 /// Stores the value at the specified memory location.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `store` method by passing
 /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::store`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_store_release<T: Copy>(_dst: *mut T, _val: T) {
-    unreachable!()
-}
+pub unsafe fn atomic_store_release<T: Copy>(_dst: *mut T, _val: T);
 /// Stores the value at the specified memory location.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `store` method by passing
 /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::store`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_store_relaxed<T: Copy>(_dst: *mut T, _val: T) {
-    unreachable!()
-}
+pub unsafe fn atomic_store_relaxed<T: Copy>(_dst: *mut T, _val: T);
 /// Do NOT use this intrinsic; "unordered" operations do not exist in our memory model!
 /// In terms of the Rust Abstract Machine, this operation is equivalent to `dst.write(val)`,
 /// i.e., it performs a non-atomic write.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_store_unordered<T: Copy>(_dst: *mut T, _val: T) {
-    unreachable!()
-}
+pub unsafe fn atomic_store_unordered<T: Copy>(_dst: *mut T, _val: T);
 
 /// Stores the value at the specified memory location, returning the old value.
 ///
@@ -595,55 +460,40 @@ pub unsafe fn atomic_store_unordered<T: Copy>(_dst: *mut T, _val: T) {
 /// [`atomic`] types via the `swap` method by passing
 /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::swap`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_xchg_seqcst<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_xchg_seqcst<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Stores the value at the specified memory location, returning the old value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `swap` method by passing
 /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::swap`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_xchg_acquire<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_xchg_acquire<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Stores the value at the specified memory location, returning the old value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `swap` method by passing
 /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::swap`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_xchg_release<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_xchg_release<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Stores the value at the specified memory location, returning the old value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `swap` method by passing
 /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::swap`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_xchg_acqrel<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_xchg_acqrel<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Stores the value at the specified memory location, returning the old value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `swap` method by passing
 /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::swap`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_xchg_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_xchg_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T;
 
 /// Adds to the current value, returning the previous value.
 ///
@@ -651,55 +501,40 @@ pub unsafe fn atomic_xchg_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T {
 /// [`atomic`] types via the `fetch_add` method by passing
 /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicIsize::fetch_add`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_xadd_seqcst<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_xadd_seqcst<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Adds to the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `fetch_add` method by passing
 /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicIsize::fetch_add`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_xadd_acquire<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_xadd_acquire<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Adds to the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `fetch_add` method by passing
 /// [`Ordering::Release`] as the `order`. For example, [`AtomicIsize::fetch_add`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_xadd_release<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_xadd_release<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Adds to the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `fetch_add` method by passing
 /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicIsize::fetch_add`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_xadd_acqrel<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_xadd_acqrel<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Adds to the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `fetch_add` method by passing
 /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicIsize::fetch_add`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_xadd_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_xadd_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T;
 
 /// Subtract from the current value, returning the previous value.
 ///
@@ -707,55 +542,40 @@ pub unsafe fn atomic_xadd_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T {
 /// [`atomic`] types via the `fetch_sub` method by passing
 /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicIsize::fetch_sub`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_xsub_seqcst<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_xsub_seqcst<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Subtract from the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `fetch_sub` method by passing
 /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicIsize::fetch_sub`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_xsub_acquire<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_xsub_acquire<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Subtract from the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `fetch_sub` method by passing
 /// [`Ordering::Release`] as the `order`. For example, [`AtomicIsize::fetch_sub`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_xsub_release<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_xsub_release<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Subtract from the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `fetch_sub` method by passing
 /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicIsize::fetch_sub`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_xsub_acqrel<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_xsub_acqrel<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Subtract from the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `fetch_sub` method by passing
 /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicIsize::fetch_sub`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_xsub_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_xsub_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T;
 
 /// Bitwise and with the current value, returning the previous value.
 ///
@@ -763,55 +583,40 @@ pub unsafe fn atomic_xsub_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T {
 /// [`atomic`] types via the `fetch_and` method by passing
 /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_and`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_and_seqcst<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_and_seqcst<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Bitwise and with the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `fetch_and` method by passing
 /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_and`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_and_acquire<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_and_acquire<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Bitwise and with the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `fetch_and` method by passing
 /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_and`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_and_release<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_and_release<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Bitwise and with the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `fetch_and` method by passing
 /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_and`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_and_acqrel<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_and_acqrel<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Bitwise and with the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `fetch_and` method by passing
 /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_and`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_and_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_and_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T;
 
 /// Bitwise nand with the current value, returning the previous value.
 ///
@@ -819,55 +624,40 @@ pub unsafe fn atomic_and_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T {
 /// [`AtomicBool`] type via the `fetch_nand` method by passing
 /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_nand`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_nand_seqcst<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_nand_seqcst<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Bitwise nand with the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`AtomicBool`] type via the `fetch_nand` method by passing
 /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_nand`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_nand_acquire<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_nand_acquire<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Bitwise nand with the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`AtomicBool`] type via the `fetch_nand` method by passing
 /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_nand`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_nand_release<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_nand_release<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Bitwise nand with the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`AtomicBool`] type via the `fetch_nand` method by passing
 /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_nand`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_nand_acqrel<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_nand_acqrel<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Bitwise nand with the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`AtomicBool`] type via the `fetch_nand` method by passing
 /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_nand`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_nand_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_nand_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T;
 
 /// Bitwise or with the current value, returning the previous value.
 ///
@@ -875,55 +665,40 @@ pub unsafe fn atomic_nand_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T {
 /// [`atomic`] types via the `fetch_or` method by passing
 /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_or`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_or_seqcst<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_or_seqcst<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Bitwise or with the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `fetch_or` method by passing
 /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_or`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_or_acquire<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_or_acquire<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Bitwise or with the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `fetch_or` method by passing
 /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_or`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_or_release<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_or_release<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Bitwise or with the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `fetch_or` method by passing
 /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_or`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_or_acqrel<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_or_acqrel<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Bitwise or with the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `fetch_or` method by passing
 /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_or`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_or_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_or_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T;
 
 /// Bitwise xor with the current value, returning the previous value.
 ///
@@ -931,55 +706,40 @@ pub unsafe fn atomic_or_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T {
 /// [`atomic`] types via the `fetch_xor` method by passing
 /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicBool::fetch_xor`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_xor_seqcst<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_xor_seqcst<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Bitwise xor with the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `fetch_xor` method by passing
 /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicBool::fetch_xor`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_xor_acquire<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_xor_acquire<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Bitwise xor with the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `fetch_xor` method by passing
 /// [`Ordering::Release`] as the `order`. For example, [`AtomicBool::fetch_xor`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_xor_release<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_xor_release<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Bitwise xor with the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `fetch_xor` method by passing
 /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicBool::fetch_xor`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_xor_acqrel<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_xor_acqrel<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Bitwise xor with the current value, returning the previous value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] types via the `fetch_xor` method by passing
 /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicBool::fetch_xor`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_xor_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_xor_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T;
 
 /// Maximum with the current value using a signed comparison.
 ///
@@ -987,55 +747,40 @@ pub unsafe fn atomic_xor_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T {
 /// [`atomic`] signed integer types via the `fetch_max` method by passing
 /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicI32::fetch_max`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_max_seqcst<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_max_seqcst<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Maximum with the current value using a signed comparison.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] signed integer types via the `fetch_max` method by passing
 /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicI32::fetch_max`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_max_acquire<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_max_acquire<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Maximum with the current value using a signed comparison.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] signed integer types via the `fetch_max` method by passing
 /// [`Ordering::Release`] as the `order`. For example, [`AtomicI32::fetch_max`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_max_release<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_max_release<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Maximum with the current value using a signed comparison.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] signed integer types via the `fetch_max` method by passing
 /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicI32::fetch_max`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_max_acqrel<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_max_acqrel<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Maximum with the current value.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] signed integer types via the `fetch_max` method by passing
 /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicI32::fetch_max`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_max_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_max_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T;
 
 /// Minimum with the current value using a signed comparison.
 ///
@@ -1043,55 +788,40 @@ pub unsafe fn atomic_max_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T {
 /// [`atomic`] signed integer types via the `fetch_min` method by passing
 /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicI32::fetch_min`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_min_seqcst<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_min_seqcst<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Minimum with the current value using a signed comparison.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] signed integer types via the `fetch_min` method by passing
 /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicI32::fetch_min`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_min_acquire<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_min_acquire<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Minimum with the current value using a signed comparison.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] signed integer types via the `fetch_min` method by passing
 /// [`Ordering::Release`] as the `order`. For example, [`AtomicI32::fetch_min`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_min_release<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_min_release<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Minimum with the current value using a signed comparison.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] signed integer types via the `fetch_min` method by passing
 /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicI32::fetch_min`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_min_acqrel<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_min_acqrel<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Minimum with the current value using a signed comparison.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] signed integer types via the `fetch_min` method by passing
 /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicI32::fetch_min`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_min_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_min_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T;
 
 /// Minimum with the current value using an unsigned comparison.
 ///
@@ -1099,55 +829,40 @@ pub unsafe fn atomic_min_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T {
 /// [`atomic`] unsigned integer types via the `fetch_min` method by passing
 /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicU32::fetch_min`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_umin_seqcst<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_umin_seqcst<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Minimum with the current value using an unsigned comparison.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] unsigned integer types via the `fetch_min` method by passing
 /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicU32::fetch_min`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_umin_acquire<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_umin_acquire<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Minimum with the current value using an unsigned comparison.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] unsigned integer types via the `fetch_min` method by passing
 /// [`Ordering::Release`] as the `order`. For example, [`AtomicU32::fetch_min`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_umin_release<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_umin_release<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Minimum with the current value using an unsigned comparison.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] unsigned integer types via the `fetch_min` method by passing
 /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicU32::fetch_min`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_umin_acqrel<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_umin_acqrel<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Minimum with the current value using an unsigned comparison.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] unsigned integer types via the `fetch_min` method by passing
 /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicU32::fetch_min`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_umin_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_umin_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T;
 
 /// Maximum with the current value using an unsigned comparison.
 ///
@@ -1155,55 +870,40 @@ pub unsafe fn atomic_umin_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T {
 /// [`atomic`] unsigned integer types via the `fetch_max` method by passing
 /// [`Ordering::SeqCst`] as the `order`. For example, [`AtomicU32::fetch_max`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_umax_seqcst<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_umax_seqcst<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Maximum with the current value using an unsigned comparison.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] unsigned integer types via the `fetch_max` method by passing
 /// [`Ordering::Acquire`] as the `order`. For example, [`AtomicU32::fetch_max`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_umax_acquire<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_umax_acquire<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Maximum with the current value using an unsigned comparison.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] unsigned integer types via the `fetch_max` method by passing
 /// [`Ordering::Release`] as the `order`. For example, [`AtomicU32::fetch_max`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_umax_release<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_umax_release<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Maximum with the current value using an unsigned comparison.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] unsigned integer types via the `fetch_max` method by passing
 /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicU32::fetch_max`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_umax_acqrel<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_umax_acqrel<T: Copy>(_dst: *mut T, _src: T) -> T;
 /// Maximum with the current value using an unsigned comparison.
 ///
 /// The stabilized version of this intrinsic is available on the
 /// [`atomic`] unsigned integer types via the `fetch_max` method by passing
 /// [`Ordering::Relaxed`] as the `order`. For example, [`AtomicU32::fetch_max`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_umax_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T {
-    unreachable!()
-}
+pub unsafe fn atomic_umax_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T;
 
 /// An atomic fence.
 ///
@@ -1211,44 +911,32 @@ pub unsafe fn atomic_umax_relaxed<T: Copy>(_dst: *mut T, _src: T) -> T {
 /// [`atomic::fence`] by passing [`Ordering::SeqCst`]
 /// as the `order`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_fence_seqcst() {
-    unreachable!()
-}
+pub unsafe fn atomic_fence_seqcst();
 /// An atomic fence.
 ///
 /// The stabilized version of this intrinsic is available in
 /// [`atomic::fence`] by passing [`Ordering::Acquire`]
 /// as the `order`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_fence_acquire() {
-    unreachable!()
-}
+pub unsafe fn atomic_fence_acquire();
 /// An atomic fence.
 ///
 /// The stabilized version of this intrinsic is available in
 /// [`atomic::fence`] by passing [`Ordering::Release`]
 /// as the `order`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_fence_release() {
-    unreachable!()
-}
+pub unsafe fn atomic_fence_release();
 /// An atomic fence.
 ///
 /// The stabilized version of this intrinsic is available in
 /// [`atomic::fence`] by passing [`Ordering::AcqRel`]
 /// as the `order`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_fence_acqrel() {
-    unreachable!()
-}
+pub unsafe fn atomic_fence_acqrel();
 
 /// A compiler-only memory barrier.
 ///
@@ -1261,11 +949,8 @@ pub unsafe fn atomic_fence_acqrel() {
 /// [`atomic::compiler_fence`] by passing [`Ordering::SeqCst`]
 /// as the `order`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_singlethreadfence_seqcst() {
-    unreachable!()
-}
+pub unsafe fn atomic_singlethreadfence_seqcst();
 /// A compiler-only memory barrier.
 ///
 /// Memory accesses will never be reordered across this barrier by the
@@ -1277,11 +962,8 @@ pub unsafe fn atomic_singlethreadfence_seqcst() {
 /// [`atomic::compiler_fence`] by passing [`Ordering::Acquire`]
 /// as the `order`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_singlethreadfence_acquire() {
-    unreachable!()
-}
+pub unsafe fn atomic_singlethreadfence_acquire();
 /// A compiler-only memory barrier.
 ///
 /// Memory accesses will never be reordered across this barrier by the
@@ -1293,11 +975,8 @@ pub unsafe fn atomic_singlethreadfence_acquire() {
 /// [`atomic::compiler_fence`] by passing [`Ordering::Release`]
 /// as the `order`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_singlethreadfence_release() {
-    unreachable!()
-}
+pub unsafe fn atomic_singlethreadfence_release();
 /// A compiler-only memory barrier.
 ///
 /// Memory accesses will never be reordered across this barrier by the
@@ -1309,11 +988,8 @@ pub unsafe fn atomic_singlethreadfence_release() {
 /// [`atomic::compiler_fence`] by passing [`Ordering::AcqRel`]
 /// as the `order`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn atomic_singlethreadfence_acqrel() {
-    unreachable!()
-}
+pub unsafe fn atomic_singlethreadfence_acqrel();
 
 /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction
 /// if supported; otherwise, it is a no-op.
@@ -1325,11 +1001,8 @@ pub unsafe fn atomic_singlethreadfence_acqrel() {
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn prefetch_read_data<T>(_data: *const T, _locality: i32) {
-    unreachable!()
-}
+pub unsafe fn prefetch_read_data<T>(_data: *const T, _locality: i32);
 /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction
 /// if supported; otherwise, it is a no-op.
 /// Prefetches have no effect on the behavior of the program but can change its performance
@@ -1340,11 +1013,8 @@ pub unsafe fn prefetch_read_data<T>(_data: *const T, _locality: i32) {
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn prefetch_write_data<T>(_data: *const T, _locality: i32) {
-    unreachable!()
-}
+pub unsafe fn prefetch_write_data<T>(_data: *const T, _locality: i32);
 /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction
 /// if supported; otherwise, it is a no-op.
 /// Prefetches have no effect on the behavior of the program but can change its performance
@@ -1355,11 +1025,8 @@ pub unsafe fn prefetch_write_data<T>(_data: *const T, _locality: i32) {
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn prefetch_read_instruction<T>(_data: *const T, _locality: i32) {
-    unreachable!()
-}
+pub unsafe fn prefetch_read_instruction<T>(_data: *const T, _locality: i32);
 /// The `prefetch` intrinsic is a hint to the code generator to insert a prefetch instruction
 /// if supported; otherwise, it is a no-op.
 /// Prefetches have no effect on the behavior of the program but can change its performance
@@ -1370,21 +1037,15 @@ pub unsafe fn prefetch_read_instruction<T>(_data: *const T, _locality: i32) {
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn prefetch_write_instruction<T>(_data: *const T, _locality: i32) {
-    unreachable!()
-}
+pub unsafe fn prefetch_write_instruction<T>(_data: *const T, _locality: i32);
 
 /// Executes a breakpoint trap, for inspection by a debugger.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub fn breakpoint() {
-    unreachable!()
-}
+pub fn breakpoint();
 
 /// Magic intrinsic that derives its meaning from attributes
 /// attached to the function.
@@ -1397,10 +1058,7 @@ pub fn breakpoint() {
 /// This intrinsic should not be used outside of the compiler.
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub fn rustc_peek<T>(_: T) -> T {
-    unreachable!()
-}
+pub fn rustc_peek<T>(_: T) -> T;
 
 /// Aborts the execution of the process.
 ///
@@ -1419,10 +1077,7 @@ pub fn rustc_peek<T>(_: T) -> T {
 /// `SIGBUS`.  The precise behavior is not guaranteed and not stable.
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub fn abort() -> ! {
-    unreachable!()
-}
+pub fn abort() -> !;
 
 /// Informs the optimizer that this point in the code is not reachable,
 /// enabling further optimizations.
@@ -1435,10 +1090,7 @@ pub fn abort() -> ! {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn unreachable() -> ! {
-    unreachable!()
-}
+pub const unsafe fn unreachable() -> !;
 
 /// Informs the optimizer that a condition is always true.
 /// If the condition is false, the behavior is undefined.
@@ -1550,10 +1202,7 @@ pub fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn assert_inhabited<T>() {
-    unreachable!()
-}
+pub const fn assert_inhabited<T>();
 
 /// A guard for unsafe functions that cannot ever be executed if `T` does not permit
 /// zero-initialization: This will statically either panic, or do nothing.
@@ -1562,10 +1211,7 @@ pub const fn assert_inhabited<T>() {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn assert_zero_valid<T>() {
-    unreachable!()
-}
+pub const fn assert_zero_valid<T>();
 
 /// A guard for `std::mem::uninitialized`. This will statically either panic, or do nothing.
 ///
@@ -1573,10 +1219,7 @@ pub const fn assert_zero_valid<T>() {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn assert_mem_uninitialized_valid<T>() {
-    unreachable!()
-}
+pub const fn assert_mem_uninitialized_valid<T>();
 
 /// Gets a reference to a static `Location` indicating where it was called.
 ///
@@ -1589,10 +1232,7 @@ pub const fn assert_mem_uninitialized_valid<T>() {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn caller_location() -> &'static crate::panic::Location<'static> {
-    unreachable!()
-}
+pub const fn caller_location() -> &'static crate::panic::Location<'static>;
 
 /// Moves a value out of scope without running drop glue.
 ///
@@ -1606,10 +1246,7 @@ pub const fn caller_location() -> &'static crate::panic::Location<'static> {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn forget<T: ?Sized>(_: T) {
-    unreachable!()
-}
+pub const fn forget<T: ?Sized>(_: T);
 
 /// Reinterprets the bits of a value of one type as another type.
 ///
@@ -1902,10 +1539,7 @@ pub const fn forget<T: ?Sized>(_: T) {
 #[rustc_diagnostic_item = "transmute"]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn transmute<Src, Dst>(_src: Src) -> Dst {
-    unreachable!()
-}
+pub const unsafe fn transmute<Src, Dst>(_src: Src) -> Dst;
 
 /// Like [`transmute`], but even less checked at compile-time: rather than
 /// giving an error for `size_of::<Src>() != size_of::<Dst>()`, it's
@@ -1919,10 +1553,7 @@ pub const unsafe fn transmute<Src, Dst>(_src: Src) -> Dst {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn transmute_unchecked<Src, Dst>(_src: Src) -> Dst {
-    unreachable!()
-}
+pub const unsafe fn transmute_unchecked<Src, Dst>(_src: Src) -> Dst;
 
 /// Returns `true` if the actual type given as `T` requires drop
 /// glue; returns `false` if the actual type provided for `T`
@@ -1940,10 +1571,7 @@ pub const unsafe fn transmute_unchecked<Src, Dst>(_src: Src) -> Dst {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn needs_drop<T: ?Sized>() -> bool {
-    unreachable!()
-}
+pub const fn needs_drop<T: ?Sized>() -> bool;
 
 /// Calculates the offset from a pointer.
 ///
@@ -1965,10 +1593,7 @@ pub const fn needs_drop<T: ?Sized>() -> bool {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn offset<Ptr, Delta>(_dst: Ptr, _offset: Delta) -> Ptr {
-    unreachable!()
-}
+pub const unsafe fn offset<Ptr, Delta>(_dst: Ptr, _offset: Delta) -> Ptr;
 
 /// Calculates the offset from a pointer, potentially wrapping.
 ///
@@ -1987,10 +1612,7 @@ pub const unsafe fn offset<Ptr, Delta>(_dst: Ptr, _offset: Delta) -> Ptr {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn arith_offset<T>(_dst: *const T, _offset: isize) -> *const T {
-    unreachable!()
-}
+pub const unsafe fn arith_offset<T>(_dst: *const T, _offset: isize) -> *const T;
 
 /// Masks out bits of the pointer according to a mask.
 ///
@@ -2002,10 +1624,7 @@ pub const unsafe fn arith_offset<T>(_dst: *const T, _offset: isize) -> *const T
 /// Consider using [`pointer::mask`] instead.
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub fn ptr_mask<T>(_ptr: *const T, _mask: usize) -> *const T {
-    unreachable!()
-}
+pub fn ptr_mask<T>(_ptr: *const T, _mask: usize) -> *const T;
 
 /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with
 /// a size of `count` * `size_of::<T>()` and an alignment of
@@ -2016,11 +1635,8 @@ pub fn ptr_mask<T>(_ptr: *const T, _mask: usize) -> *const T {
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn volatile_copy_nonoverlapping_memory<T>(_dst: *mut T, _src: *const T, _count: usize) {
-    unreachable!()
-}
+pub unsafe fn volatile_copy_nonoverlapping_memory<T>(_dst: *mut T, _src: *const T, _count: usize);
 /// Equivalent to the appropriate `llvm.memmove.p0i8.0i8.*` intrinsic, with
 /// a size of `count * size_of::<T>()` and an alignment of
 /// `min_align_of::<T>()`
@@ -2030,11 +1646,8 @@ pub unsafe fn volatile_copy_nonoverlapping_memory<T>(_dst: *mut T, _src: *const
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn volatile_copy_memory<T>(_dst: *mut T, _src: *const T, _count: usize) {
-    unreachable!()
-}
+pub unsafe fn volatile_copy_memory<T>(_dst: *mut T, _src: *const T, _count: usize);
 /// Equivalent to the appropriate `llvm.memset.p0i8.*` intrinsic, with a
 /// size of `count * size_of::<T>()` and an alignment of
 /// `min_align_of::<T>()`.
@@ -2044,504 +1657,357 @@ pub unsafe fn volatile_copy_memory<T>(_dst: *mut T, _src: *const T, _count: usiz
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn volatile_set_memory<T>(_dst: *mut T, _val: u8, _count: usize) {
-    unreachable!()
-}
+pub unsafe fn volatile_set_memory<T>(_dst: *mut T, _val: u8, _count: usize);
 
 /// Performs a volatile load from the `src` pointer.
 ///
 /// The stabilized version of this intrinsic is [`core::ptr::read_volatile`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn volatile_load<T>(_src: *const T) -> T {
-    unreachable!()
-}
+pub unsafe fn volatile_load<T>(_src: *const T) -> T;
 /// Performs a volatile store to the `dst` pointer.
 ///
 /// The stabilized version of this intrinsic is [`core::ptr::write_volatile`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn volatile_store<T>(_dst: *mut T, _val: T) {
-    unreachable!()
-}
+pub unsafe fn volatile_store<T>(_dst: *mut T, _val: T);
 
 /// Performs a volatile load from the `src` pointer
 /// The pointer is not required to be aligned.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
 #[rustc_diagnostic_item = "intrinsics_unaligned_volatile_load"]
-pub unsafe fn unaligned_volatile_load<T>(_src: *const T) -> T {
-    unreachable!()
-}
+pub unsafe fn unaligned_volatile_load<T>(_src: *const T) -> T;
 /// Performs a volatile store to the `dst` pointer.
 /// The pointer is not required to be aligned.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
 #[rustc_diagnostic_item = "intrinsics_unaligned_volatile_store"]
-pub unsafe fn unaligned_volatile_store<T>(_dst: *mut T, _val: T) {
-    unreachable!()
-}
+pub unsafe fn unaligned_volatile_store<T>(_dst: *mut T, _val: T);
 
 /// Returns the square root of an `f16`
 ///
 /// The stabilized version of this intrinsic is
 /// [`f16::sqrt`](../../std/primitive.f16.html#method.sqrt)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn sqrtf16(_x: f16) -> f16 {
-    unreachable!()
-}
+pub unsafe fn sqrtf16(_x: f16) -> f16;
 /// Returns the square root of an `f32`
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::sqrt`](../../std/primitive.f32.html#method.sqrt)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn sqrtf32(_x: f32) -> f32 {
-    unreachable!()
-}
+pub unsafe fn sqrtf32(_x: f32) -> f32;
 /// Returns the square root of an `f64`
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::sqrt`](../../std/primitive.f64.html#method.sqrt)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn sqrtf64(_x: f64) -> f64 {
-    unreachable!()
-}
+pub unsafe fn sqrtf64(_x: f64) -> f64;
 /// Returns the square root of an `f128`
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::sqrt`](../../std/primitive.f128.html#method.sqrt)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn sqrtf128(_x: f128) -> f128 {
-    unreachable!()
-}
+pub unsafe fn sqrtf128(_x: f128) -> f128;
 
 /// Raises an `f16` to an integer power.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f16::powi`](../../std/primitive.f16.html#method.powi)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn powif16(_a: f16, _x: i32) -> f16 {
-    unreachable!()
-}
+pub unsafe fn powif16(_a: f16, _x: i32) -> f16;
 /// Raises an `f32` to an integer power.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::powi`](../../std/primitive.f32.html#method.powi)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn powif32(_a: f32, _x: i32) -> f32 {
-    unreachable!()
-}
+pub unsafe fn powif32(_a: f32, _x: i32) -> f32;
 /// Raises an `f64` to an integer power.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::powi`](../../std/primitive.f64.html#method.powi)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn powif64(_a: f64, _x: i32) -> f64 {
-    unreachable!()
-}
+pub unsafe fn powif64(_a: f64, _x: i32) -> f64;
 /// Raises an `f128` to an integer power.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::powi`](../../std/primitive.f128.html#method.powi)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn powif128(_a: f128, _x: i32) -> f128 {
-    unreachable!()
-}
+pub unsafe fn powif128(_a: f128, _x: i32) -> f128;
 
 /// Returns the sine of an `f16`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f16::sin`](../../std/primitive.f16.html#method.sin)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn sinf16(_x: f16) -> f16 {
-    unreachable!()
-}
+pub unsafe fn sinf16(_x: f16) -> f16;
 /// Returns the sine of an `f32`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::sin`](../../std/primitive.f32.html#method.sin)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn sinf32(_x: f32) -> f32 {
-    unreachable!()
-}
+pub unsafe fn sinf32(_x: f32) -> f32;
 /// Returns the sine of an `f64`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::sin`](../../std/primitive.f64.html#method.sin)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn sinf64(_x: f64) -> f64 {
-    unreachable!()
-}
+pub unsafe fn sinf64(_x: f64) -> f64;
 /// Returns the sine of an `f128`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::sin`](../../std/primitive.f128.html#method.sin)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn sinf128(_x: f128) -> f128 {
-    unreachable!()
-}
+pub unsafe fn sinf128(_x: f128) -> f128;
 
 /// Returns the cosine of an `f16`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f16::cos`](../../std/primitive.f16.html#method.cos)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn cosf16(_x: f16) -> f16 {
-    unreachable!()
-}
+pub unsafe fn cosf16(_x: f16) -> f16;
 /// Returns the cosine of an `f32`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::cos`](../../std/primitive.f32.html#method.cos)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn cosf32(_x: f32) -> f32 {
-    unreachable!()
-}
+pub unsafe fn cosf32(_x: f32) -> f32;
 /// Returns the cosine of an `f64`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::cos`](../../std/primitive.f64.html#method.cos)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn cosf64(_x: f64) -> f64 {
-    unreachable!()
-}
+pub unsafe fn cosf64(_x: f64) -> f64;
 /// Returns the cosine of an `f128`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::cos`](../../std/primitive.f128.html#method.cos)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn cosf128(_x: f128) -> f128 {
-    unreachable!()
-}
+pub unsafe fn cosf128(_x: f128) -> f128;
 
 /// Raises an `f16` to an `f16` power.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f16::powf`](../../std/primitive.f16.html#method.powf)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn powf16(_a: f16, _x: f16) -> f16 {
-    unreachable!()
-}
+pub unsafe fn powf16(_a: f16, _x: f16) -> f16;
 /// Raises an `f32` to an `f32` power.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::powf`](../../std/primitive.f32.html#method.powf)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn powf32(_a: f32, _x: f32) -> f32 {
-    unreachable!()
-}
+pub unsafe fn powf32(_a: f32, _x: f32) -> f32;
 /// Raises an `f64` to an `f64` power.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::powf`](../../std/primitive.f64.html#method.powf)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn powf64(_a: f64, _x: f64) -> f64 {
-    unreachable!()
-}
+pub unsafe fn powf64(_a: f64, _x: f64) -> f64;
 /// Raises an `f128` to an `f128` power.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::powf`](../../std/primitive.f128.html#method.powf)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn powf128(_a: f128, _x: f128) -> f128 {
-    unreachable!()
-}
+pub unsafe fn powf128(_a: f128, _x: f128) -> f128;
 
 /// Returns the exponential of an `f16`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f16::exp`](../../std/primitive.f16.html#method.exp)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn expf16(_x: f16) -> f16 {
-    unreachable!()
-}
+pub unsafe fn expf16(_x: f16) -> f16;
 /// Returns the exponential of an `f32`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::exp`](../../std/primitive.f32.html#method.exp)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn expf32(_x: f32) -> f32 {
-    unreachable!()
-}
+pub unsafe fn expf32(_x: f32) -> f32;
 /// Returns the exponential of an `f64`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::exp`](../../std/primitive.f64.html#method.exp)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn expf64(_x: f64) -> f64 {
-    unreachable!()
-}
+pub unsafe fn expf64(_x: f64) -> f64;
 /// Returns the exponential of an `f128`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::exp`](../../std/primitive.f128.html#method.exp)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn expf128(_x: f128) -> f128 {
-    unreachable!()
-}
+pub unsafe fn expf128(_x: f128) -> f128;
 
 /// Returns 2 raised to the power of an `f16`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f16::exp2`](../../std/primitive.f16.html#method.exp2)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn exp2f16(_x: f16) -> f16 {
-    unreachable!()
-}
+pub unsafe fn exp2f16(_x: f16) -> f16;
 /// Returns 2 raised to the power of an `f32`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::exp2`](../../std/primitive.f32.html#method.exp2)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn exp2f32(_x: f32) -> f32 {
-    unreachable!()
-}
+pub unsafe fn exp2f32(_x: f32) -> f32;
 /// Returns 2 raised to the power of an `f64`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::exp2`](../../std/primitive.f64.html#method.exp2)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn exp2f64(_x: f64) -> f64 {
-    unreachable!()
-}
+pub unsafe fn exp2f64(_x: f64) -> f64;
 /// Returns 2 raised to the power of an `f128`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::exp2`](../../std/primitive.f128.html#method.exp2)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn exp2f128(_x: f128) -> f128 {
-    unreachable!()
-}
+pub unsafe fn exp2f128(_x: f128) -> f128;
 
 /// Returns the natural logarithm of an `f16`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f16::ln`](../../std/primitive.f16.html#method.ln)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn logf16(_x: f16) -> f16 {
-    unreachable!()
-}
+pub unsafe fn logf16(_x: f16) -> f16;
 /// Returns the natural logarithm of an `f32`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::ln`](../../std/primitive.f32.html#method.ln)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn logf32(_x: f32) -> f32 {
-    unreachable!()
-}
+pub unsafe fn logf32(_x: f32) -> f32;
 /// Returns the natural logarithm of an `f64`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::ln`](../../std/primitive.f64.html#method.ln)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn logf64(_x: f64) -> f64 {
-    unreachable!()
-}
+pub unsafe fn logf64(_x: f64) -> f64;
 /// Returns the natural logarithm of an `f128`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::ln`](../../std/primitive.f128.html#method.ln)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn logf128(_x: f128) -> f128 {
-    unreachable!()
-}
+pub unsafe fn logf128(_x: f128) -> f128;
 
 /// Returns the base 10 logarithm of an `f16`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f16::log10`](../../std/primitive.f16.html#method.log10)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn log10f16(_x: f16) -> f16 {
-    unreachable!()
-}
+pub unsafe fn log10f16(_x: f16) -> f16;
 /// Returns the base 10 logarithm of an `f32`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::log10`](../../std/primitive.f32.html#method.log10)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn log10f32(_x: f32) -> f32 {
-    unreachable!()
-}
+pub unsafe fn log10f32(_x: f32) -> f32;
 /// Returns the base 10 logarithm of an `f64`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::log10`](../../std/primitive.f64.html#method.log10)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn log10f64(_x: f64) -> f64 {
-    unreachable!()
-}
+pub unsafe fn log10f64(_x: f64) -> f64;
 /// Returns the base 10 logarithm of an `f128`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::log10`](../../std/primitive.f128.html#method.log10)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn log10f128(_x: f128) -> f128 {
-    unreachable!()
-}
+pub unsafe fn log10f128(_x: f128) -> f128;
 
 /// Returns the base 2 logarithm of an `f16`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f16::log2`](../../std/primitive.f16.html#method.log2)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn log2f16(_x: f16) -> f16 {
-    unreachable!()
-}
+pub unsafe fn log2f16(_x: f16) -> f16;
 /// Returns the base 2 logarithm of an `f32`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::log2`](../../std/primitive.f32.html#method.log2)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn log2f32(_x: f32) -> f32 {
-    unreachable!()
-}
+pub unsafe fn log2f32(_x: f32) -> f32;
 /// Returns the base 2 logarithm of an `f64`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::log2`](../../std/primitive.f64.html#method.log2)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn log2f64(_x: f64) -> f64 {
-    unreachable!()
-}
+pub unsafe fn log2f64(_x: f64) -> f64;
 /// Returns the base 2 logarithm of an `f128`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::log2`](../../std/primitive.f128.html#method.log2)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn log2f128(_x: f128) -> f128 {
-    unreachable!()
-}
+pub unsafe fn log2f128(_x: f128) -> f128;
 
 /// Returns `a * b + c` for `f16` values.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f16::mul_add`](../../std/primitive.f16.html#method.mul_add)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn fmaf16(_a: f16, _b: f16, _c: f16) -> f16 {
-    unreachable!()
-}
+pub unsafe fn fmaf16(_a: f16, _b: f16, _c: f16) -> f16;
 /// Returns `a * b + c` for `f32` values.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::mul_add`](../../std/primitive.f32.html#method.mul_add)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn fmaf32(_a: f32, _b: f32, _c: f32) -> f32 {
-    unreachable!()
-}
+pub unsafe fn fmaf32(_a: f32, _b: f32, _c: f32) -> f32;
 /// Returns `a * b + c` for `f64` values.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::mul_add`](../../std/primitive.f64.html#method.mul_add)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn fmaf64(_a: f64, _b: f64, _c: f64) -> f64 {
-    unreachable!()
-}
+pub unsafe fn fmaf64(_a: f64, _b: f64, _c: f64) -> f64;
 /// Returns `a * b + c` for `f128` values.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::mul_add`](../../std/primitive.f128.html#method.mul_add)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn fmaf128(_a: f128, _b: f128, _c: f128) -> f128 {
-    unreachable!()
-}
+pub unsafe fn fmaf128(_a: f128, _b: f128, _c: f128) -> f128;
 
 /// Returns `a * b + c` for `f16` values, non-deterministically executing
 /// either a fused multiply-add or two operations with rounding of the
@@ -2554,11 +2020,8 @@ pub unsafe fn fmaf128(_a: f128, _b: f128, _c: f128) -> f128 {
 /// is selected, and that may depend on optimization level and context, for
 /// example.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn fmuladdf16(_a: f16, _b: f16, _c: f16) -> f16 {
-    unreachable!()
-}
+pub unsafe fn fmuladdf16(_a: f16, _b: f16, _c: f16) -> f16;
 /// Returns `a * b + c` for `f32` values, non-deterministically executing
 /// either a fused multiply-add or two operations with rounding of the
 /// intermediate result.
@@ -2570,11 +2033,8 @@ pub unsafe fn fmuladdf16(_a: f16, _b: f16, _c: f16) -> f16 {
 /// is selected, and that may depend on optimization level and context, for
 /// example.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn fmuladdf32(_a: f32, _b: f32, _c: f32) -> f32 {
-    unreachable!()
-}
+pub unsafe fn fmuladdf32(_a: f32, _b: f32, _c: f32) -> f32;
 /// Returns `a * b + c` for `f64` values, non-deterministically executing
 /// either a fused multiply-add or two operations with rounding of the
 /// intermediate result.
@@ -2586,11 +2046,8 @@ pub unsafe fn fmuladdf32(_a: f32, _b: f32, _c: f32) -> f32 {
 /// is selected, and that may depend on optimization level and context, for
 /// example.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn fmuladdf64(_a: f64, _b: f64, _c: f64) -> f64 {
-    unreachable!()
-}
+pub unsafe fn fmuladdf64(_a: f64, _b: f64, _c: f64) -> f64;
 /// Returns `a * b + c` for `f128` values, non-deterministically executing
 /// either a fused multiply-add or two operations with rounding of the
 /// intermediate result.
@@ -2602,134 +2059,95 @@ pub unsafe fn fmuladdf64(_a: f64, _b: f64, _c: f64) -> f64 {
 /// is selected, and that may depend on optimization level and context, for
 /// example.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn fmuladdf128(_a: f128, _b: f128, _c: f128) -> f128 {
-    unreachable!()
-}
+pub unsafe fn fmuladdf128(_a: f128, _b: f128, _c: f128) -> f128;
 
 /// Returns the largest integer less than or equal to an `f16`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f16::floor`](../../std/primitive.f16.html#method.floor)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn floorf16(_x: f16) -> f16 {
-    unreachable!()
-}
+pub unsafe fn floorf16(_x: f16) -> f16;
 /// Returns the largest integer less than or equal to an `f32`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::floor`](../../std/primitive.f32.html#method.floor)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn floorf32(_x: f32) -> f32 {
-    unreachable!()
-}
+pub unsafe fn floorf32(_x: f32) -> f32;
 /// Returns the largest integer less than or equal to an `f64`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::floor`](../../std/primitive.f64.html#method.floor)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn floorf64(_x: f64) -> f64 {
-    unreachable!()
-}
+pub unsafe fn floorf64(_x: f64) -> f64;
 /// Returns the largest integer less than or equal to an `f128`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::floor`](../../std/primitive.f128.html#method.floor)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn floorf128(_x: f128) -> f128 {
-    unreachable!()
-}
+pub unsafe fn floorf128(_x: f128) -> f128;
 
 /// Returns the smallest integer greater than or equal to an `f16`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f16::ceil`](../../std/primitive.f16.html#method.ceil)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn ceilf16(_x: f16) -> f16 {
-    unreachable!()
-}
+pub unsafe fn ceilf16(_x: f16) -> f16;
 /// Returns the smallest integer greater than or equal to an `f32`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::ceil`](../../std/primitive.f32.html#method.ceil)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn ceilf32(_x: f32) -> f32 {
-    unreachable!()
-}
+pub unsafe fn ceilf32(_x: f32) -> f32;
 /// Returns the smallest integer greater than or equal to an `f64`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::ceil`](../../std/primitive.f64.html#method.ceil)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn ceilf64(_x: f64) -> f64 {
-    unreachable!()
-}
+pub unsafe fn ceilf64(_x: f64) -> f64;
 /// Returns the smallest integer greater than or equal to an `f128`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::ceil`](../../std/primitive.f128.html#method.ceil)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn ceilf128(_x: f128) -> f128 {
-    unreachable!()
-}
+pub unsafe fn ceilf128(_x: f128) -> f128;
 
 /// Returns the integer part of an `f16`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f16::trunc`](../../std/primitive.f16.html#method.trunc)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn truncf16(_x: f16) -> f16 {
-    unreachable!()
-}
+pub unsafe fn truncf16(_x: f16) -> f16;
 /// Returns the integer part of an `f32`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::trunc`](../../std/primitive.f32.html#method.trunc)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn truncf32(_x: f32) -> f32 {
-    unreachable!()
-}
+pub unsafe fn truncf32(_x: f32) -> f32;
 /// Returns the integer part of an `f64`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::trunc`](../../std/primitive.f64.html#method.trunc)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn truncf64(_x: f64) -> f64 {
-    unreachable!()
-}
+pub unsafe fn truncf64(_x: f64) -> f64;
 /// Returns the integer part of an `f128`.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::trunc`](../../std/primitive.f128.html#method.trunc)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn truncf128(_x: f128) -> f128 {
-    unreachable!()
-}
+pub unsafe fn truncf128(_x: f128) -> f128;
 
 /// Returns the nearest integer to an `f16`. Rounds half-way cases to the number with an even
 /// least significant digit.
@@ -2737,22 +2155,16 @@ pub unsafe fn truncf128(_x: f128) -> f128 {
 /// The stabilized version of this intrinsic is
 /// [`f16::round_ties_even`](../../std/primitive.f16.html#method.round_ties_even)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
 #[cfg(not(bootstrap))]
-pub fn round_ties_even_f16(_x: f16) -> f16 {
-    unreachable!()
-}
+pub fn round_ties_even_f16(_x: f16) -> f16;
 
 /// To be removed on next bootstrap bump.
 #[cfg(bootstrap)]
 pub fn round_ties_even_f16(x: f16) -> f16 {
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
     #[rustc_nounwind]
-    unsafe fn rintf16(_x: f16) -> f16 {
-        unreachable!()
-    }
+    unsafe fn rintf16(_x: f16) -> f16;
 
     // SAFETY: this intrinsic isn't actually unsafe
     unsafe { rintf16(x) }
@@ -2764,22 +2176,16 @@ pub fn round_ties_even_f16(x: f16) -> f16 {
 /// The stabilized version of this intrinsic is
 /// [`f32::round_ties_even`](../../std/primitive.f32.html#method.round_ties_even)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
 #[cfg(not(bootstrap))]
-pub fn round_ties_even_f32(_x: f32) -> f32 {
-    unreachable!()
-}
+pub fn round_ties_even_f32(_x: f32) -> f32;
 
 /// To be removed on next bootstrap bump.
 #[cfg(bootstrap)]
 pub fn round_ties_even_f32(x: f32) -> f32 {
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
     #[rustc_nounwind]
-    unsafe fn rintf32(_x: f32) -> f32 {
-        unreachable!()
-    }
+    unsafe fn rintf32(_x: f32) -> f32;
 
     // SAFETY: this intrinsic isn't actually unsafe
     unsafe { rintf32(x) }
@@ -2797,22 +2203,16 @@ pub unsafe fn rintf32(x: f32) -> f32 {
 /// The stabilized version of this intrinsic is
 /// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
 #[cfg(not(bootstrap))]
-pub fn round_ties_even_f64(_x: f64) -> f64 {
-    unreachable!()
-}
+pub fn round_ties_even_f64(_x: f64) -> f64;
 
 /// To be removed on next bootstrap bump.
 #[cfg(bootstrap)]
 pub fn round_ties_even_f64(x: f64) -> f64 {
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
     #[rustc_nounwind]
-    unsafe fn rintf64(_x: f64) -> f64 {
-        unreachable!()
-    }
+    unsafe fn rintf64(_x: f64) -> f64;
 
     // SAFETY: this intrinsic isn't actually unsafe
     unsafe { rintf64(x) }
@@ -2830,22 +2230,16 @@ pub unsafe fn rintf64(x: f64) -> f64 {
 /// The stabilized version of this intrinsic is
 /// [`f128::round_ties_even`](../../std/primitive.f128.html#method.round_ties_even)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
 #[cfg(not(bootstrap))]
-pub fn round_ties_even_f128(_x: f128) -> f128 {
-    unreachable!()
-}
+pub fn round_ties_even_f128(_x: f128) -> f128;
 
 /// To be removed on next bootstrap bump.
 #[cfg(bootstrap)]
 pub fn round_ties_even_f128(x: f128) -> f128 {
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
     #[rustc_nounwind]
-    unsafe fn rintf128(_x: f128) -> f128 {
-        unreachable!()
-    }
+    unsafe fn rintf128(_x: f128) -> f128;
 
     // SAFETY: this intrinsic isn't actually unsafe
     unsafe { rintf128(x) }
@@ -2856,157 +2250,112 @@ pub fn round_ties_even_f128(x: f128) -> f128 {
 /// The stabilized version of this intrinsic is
 /// [`f16::round`](../../std/primitive.f16.html#method.round)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn roundf16(_x: f16) -> f16 {
-    unreachable!()
-}
+pub unsafe fn roundf16(_x: f16) -> f16;
 /// Returns the nearest integer to an `f32`. Rounds half-way cases away from zero.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f32::round`](../../std/primitive.f32.html#method.round)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn roundf32(_x: f32) -> f32 {
-    unreachable!()
-}
+pub unsafe fn roundf32(_x: f32) -> f32;
 /// Returns the nearest integer to an `f64`. Rounds half-way cases away from zero.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f64::round`](../../std/primitive.f64.html#method.round)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn roundf64(_x: f64) -> f64 {
-    unreachable!()
-}
+pub unsafe fn roundf64(_x: f64) -> f64;
 /// Returns the nearest integer to an `f128`. Rounds half-way cases away from zero.
 ///
 /// The stabilized version of this intrinsic is
 /// [`f128::round`](../../std/primitive.f128.html#method.round)
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn roundf128(_x: f128) -> f128 {
-    unreachable!()
-}
+pub unsafe fn roundf128(_x: f128) -> f128;
 
 /// Float addition that allows optimizations based on algebraic rules.
 /// May assume inputs are finite.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn fadd_fast<T: Copy>(_a: T, _b: T) -> T {
-    unreachable!()
-}
+pub unsafe fn fadd_fast<T: Copy>(_a: T, _b: T) -> T;
 
 /// Float subtraction that allows optimizations based on algebraic rules.
 /// May assume inputs are finite.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn fsub_fast<T: Copy>(_a: T, _b: T) -> T {
-    unreachable!()
-}
+pub unsafe fn fsub_fast<T: Copy>(_a: T, _b: T) -> T;
 
 /// Float multiplication that allows optimizations based on algebraic rules.
 /// May assume inputs are finite.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn fmul_fast<T: Copy>(_a: T, _b: T) -> T {
-    unreachable!()
-}
+pub unsafe fn fmul_fast<T: Copy>(_a: T, _b: T) -> T;
 
 /// Float division that allows optimizations based on algebraic rules.
 /// May assume inputs are finite.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn fdiv_fast<T: Copy>(_a: T, _b: T) -> T {
-    unreachable!()
-}
+pub unsafe fn fdiv_fast<T: Copy>(_a: T, _b: T) -> T;
 
 /// Float remainder that allows optimizations based on algebraic rules.
 /// May assume inputs are finite.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn frem_fast<T: Copy>(_a: T, _b: T) -> T {
-    unreachable!()
-}
+pub unsafe fn frem_fast<T: Copy>(_a: T, _b: T) -> T;
 
 /// Converts with LLVM’s fptoui/fptosi, which may return undef for values out of range
 /// (<https://github.com/rust-lang/rust/issues/10184>)
 ///
 /// Stabilized as [`f32::to_int_unchecked`] and [`f64::to_int_unchecked`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int {
-    unreachable!()
-}
+pub unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int;
 
 /// Float addition that allows optimizations based on algebraic rules.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub fn fadd_algebraic<T: Copy>(_a: T, _b: T) -> T {
-    unimplemented!()
-}
+pub fn fadd_algebraic<T: Copy>(_a: T, _b: T) -> T;
 
 /// Float subtraction that allows optimizations based on algebraic rules.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub fn fsub_algebraic<T: Copy>(_a: T, _b: T) -> T {
-    unimplemented!()
-}
+pub fn fsub_algebraic<T: Copy>(_a: T, _b: T) -> T;
 
 /// Float multiplication that allows optimizations based on algebraic rules.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub fn fmul_algebraic<T: Copy>(_a: T, _b: T) -> T {
-    unimplemented!()
-}
+pub fn fmul_algebraic<T: Copy>(_a: T, _b: T) -> T;
 
 /// Float division that allows optimizations based on algebraic rules.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub fn fdiv_algebraic<T: Copy>(_a: T, _b: T) -> T {
-    unimplemented!()
-}
+pub fn fdiv_algebraic<T: Copy>(_a: T, _b: T) -> T;
 
 /// Float remainder that allows optimizations based on algebraic rules.
 ///
 /// This intrinsic does not have a stable counterpart.
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub fn frem_algebraic<T: Copy>(_a: T, _b: T) -> T {
-    unimplemented!()
-}
+pub fn frem_algebraic<T: Copy>(_a: T, _b: T) -> T;
 
 /// Returns the number of bits set in an integer type `T`
 ///
@@ -3021,10 +2370,7 @@ pub fn frem_algebraic<T: Copy>(_a: T, _b: T) -> T {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn ctpop<T: Copy>(_x: T) -> u32 {
-    unimplemented!()
-}
+pub const fn ctpop<T: Copy>(_x: T) -> u32;
 
 /// Returns the number of leading unset bits (zeroes) in an integer type `T`.
 ///
@@ -3065,10 +2411,7 @@ pub const fn ctpop<T: Copy>(_x: T) -> u32 {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn ctlz<T: Copy>(_x: T) -> u32 {
-    unimplemented!()
-}
+pub const fn ctlz<T: Copy>(_x: T) -> u32;
 
 /// Like `ctlz`, but extra-unsafe as it returns `undef` when
 /// given an `x` with value `0`.
@@ -3090,10 +2433,7 @@ pub const fn ctlz<T: Copy>(_x: T) -> u32 {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn ctlz_nonzero<T: Copy>(_x: T) -> u32 {
-    unimplemented!()
-}
+pub const unsafe fn ctlz_nonzero<T: Copy>(_x: T) -> u32;
 
 /// Returns the number of trailing unset bits (zeroes) in an integer type `T`.
 ///
@@ -3134,10 +2474,7 @@ pub const unsafe fn ctlz_nonzero<T: Copy>(_x: T) -> u32 {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn cttz<T: Copy>(_x: T) -> u32 {
-    unimplemented!()
-}
+pub const fn cttz<T: Copy>(_x: T) -> u32;
 
 /// Like `cttz`, but extra-unsafe as it returns `undef` when
 /// given an `x` with value `0`.
@@ -3159,10 +2496,7 @@ pub const fn cttz<T: Copy>(_x: T) -> u32 {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn cttz_nonzero<T: Copy>(_x: T) -> u32 {
-    unimplemented!()
-}
+pub const unsafe fn cttz_nonzero<T: Copy>(_x: T) -> u32;
 
 /// Reverses the bytes in an integer type `T`.
 ///
@@ -3177,10 +2511,7 @@ pub const unsafe fn cttz_nonzero<T: Copy>(_x: T) -> u32 {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn bswap<T: Copy>(_x: T) -> T {
-    unimplemented!()
-}
+pub const fn bswap<T: Copy>(_x: T) -> T;
 
 /// Reverses the bits in an integer type `T`.
 ///
@@ -3195,10 +2526,7 @@ pub const fn bswap<T: Copy>(_x: T) -> T {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn bitreverse<T: Copy>(_x: T) -> T {
-    unimplemented!()
-}
+pub const fn bitreverse<T: Copy>(_x: T) -> T;
 
 /// Does a three-way comparison between the two integer arguments.
 ///
@@ -3208,10 +2536,7 @@ pub const fn bitreverse<T: Copy>(_x: T) -> T {
 ///
 /// The stabilized version of this intrinsic is [`Ord::cmp`].
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn three_way_compare<T: Copy>(_lhs: T, _rhss: T) -> crate::cmp::Ordering {
-    unimplemented!()
-}
+pub const fn three_way_compare<T: Copy>(_lhs: T, _rhss: T) -> crate::cmp::Ordering;
 
 /// Combine two values which have no bits in common.
 ///
@@ -3246,10 +2571,7 @@ pub const unsafe fn disjoint_bitor<T: ~const fallback::DisjointBitOr>(a: T, b: T
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn add_with_overflow<T: Copy>(_x: T, _y: T) -> (T, bool) {
-    unimplemented!()
-}
+pub const fn add_with_overflow<T: Copy>(_x: T, _y: T) -> (T, bool);
 
 /// Performs checked integer subtraction
 ///
@@ -3264,10 +2586,7 @@ pub const fn add_with_overflow<T: Copy>(_x: T, _y: T) -> (T, bool) {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn sub_with_overflow<T: Copy>(_x: T, _y: T) -> (T, bool) {
-    unimplemented!()
-}
+pub const fn sub_with_overflow<T: Copy>(_x: T, _y: T) -> (T, bool);
 
 /// Performs checked integer multiplication
 ///
@@ -3282,10 +2601,7 @@ pub const fn sub_with_overflow<T: Copy>(_x: T, _y: T) -> (T, bool) {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn mul_with_overflow<T: Copy>(_x: T, _y: T) -> (T, bool) {
-    unimplemented!()
-}
+pub const fn mul_with_overflow<T: Copy>(_x: T, _y: T) -> (T, bool);
 
 /// Performs full-width multiplication and addition with a carry:
 /// `multiplier * multiplicand + addend + carry`.
@@ -3321,10 +2637,7 @@ pub const fn carrying_mul_add<T: ~const fallback::CarryingMulAdd<Unsigned = U>,
 /// This intrinsic does not have a stable counterpart.
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn exact_div<T: Copy>(_x: T, _y: T) -> T {
-    unimplemented!()
-}
+pub const unsafe fn exact_div<T: Copy>(_x: T, _y: T) -> T;
 
 /// Performs an unchecked division, resulting in undefined behavior
 /// where `y == 0` or `x == T::MIN && y == -1`
@@ -3335,10 +2648,7 @@ pub const unsafe fn exact_div<T: Copy>(_x: T, _y: T) -> T {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn unchecked_div<T: Copy>(_x: T, _y: T) -> T {
-    unimplemented!()
-}
+pub const unsafe fn unchecked_div<T: Copy>(_x: T, _y: T) -> T;
 /// Returns the remainder of an unchecked division, resulting in
 /// undefined behavior when `y == 0` or `x == T::MIN && y == -1`
 ///
@@ -3348,10 +2658,7 @@ pub const unsafe fn unchecked_div<T: Copy>(_x: T, _y: T) -> T {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn unchecked_rem<T: Copy>(_x: T, _y: T) -> T {
-    unimplemented!()
-}
+pub const unsafe fn unchecked_rem<T: Copy>(_x: T, _y: T) -> T;
 
 /// Performs an unchecked left shift, resulting in undefined behavior when
 /// `y < 0` or `y >= N`, where N is the width of T in bits.
@@ -3362,10 +2669,7 @@ pub const unsafe fn unchecked_rem<T: Copy>(_x: T, _y: T) -> T {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn unchecked_shl<T: Copy, U: Copy>(_x: T, _y: U) -> T {
-    unimplemented!()
-}
+pub const unsafe fn unchecked_shl<T: Copy, U: Copy>(_x: T, _y: U) -> T;
 /// Performs an unchecked right shift, resulting in undefined behavior when
 /// `y < 0` or `y >= N`, where N is the width of T in bits.
 ///
@@ -3375,10 +2679,7 @@ pub const unsafe fn unchecked_shl<T: Copy, U: Copy>(_x: T, _y: U) -> T {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn unchecked_shr<T: Copy, U: Copy>(_x: T, _y: U) -> T {
-    unimplemented!()
-}
+pub const unsafe fn unchecked_shr<T: Copy, U: Copy>(_x: T, _y: U) -> T;
 
 /// Returns the result of an unchecked addition, resulting in
 /// undefined behavior when `x + y > T::MAX` or `x + y < T::MIN`.
@@ -3388,10 +2689,7 @@ pub const unsafe fn unchecked_shr<T: Copy, U: Copy>(_x: T, _y: U) -> T {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn unchecked_add<T: Copy>(_x: T, _y: T) -> T {
-    unimplemented!()
-}
+pub const unsafe fn unchecked_add<T: Copy>(_x: T, _y: T) -> T;
 
 /// Returns the result of an unchecked subtraction, resulting in
 /// undefined behavior when `x - y > T::MAX` or `x - y < T::MIN`.
@@ -3401,10 +2699,7 @@ pub const unsafe fn unchecked_add<T: Copy>(_x: T, _y: T) -> T {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn unchecked_sub<T: Copy>(_x: T, _y: T) -> T {
-    unimplemented!()
-}
+pub const unsafe fn unchecked_sub<T: Copy>(_x: T, _y: T) -> T;
 
 /// Returns the result of an unchecked multiplication, resulting in
 /// undefined behavior when `x * y > T::MAX` or `x * y < T::MIN`.
@@ -3414,10 +2709,7 @@ pub const unsafe fn unchecked_sub<T: Copy>(_x: T, _y: T) -> T {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn unchecked_mul<T: Copy>(_x: T, _y: T) -> T {
-    unimplemented!()
-}
+pub const unsafe fn unchecked_mul<T: Copy>(_x: T, _y: T) -> T;
 
 /// Performs rotate left.
 ///
@@ -3432,10 +2724,7 @@ pub const unsafe fn unchecked_mul<T: Copy>(_x: T, _y: T) -> T {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn rotate_left<T: Copy>(_x: T, _shift: u32) -> T {
-    unimplemented!()
-}
+pub const fn rotate_left<T: Copy>(_x: T, _shift: u32) -> T;
 
 /// Performs rotate right.
 ///
@@ -3450,10 +2739,7 @@ pub const fn rotate_left<T: Copy>(_x: T, _shift: u32) -> T {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn rotate_right<T: Copy>(_x: T, _shift: u32) -> T {
-    unimplemented!()
-}
+pub const fn rotate_right<T: Copy>(_x: T, _shift: u32) -> T;
 
 /// Returns (a + b) mod 2<sup>N</sup>, where N is the width of T in bits.
 ///
@@ -3468,10 +2754,7 @@ pub const fn rotate_right<T: Copy>(_x: T, _shift: u32) -> T {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn wrapping_add<T: Copy>(_a: T, _b: T) -> T {
-    unimplemented!()
-}
+pub const fn wrapping_add<T: Copy>(_a: T, _b: T) -> T;
 /// Returns (a - b) mod 2<sup>N</sup>, where N is the width of T in bits.
 ///
 /// Note that, unlike most intrinsics, this is safe to call;
@@ -3485,10 +2768,7 @@ pub const fn wrapping_add<T: Copy>(_a: T, _b: T) -> T {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn wrapping_sub<T: Copy>(_a: T, _b: T) -> T {
-    unimplemented!()
-}
+pub const fn wrapping_sub<T: Copy>(_a: T, _b: T) -> T;
 /// Returns (a * b) mod 2<sup>N</sup>, where N is the width of T in bits.
 ///
 /// Note that, unlike most intrinsics, this is safe to call;
@@ -3502,10 +2782,7 @@ pub const fn wrapping_sub<T: Copy>(_a: T, _b: T) -> T {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn wrapping_mul<T: Copy>(_a: T, _b: T) -> T {
-    unimplemented!()
-}
+pub const fn wrapping_mul<T: Copy>(_a: T, _b: T) -> T;
 
 /// Computes `a + b`, saturating at numeric bounds.
 ///
@@ -3520,10 +2797,7 @@ pub const fn wrapping_mul<T: Copy>(_a: T, _b: T) -> T {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn saturating_add<T: Copy>(_a: T, _b: T) -> T {
-    unimplemented!()
-}
+pub const fn saturating_add<T: Copy>(_a: T, _b: T) -> T;
 /// Computes `a - b`, saturating at numeric bounds.
 ///
 /// Note that, unlike most intrinsics, this is safe to call;
@@ -3537,10 +2811,7 @@ pub const fn saturating_add<T: Copy>(_a: T, _b: T) -> T {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn saturating_sub<T: Copy>(_a: T, _b: T) -> T {
-    unimplemented!()
-}
+pub const fn saturating_sub<T: Copy>(_a: T, _b: T) -> T;
 
 /// This is an implementation detail of [`crate::ptr::read`] and should
 /// not be used anywhere else.  See its comments for why this exists.
@@ -3551,10 +2822,7 @@ pub const fn saturating_sub<T: Copy>(_a: T, _b: T) -> T {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn read_via_copy<T>(_ptr: *const T) -> T {
-    unimplemented!()
-}
+pub const unsafe fn read_via_copy<T>(_ptr: *const T) -> T;
 
 /// This is an implementation detail of [`crate::ptr::write`] and should
 /// not be used anywhere else.  See its comments for why this exists.
@@ -3565,10 +2833,7 @@ pub const unsafe fn read_via_copy<T>(_ptr: *const T) -> T {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn write_via_move<T>(_ptr: *mut T, _value: T) {
-    unimplemented!()
-}
+pub const unsafe fn write_via_move<T>(_ptr: *mut T, _value: T);
 
 /// Returns the value of the discriminant for the variant in 'v';
 /// if `T` has no discriminant, returns `0`.
@@ -3582,10 +2847,7 @@ pub const unsafe fn write_via_move<T>(_ptr: *mut T, _value: T) {
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn discriminant_value<T>(_v: &T) -> <T as DiscriminantKind>::Discriminant {
-    unimplemented!()
-}
+pub const fn discriminant_value<T>(_v: &T) -> <T as DiscriminantKind>::Discriminant;
 
 /// Rust's "try catch" construct for unwinding. Invokes the function pointer `try_fn` with the
 /// data pointer `data`, and calls `catch_fn` if unwinding occurs while `try_fn` runs.
@@ -3604,15 +2866,12 @@ pub const fn discriminant_value<T>(_v: &T) -> <T as DiscriminantKind>::Discrimin
 /// For more information, see the compiler's source, as well as the documentation for the stable
 /// version of this intrinsic, `std::panic::catch_unwind`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
 pub unsafe fn catch_unwind(
     _try_fn: fn(*mut u8),
     _data: *mut u8,
     _catch_fn: fn(*mut u8, *mut u8),
-) -> i32 {
-    unreachable!()
-}
+) -> i32;
 
 /// Emits a `nontemporal` store, which gives a hint to the CPU that the data should not be held
 /// in cache. Except for performance, this is fully equivalent to `ptr.write(val)`.
@@ -3621,29 +2880,20 @@ pub unsafe fn catch_unwind(
 /// exists, that operation is *not* equivalent to `ptr.write(val)` (`MOVNT` writes can be reordered
 /// in ways that are not allowed for regular writes).
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn nontemporal_store<T>(_ptr: *mut T, _val: T) {
-    unreachable!()
-}
+pub unsafe fn nontemporal_store<T>(_ptr: *mut T, _val: T);
 
 /// See documentation of `<*const T>::offset_from` for details.
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn ptr_offset_from<T>(_ptr: *const T, _base: *const T) -> isize {
-    unimplemented!()
-}
+pub const unsafe fn ptr_offset_from<T>(_ptr: *const T, _base: *const T) -> isize;
 
 /// See documentation of `<*const T>::sub_ptr` for details.
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_intrinsic_const_stable_indirect]
-pub const unsafe fn ptr_offset_from_unsigned<T>(_ptr: *const T, _base: *const T) -> usize {
-    unimplemented!()
-}
+pub const unsafe fn ptr_offset_from_unsigned<T>(_ptr: *const T, _base: *const T) -> usize;
 
 /// See documentation of `<*const T>::guaranteed_eq` for details.
 /// Returns `2` if the result is unknown.
@@ -3683,10 +2933,7 @@ pub const fn ptr_guaranteed_cmp<T>(ptr: *const T, other: *const T) -> u8 {
 /// which is UB if any of their inputs are `undef`.)
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn raw_eq<T>(_a: &T, _b: &T) -> bool {
-    unimplemented!()
-}
+pub const unsafe fn raw_eq<T>(_a: &T, _b: &T) -> bool;
 
 /// Lexicographically compare `[left, left + bytes)` and `[right, right + bytes)`
 /// as unsigned bytes, returning negative if `left` is less, zero if all the
@@ -3704,21 +2951,15 @@ pub const unsafe fn raw_eq<T>(_a: &T, _b: &T) -> bool {
 /// [valid]: crate::ptr#safety
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn compare_bytes(_left: *const u8, _right: *const u8, _bytes: usize) -> i32 {
-    unimplemented!()
-}
+pub const unsafe fn compare_bytes(_left: *const u8, _right: *const u8, _bytes: usize) -> i32;
 
 /// See documentation of [`std::hint::black_box`] for details.
 ///
 /// [`std::hint::black_box`]: crate::hint::black_box
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_intrinsic_const_stable_indirect]
-pub const fn black_box<T>(_dummy: T) -> T {
-    unimplemented!()
-}
+pub const fn black_box<T>(_dummy: T) -> T;
 
 /// Selects which function to call depending on the context.
 ///
@@ -3774,7 +3015,6 @@ pub const fn black_box<T>(_dummy: T) -> T {
 /// otherwise, that principle should not be violated.
 #[rustc_const_unstable(feature = "const_eval_select", issue = "124625")]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 pub const fn const_eval_select<ARG: Tuple, F, G, RET>(
     _arg: ARG,
     _called_in_const: F,
@@ -3782,10 +3022,7 @@ pub const fn const_eval_select<ARG: Tuple, F, G, RET>(
 ) -> RET
 where
     G: FnOnce<ARG, Output = RET>,
-    F: FnOnce<ARG, Output = RET>,
-{
-    unreachable!()
-}
+    F: FnOnce<ARG, Output = RET>;
 
 /// A macro to make it easier to invoke const_eval_select. Use as follows:
 /// ```rust,ignore (just a macro example)
@@ -4081,10 +3318,7 @@ pub fn contract_check_ensures<'a, Ret, C: Fn(&'a Ret) -> bool>(ret: &'a Ret, con
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub unsafe fn vtable_size(_ptr: *const ()) -> usize {
-    unreachable!()
-}
+pub unsafe fn vtable_size(_ptr: *const ()) -> usize;
 
 /// The intrinsic will return the alignment stored in that vtable.
 ///
@@ -4094,10 +3328,7 @@ pub unsafe fn vtable_size(_ptr: *const ()) -> usize {
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub unsafe fn vtable_align(_ptr: *const ()) -> usize {
-    unreachable!()
-}
+pub unsafe fn vtable_align(_ptr: *const ()) -> usize;
 
 /// The size of a type in bytes.
 ///
@@ -4114,10 +3345,7 @@ pub unsafe fn vtable_align(_ptr: *const ()) -> usize {
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn size_of<T>() -> usize {
-    unreachable!()
-}
+pub const fn size_of<T>() -> usize;
 
 /// The minimum alignment of a type.
 ///
@@ -4131,10 +3359,7 @@ pub const fn size_of<T>() -> usize {
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn min_align_of<T>() -> usize {
-    unreachable!()
-}
+pub const fn min_align_of<T>() -> usize;
 
 /// The preferred alignment of a type.
 ///
@@ -4143,10 +3368,7 @@ pub const fn min_align_of<T>() -> usize {
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn pref_align_of<T>() -> usize {
-    unreachable!()
-}
+pub const unsafe fn pref_align_of<T>() -> usize;
 
 /// Returns the number of variants of the type `T` cast to a `usize`;
 /// if `T` has no variants, returns `0`. Uninhabited variants will be counted.
@@ -4160,10 +3382,7 @@ pub const unsafe fn pref_align_of<T>() -> usize {
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn variant_count<T>() -> usize {
-    unreachable!()
-}
+pub const fn variant_count<T>() -> usize;
 
 /// The size of the referenced value in bytes.
 ///
@@ -4175,11 +3394,8 @@ pub const fn variant_count<T>() -> usize {
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_intrinsic_const_stable_indirect]
-pub const unsafe fn size_of_val<T: ?Sized>(_ptr: *const T) -> usize {
-    unreachable!()
-}
+pub const unsafe fn size_of_val<T: ?Sized>(_ptr: *const T) -> usize;
 
 /// The required alignment of the referenced value.
 ///
@@ -4191,11 +3407,8 @@ pub const unsafe fn size_of_val<T: ?Sized>(_ptr: *const T) -> usize {
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_intrinsic_const_stable_indirect]
-pub const unsafe fn min_align_of_val<T: ?Sized>(_ptr: *const T) -> usize {
-    unreachable!()
-}
+pub const unsafe fn min_align_of_val<T: ?Sized>(_ptr: *const T) -> usize;
 
 /// Gets a static string slice containing the name of a type.
 ///
@@ -4208,10 +3421,7 @@ pub const unsafe fn min_align_of_val<T: ?Sized>(_ptr: *const T) -> usize {
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn type_name<T: ?Sized>() -> &'static str {
-    unreachable!()
-}
+pub const fn type_name<T: ?Sized>() -> &'static str;
 
 /// Gets an identifier which is globally unique to the specified type. This
 /// function will return the same value for a type regardless of whichever
@@ -4226,10 +3436,7 @@ pub const fn type_name<T: ?Sized>() -> &'static str {
 #[rustc_nounwind]
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn type_id<T: ?Sized + 'static>() -> u128 {
-    unreachable!()
-}
+pub const fn type_id<T: ?Sized + 'static>() -> u128;
 
 /// Lowers in MIR to `Rvalue::Aggregate` with `AggregateKind::RawPtr`.
 ///
@@ -4240,12 +3447,7 @@ pub const fn type_id<T: ?Sized + 'static>() -> u128 {
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn aggregate_raw_ptr<P: AggregateRawPtr<D, Metadata = M>, D, M>(_data: D, _meta: M) -> P {
-    // To implement a fallback we'd have to assume the layout of the pointer,
-    // but the whole point of this intrinsic is that we shouldn't do that.
-    unreachable!()
-}
+pub const fn aggregate_raw_ptr<P: AggregateRawPtr<D, Metadata = M>, D, M>(_data: D, _meta: M) -> P;
 
 #[unstable(feature = "core_intrinsics", issue = "none")]
 pub trait AggregateRawPtr<D> {
@@ -4265,12 +3467,7 @@ impl<P: ?Sized, T: ptr::Thin> AggregateRawPtr<*mut T> for *mut P {
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(_ptr: *const P) -> M {
-    // To implement a fallback we'd have to assume the layout of the pointer,
-    // but the whole point of this intrinsic is that we shouldn't do that.
-    unreachable!()
-}
+pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(_ptr: *const P) -> M;
 
 // Some functions are defined here because they accidentally got made
 // available in this module on stable. See <https://github.com/rust-lang/rust/issues/15702>.
@@ -4372,10 +3569,7 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
     #[rustc_intrinsic_const_stable_indirect]
     #[rustc_nounwind]
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    const unsafe fn copy_nonoverlapping<T>(_src: *const T, _dst: *mut T, _count: usize) {
-        unreachable!()
-    }
+    const unsafe fn copy_nonoverlapping<T>(_src: *const T, _dst: *mut T, _count: usize);
 
     ub_checks::assert_unsafe_precondition!(
         check_language_ub,
@@ -4476,10 +3670,7 @@ pub const unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
     #[rustc_intrinsic_const_stable_indirect]
     #[rustc_nounwind]
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    const unsafe fn copy<T>(_src: *const T, _dst: *mut T, _count: usize) {
-        unreachable!()
-    }
+    const unsafe fn copy<T>(_src: *const T, _dst: *mut T, _count: usize);
 
     // SAFETY: the safety contract for `copy` must be upheld by the caller.
     unsafe {
@@ -4559,10 +3750,7 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
     #[rustc_intrinsic_const_stable_indirect]
     #[rustc_nounwind]
     #[rustc_intrinsic]
-    #[rustc_intrinsic_must_be_overridden]
-    const unsafe fn write_bytes<T>(_dst: *mut T, _val: u8, _count: usize) {
-        unreachable!()
-    }
+    const unsafe fn write_bytes<T>(_dst: *mut T, _val: u8, _count: usize);
 
     // SAFETY: the safety contract for `write_bytes` must be upheld by the caller.
     unsafe {
@@ -4590,10 +3778,7 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
 /// [`f16::min`]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn minnumf16(_x: f16, _y: f16) -> f16 {
-    unimplemented!();
-}
+pub const fn minnumf16(_x: f16, _y: f16) -> f16;
 
 /// Returns the minimum of two `f32` values.
 ///
@@ -4607,10 +3792,7 @@ pub const fn minnumf16(_x: f16, _y: f16) -> f16 {
 #[rustc_nounwind]
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn minnumf32(_x: f32, _y: f32) -> f32 {
-    unimplemented!();
-}
+pub const fn minnumf32(_x: f32, _y: f32) -> f32;
 
 /// Returns the minimum of two `f64` values.
 ///
@@ -4624,10 +3806,7 @@ pub const fn minnumf32(_x: f32, _y: f32) -> f32 {
 #[rustc_nounwind]
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn minnumf64(_x: f64, _y: f64) -> f64 {
-    unimplemented!();
-}
+pub const fn minnumf64(_x: f64, _y: f64) -> f64;
 
 /// Returns the minimum of two `f128` values.
 ///
@@ -4640,10 +3819,7 @@ pub const fn minnumf64(_x: f64, _y: f64) -> f64 {
 /// [`f128::min`]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn minnumf128(_x: f128, _y: f128) -> f128 {
-    unimplemented!();
-}
+pub const fn minnumf128(_x: f128, _y: f128) -> f128;
 
 /// Returns the maximum of two `f16` values.
 ///
@@ -4656,10 +3832,7 @@ pub const fn minnumf128(_x: f128, _y: f128) -> f128 {
 /// [`f16::max`]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn maxnumf16(_x: f16, _y: f16) -> f16 {
-    unimplemented!();
-}
+pub const fn maxnumf16(_x: f16, _y: f16) -> f16;
 
 /// Returns the maximum of two `f32` values.
 ///
@@ -4673,10 +3846,7 @@ pub const fn maxnumf16(_x: f16, _y: f16) -> f16 {
 #[rustc_nounwind]
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn maxnumf32(_x: f32, _y: f32) -> f32 {
-    unimplemented!();
-}
+pub const fn maxnumf32(_x: f32, _y: f32) -> f32;
 
 /// Returns the maximum of two `f64` values.
 ///
@@ -4690,10 +3860,7 @@ pub const fn maxnumf32(_x: f32, _y: f32) -> f32 {
 #[rustc_nounwind]
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn maxnumf64(_x: f64, _y: f64) -> f64 {
-    unimplemented!();
-}
+pub const fn maxnumf64(_x: f64, _y: f64) -> f64;
 
 /// Returns the maximum of two `f128` values.
 ///
@@ -4706,10 +3873,7 @@ pub const fn maxnumf64(_x: f64, _y: f64) -> f64 {
 /// [`f128::max`]
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const fn maxnumf128(_x: f128, _y: f128) -> f128 {
-    unimplemented!();
-}
+pub const fn maxnumf128(_x: f128, _y: f128) -> f128;
 
 /// Returns the absolute value of an `f16`.
 ///
@@ -4717,10 +3881,7 @@ pub const fn maxnumf128(_x: f128, _y: f128) -> f128 {
 /// [`f16::abs`](../../std/primitive.f16.html#method.abs)
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn fabsf16(_x: f16) -> f16 {
-    unimplemented!();
-}
+pub const unsafe fn fabsf16(_x: f16) -> f16;
 
 /// Returns the absolute value of an `f32`.
 ///
@@ -4729,10 +3890,7 @@ pub const unsafe fn fabsf16(_x: f16) -> f16 {
 #[rustc_nounwind]
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn fabsf32(_x: f32) -> f32 {
-    unimplemented!();
-}
+pub const unsafe fn fabsf32(_x: f32) -> f32;
 
 /// Returns the absolute value of an `f64`.
 ///
@@ -4741,10 +3899,7 @@ pub const unsafe fn fabsf32(_x: f32) -> f32 {
 #[rustc_nounwind]
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn fabsf64(_x: f64) -> f64 {
-    unimplemented!();
-}
+pub const unsafe fn fabsf64(_x: f64) -> f64;
 
 /// Returns the absolute value of an `f128`.
 ///
@@ -4752,10 +3907,7 @@ pub const unsafe fn fabsf64(_x: f64) -> f64 {
 /// [`f128::abs`](../../std/primitive.f128.html#method.abs)
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn fabsf128(_x: f128) -> f128 {
-    unimplemented!();
-}
+pub const unsafe fn fabsf128(_x: f128) -> f128;
 
 /// Copies the sign from `y` to `x` for `f16` values.
 ///
@@ -4763,10 +3915,7 @@ pub const unsafe fn fabsf128(_x: f128) -> f128 {
 /// [`f16::copysign`](../../std/primitive.f16.html#method.copysign)
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn copysignf16(_x: f16, _y: f16) -> f16 {
-    unimplemented!();
-}
+pub const unsafe fn copysignf16(_x: f16, _y: f16) -> f16;
 
 /// Copies the sign from `y` to `x` for `f32` values.
 ///
@@ -4775,10 +3924,7 @@ pub const unsafe fn copysignf16(_x: f16, _y: f16) -> f16 {
 #[rustc_nounwind]
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn copysignf32(_x: f32, _y: f32) -> f32 {
-    unimplemented!();
-}
+pub const unsafe fn copysignf32(_x: f32, _y: f32) -> f32;
 /// Copies the sign from `y` to `x` for `f64` values.
 ///
 /// The stabilized version of this intrinsic is
@@ -4786,10 +3932,7 @@ pub const unsafe fn copysignf32(_x: f32, _y: f32) -> f32 {
 #[rustc_nounwind]
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn copysignf64(_x: f64, _y: f64) -> f64 {
-    unimplemented!();
-}
+pub const unsafe fn copysignf64(_x: f64, _y: f64) -> f64;
 
 /// Copies the sign from `y` to `x` for `f128` values.
 ///
@@ -4797,10 +3940,7 @@ pub const unsafe fn copysignf64(_x: f64, _y: f64) -> f64 {
 /// [`f128::copysign`](../../std/primitive.f128.html#method.copysign)
 #[rustc_nounwind]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn copysignf128(_x: f128, _y: f128) -> f128 {
-    unimplemented!();
-}
+pub const unsafe fn copysignf128(_x: f128, _y: f128) -> f128;
 
 /// Inform Miri that a given pointer definitely has a certain alignment.
 #[cfg(miri)]
diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs
index e59d3aff379..3bde183fefb 100644
--- a/library/core/src/intrinsics/simd.rs
+++ b/library/core/src/intrinsics/simd.rs
@@ -10,11 +10,8 @@
 ///
 /// `idx` must be in-bounds of the vector.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_insert<T, U>(_x: T, _idx: u32, _val: U) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_insert<T, U>(_x: T, _idx: u32, _val: U) -> T;
 
 /// Extracts an element from a vector.
 ///
@@ -24,41 +21,29 @@ pub unsafe fn simd_insert<T, U>(_x: T, _idx: u32, _val: U) -> T {
 ///
 /// `idx` must be in-bounds of the vector.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_extract<T, U>(_x: T, _idx: u32) -> U {
-    unreachable!()
-}
+pub unsafe fn simd_extract<T, U>(_x: T, _idx: u32) -> U;
 
 /// Adds two simd vectors elementwise.
 ///
 /// `T` must be a vector of integer or floating point primitive types.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_add<T>(_x: T, _y: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_add<T>(_x: T, _y: T) -> T;
 
 /// Subtracts `rhs` from `lhs` elementwise.
 ///
 /// `T` must be a vector of integer or floating point primitive types.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_sub<T>(_lhs: T, _rhs: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_sub<T>(_lhs: T, _rhs: T) -> T;
 
 /// Multiplies two simd vectors elementwise.
 ///
 /// `T` must be a vector of integer or floating point primitive types.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_mul<T>(_x: T, _y: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_mul<T>(_x: T, _y: T) -> T;
 
 /// Divides `lhs` by `rhs` elementwise.
 ///
@@ -68,11 +53,8 @@ pub unsafe fn simd_mul<T>(_x: T, _y: T) -> T {
 /// For integers, `rhs` must not contain any zero elements.
 /// Additionally for signed integers, `<int>::MIN / -1` is undefined behavior.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_div<T>(_lhs: T, _rhs: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_div<T>(_lhs: T, _rhs: T) -> T;
 
 /// Returns remainder of two vectors elementwise.
 ///
@@ -82,11 +64,8 @@ pub unsafe fn simd_div<T>(_lhs: T, _rhs: T) -> T {
 /// For integers, `rhs` must not contain any zero elements.
 /// Additionally for signed integers, `<int>::MIN / -1` is undefined behavior.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_rem<T>(_lhs: T, _rhs: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_rem<T>(_lhs: T, _rhs: T) -> T;
 
 /// Shifts vector left elementwise, with UB on overflow.
 ///
@@ -98,11 +77,8 @@ pub unsafe fn simd_rem<T>(_lhs: T, _rhs: T) -> T {
 ///
 /// Each element of `rhs` must be less than `<int>::BITS`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_shl<T>(_lhs: T, _rhs: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_shl<T>(_lhs: T, _rhs: T) -> T;
 
 /// Shifts vector right elementwise, with UB on overflow.
 ///
@@ -114,41 +90,29 @@ pub unsafe fn simd_shl<T>(_lhs: T, _rhs: T) -> T {
 ///
 /// Each element of `rhs` must be less than `<int>::BITS`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_shr<T>(_lhs: T, _rhs: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_shr<T>(_lhs: T, _rhs: T) -> T;
 
 /// "Ands" vectors elementwise.
 ///
 /// `T` must be a vector of integer primitive types.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_and<T>(_x: T, _y: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_and<T>(_x: T, _y: T) -> T;
 
 /// "Ors" vectors elementwise.
 ///
 /// `T` must be a vector of integer primitive types.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_or<T>(_x: T, _y: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_or<T>(_x: T, _y: T) -> T;
 
 /// "Exclusive ors" vectors elementwise.
 ///
 /// `T` must be a vector of integer primitive types.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_xor<T>(_x: T, _y: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_xor<T>(_x: T, _y: T) -> T;
 
 /// Numerically casts a vector, elementwise.
 ///
@@ -169,11 +133,8 @@ pub unsafe fn simd_xor<T>(_x: T, _y: T) -> T {
 /// * Not be infinite
 /// * Be representable in the return type, after truncating off its fractional part
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_cast<T, U>(_x: T) -> U {
-    unreachable!()
-}
+pub unsafe fn simd_cast<T, U>(_x: T) -> U;
 
 /// Numerically casts a vector, elementwise.
 ///
@@ -187,11 +148,8 @@ pub unsafe fn simd_cast<T, U>(_x: T) -> U {
 /// When casting integers to floats, the result is rounded.
 /// Otherwise, truncates or extends the value, maintaining the sign for signed integers.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_as<T, U>(_x: T) -> U {
-    unreachable!()
-}
+pub unsafe fn simd_as<T, U>(_x: T) -> U;
 
 /// Negates a vector elementwise.
 ///
@@ -199,21 +157,15 @@ pub unsafe fn simd_as<T, U>(_x: T) -> U {
 ///
 /// Rust panics for `-<int>::Min` due to overflow, but it is not UB with this intrinsic.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_neg<T>(_x: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_neg<T>(_x: T) -> T;
 
 /// Returns absolute value of a vector, elementwise.
 ///
 /// `T` must be a vector of floating-point primitive types.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_fabs<T>(_x: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_fabs<T>(_x: T) -> T;
 
 /// Returns the minimum of two vectors, elementwise.
 ///
@@ -221,11 +173,8 @@ pub unsafe fn simd_fabs<T>(_x: T) -> T {
 ///
 /// Follows IEEE-754 `minNum` semantics.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_fmin<T>(_x: T, _y: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_fmin<T>(_x: T, _y: T) -> T;
 
 /// Returns the maximum of two vectors, elementwise.
 ///
@@ -233,11 +182,8 @@ pub unsafe fn simd_fmin<T>(_x: T, _y: T) -> T {
 ///
 /// Follows IEEE-754 `maxNum` semantics.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_fmax<T>(_x: T, _y: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_fmax<T>(_x: T, _y: T) -> T;
 
 /// Tests elementwise equality of two vectors.
 ///
@@ -247,11 +193,8 @@ pub unsafe fn simd_fmax<T>(_x: T, _y: T) -> T {
 ///
 /// Returns `0` for false and `!0` for true.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_eq<T, U>(_x: T, _y: T) -> U {
-    unreachable!()
-}
+pub unsafe fn simd_eq<T, U>(_x: T, _y: T) -> U;
 
 /// Tests elementwise inequality equality of two vectors.
 ///
@@ -261,11 +204,8 @@ pub unsafe fn simd_eq<T, U>(_x: T, _y: T) -> U {
 ///
 /// Returns `0` for false and `!0` for true.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_ne<T, U>(_x: T, _y: T) -> U {
-    unreachable!()
-}
+pub unsafe fn simd_ne<T, U>(_x: T, _y: T) -> U;
 
 /// Tests if `x` is less than `y`, elementwise.
 ///
@@ -275,11 +215,8 @@ pub unsafe fn simd_ne<T, U>(_x: T, _y: T) -> U {
 ///
 /// Returns `0` for false and `!0` for true.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_lt<T, U>(_x: T, _y: T) -> U {
-    unreachable!()
-}
+pub unsafe fn simd_lt<T, U>(_x: T, _y: T) -> U;
 
 /// Tests if `x` is less than or equal to `y`, elementwise.
 ///
@@ -289,11 +226,8 @@ pub unsafe fn simd_lt<T, U>(_x: T, _y: T) -> U {
 ///
 /// Returns `0` for false and `!0` for true.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_le<T, U>(_x: T, _y: T) -> U {
-    unreachable!()
-}
+pub unsafe fn simd_le<T, U>(_x: T, _y: T) -> U;
 
 /// Tests if `x` is greater than `y`, elementwise.
 ///
@@ -303,11 +237,8 @@ pub unsafe fn simd_le<T, U>(_x: T, _y: T) -> U {
 ///
 /// Returns `0` for false and `!0` for true.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_gt<T, U>(_x: T, _y: T) -> U {
-    unreachable!()
-}
+pub unsafe fn simd_gt<T, U>(_x: T, _y: T) -> U;
 
 /// Tests if `x` is greater than or equal to `y`, elementwise.
 ///
@@ -317,11 +248,8 @@ pub unsafe fn simd_gt<T, U>(_x: T, _y: T) -> U {
 ///
 /// Returns `0` for false and `!0` for true.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_ge<T, U>(_x: T, _y: T) -> U {
-    unreachable!()
-}
+pub unsafe fn simd_ge<T, U>(_x: T, _y: T) -> U;
 
 /// Shuffles two vectors by const indices.
 ///
@@ -336,11 +264,8 @@ pub unsafe fn simd_ge<T, U>(_x: T, _y: T) -> U {
 /// is the concatenation of `x` and `y`. It is a compile-time error if `idx[i]` is out-of-bounds
 /// of `xy`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_shuffle<T, U, V>(_x: T, _y: T, _idx: U) -> V {
-    unreachable!()
-}
+pub unsafe fn simd_shuffle<T, U, V>(_x: T, _y: T, _idx: U) -> V;
 
 /// Reads a vector of pointers.
 ///
@@ -360,11 +285,8 @@ pub unsafe fn simd_shuffle<T, U, V>(_x: T, _y: T, _idx: U) -> V {
 ///
 /// `mask` must only contain `0` or `!0` values.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_gather<T, U, V>(_val: T, _ptr: U, _mask: V) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_gather<T, U, V>(_val: T, _ptr: U, _mask: V) -> T;
 
 /// Writes to a vector of pointers.
 ///
@@ -387,11 +309,8 @@ pub unsafe fn simd_gather<T, U, V>(_val: T, _ptr: U, _mask: V) -> T {
 ///
 /// `mask` must only contain `0` or `!0` values.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_scatter<T, U, V>(_val: T, _ptr: U, _mask: V) {
-    unreachable!()
-}
+pub unsafe fn simd_scatter<T, U, V>(_val: T, _ptr: U, _mask: V);
 
 /// Reads a vector of pointers.
 ///
@@ -413,11 +332,8 @@ pub unsafe fn simd_scatter<T, U, V>(_val: T, _ptr: U, _mask: V) {
 ///
 /// `mask` must only contain `0` or `!0` values.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_masked_load<V, U, T>(_mask: V, _ptr: U, _val: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_masked_load<V, U, T>(_mask: V, _ptr: U, _val: T) -> T;
 
 /// Writes to a vector of pointers.
 ///
@@ -438,21 +354,15 @@ pub unsafe fn simd_masked_load<V, U, T>(_mask: V, _ptr: U, _val: T) -> T {
 ///
 /// `mask` must only contain `0` or `!0` values.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_masked_store<V, U, T>(_mask: V, _ptr: U, _val: T) {
-    unreachable!()
-}
+pub unsafe fn simd_masked_store<V, U, T>(_mask: V, _ptr: U, _val: T);
 
 /// Adds two simd vectors elementwise, with saturation.
 ///
 /// `T` must be a vector of integer primitive types.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_saturating_add<T>(_x: T, _y: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_saturating_add<T>(_x: T, _y: T) -> T;
 
 /// Subtracts two simd vectors elementwise, with saturation.
 ///
@@ -460,11 +370,8 @@ pub unsafe fn simd_saturating_add<T>(_x: T, _y: T) -> T {
 ///
 /// Subtract `rhs` from `lhs`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_saturating_sub<T>(_lhs: T, _rhs: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_saturating_sub<T>(_lhs: T, _rhs: T) -> T;
 
 /// Adds elements within a vector from left to right.
 ///
@@ -474,11 +381,8 @@ pub unsafe fn simd_saturating_sub<T>(_lhs: T, _rhs: T) -> T {
 ///
 /// Starting with the value `y`, add the elements of `x` and accumulate.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_reduce_add_ordered<T, U>(_x: T, _y: U) -> U {
-    unreachable!()
-}
+pub unsafe fn simd_reduce_add_ordered<T, U>(_x: T, _y: U) -> U;
 
 /// Adds elements within a vector in arbitrary order. May also be re-associated with
 /// unordered additions on the inputs/outputs.
@@ -487,11 +391,8 @@ pub unsafe fn simd_reduce_add_ordered<T, U>(_x: T, _y: U) -> U {
 ///
 /// `U` must be the element type of `T`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_reduce_add_unordered<T, U>(_x: T) -> U {
-    unreachable!()
-}
+pub unsafe fn simd_reduce_add_unordered<T, U>(_x: T) -> U;
 
 /// Multiplies elements within a vector from left to right.
 ///
@@ -501,11 +402,8 @@ pub unsafe fn simd_reduce_add_unordered<T, U>(_x: T) -> U {
 ///
 /// Starting with the value `y`, multiply the elements of `x` and accumulate.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_reduce_mul_ordered<T, U>(_x: T, _y: U) -> U {
-    unreachable!()
-}
+pub unsafe fn simd_reduce_mul_ordered<T, U>(_x: T, _y: U) -> U;
 
 /// Multiplies elements within a vector in arbitrary order. May also be re-associated with
 /// unordered additions on the inputs/outputs.
@@ -514,11 +412,8 @@ pub unsafe fn simd_reduce_mul_ordered<T, U>(_x: T, _y: U) -> U {
 ///
 /// `U` must be the element type of `T`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_reduce_mul_unordered<T, U>(_x: T) -> U {
-    unreachable!()
-}
+pub unsafe fn simd_reduce_mul_unordered<T, U>(_x: T) -> U;
 
 /// Checks if all mask values are true.
 ///
@@ -527,11 +422,8 @@ pub unsafe fn simd_reduce_mul_unordered<T, U>(_x: T) -> U {
 /// # Safety
 /// `x` must contain only `0` or `!0`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_reduce_all<T>(_x: T) -> bool {
-    unreachable!()
-}
+pub unsafe fn simd_reduce_all<T>(_x: T) -> bool;
 
 /// Checks if any mask value is true.
 ///
@@ -540,11 +432,8 @@ pub unsafe fn simd_reduce_all<T>(_x: T) -> bool {
 /// # Safety
 /// `x` must contain only `0` or `!0`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_reduce_any<T>(_x: T) -> bool {
-    unreachable!()
-}
+pub unsafe fn simd_reduce_any<T>(_x: T) -> bool;
 
 /// Returns the maximum element of a vector.
 ///
@@ -554,11 +443,8 @@ pub unsafe fn simd_reduce_any<T>(_x: T) -> bool {
 ///
 /// For floating-point values, uses IEEE-754 `maxNum`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_reduce_max<T, U>(_x: T) -> U {
-    unreachable!()
-}
+pub unsafe fn simd_reduce_max<T, U>(_x: T) -> U;
 
 /// Returns the minimum element of a vector.
 ///
@@ -568,11 +454,8 @@ pub unsafe fn simd_reduce_max<T, U>(_x: T) -> U {
 ///
 /// For floating-point values, uses IEEE-754 `minNum`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_reduce_min<T, U>(_x: T) -> U {
-    unreachable!()
-}
+pub unsafe fn simd_reduce_min<T, U>(_x: T) -> U;
 
 /// Logical "ands" all elements together.
 ///
@@ -580,11 +463,8 @@ pub unsafe fn simd_reduce_min<T, U>(_x: T) -> U {
 ///
 /// `U` must be the element type of `T`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_reduce_and<T, U>(_x: T) -> U {
-    unreachable!()
-}
+pub unsafe fn simd_reduce_and<T, U>(_x: T) -> U;
 
 /// Logical "ors" all elements together.
 ///
@@ -592,11 +472,8 @@ pub unsafe fn simd_reduce_and<T, U>(_x: T) -> U {
 ///
 /// `U` must be the element type of `T`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_reduce_or<T, U>(_x: T) -> U {
-    unreachable!()
-}
+pub unsafe fn simd_reduce_or<T, U>(_x: T) -> U;
 
 /// Logical "exclusive ors" all elements together.
 ///
@@ -604,11 +481,8 @@ pub unsafe fn simd_reduce_or<T, U>(_x: T) -> U {
 ///
 /// `U` must be the element type of `T`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_reduce_xor<T, U>(_x: T) -> U {
-    unreachable!()
-}
+pub unsafe fn simd_reduce_xor<T, U>(_x: T) -> U;
 
 /// Truncates an integer vector to a bitmask.
 ///
@@ -644,11 +518,8 @@ pub unsafe fn simd_reduce_xor<T, U>(_x: T) -> U {
 /// # Safety
 /// `x` must contain only `0` and `!0`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_bitmask<T, U>(_x: T) -> U {
-    unreachable!()
-}
+pub unsafe fn simd_bitmask<T, U>(_x: T) -> U;
 
 /// Selects elements from a mask.
 ///
@@ -663,11 +534,8 @@ pub unsafe fn simd_bitmask<T, U>(_x: T) -> U {
 /// # Safety
 /// `mask` must only contain `0` and `!0`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_select<M, T>(_mask: M, _if_true: T, _if_false: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_select<M, T>(_mask: M, _if_true: T, _if_false: T) -> T;
 
 /// Selects elements from a bitmask.
 ///
@@ -684,11 +552,8 @@ pub unsafe fn simd_select<M, T>(_mask: M, _if_true: T, _if_false: T) -> T {
 /// # Safety
 /// Padding bits must be all zero.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_select_bitmask<M, T>(_m: M, _yes: T, _no: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_select_bitmask<M, T>(_m: M, _yes: T, _no: T) -> T;
 
 /// Calculates the offset from a pointer vector elementwise, potentially
 /// wrapping.
@@ -699,21 +564,15 @@ pub unsafe fn simd_select_bitmask<M, T>(_m: M, _yes: T, _no: T) -> T {
 ///
 /// Operates as if by `<ptr>::wrapping_offset`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_arith_offset<T, U>(_ptr: T, _offset: U) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_arith_offset<T, U>(_ptr: T, _offset: U) -> T;
 
 /// Casts a vector of pointers.
 ///
 /// `T` and `U` must be vectors of pointers with the same number of elements.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_cast_ptr<T, U>(_ptr: T) -> U {
-    unreachable!()
-}
+pub unsafe fn simd_cast_ptr<T, U>(_ptr: T) -> U;
 
 /// Exposes a vector of pointers as a vector of addresses.
 ///
@@ -721,11 +580,8 @@ pub unsafe fn simd_cast_ptr<T, U>(_ptr: T) -> U {
 ///
 /// `U` must be a vector of `usize` with the same length as `T`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_expose_provenance<T, U>(_ptr: T) -> U {
-    unreachable!()
-}
+pub unsafe fn simd_expose_provenance<T, U>(_ptr: T) -> U;
 
 /// Creates a vector of pointers from a vector of addresses.
 ///
@@ -733,123 +589,87 @@ pub unsafe fn simd_expose_provenance<T, U>(_ptr: T) -> U {
 ///
 /// `U` must be a vector of pointers, with the same length as `T`.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_with_exposed_provenance<T, U>(_addr: T) -> U {
-    unreachable!()
-}
+pub unsafe fn simd_with_exposed_provenance<T, U>(_addr: T) -> U;
 
 /// Swaps bytes of each element.
 ///
 /// `T` must be a vector of integers.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_bswap<T>(_x: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_bswap<T>(_x: T) -> T;
 
 /// Reverses bits of each element.
 ///
 /// `T` must be a vector of integers.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_bitreverse<T>(_x: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_bitreverse<T>(_x: T) -> T;
 
 /// Counts the leading zeros of each element.
 ///
 /// `T` must be a vector of integers.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_ctlz<T>(_x: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_ctlz<T>(_x: T) -> T;
 
 /// Counts the number of ones in each element.
 ///
 /// `T` must be a vector of integers.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_ctpop<T>(_x: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_ctpop<T>(_x: T) -> T;
 
 /// Counts the trailing zeros of each element.
 ///
 /// `T` must be a vector of integers.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_cttz<T>(_x: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_cttz<T>(_x: T) -> T;
 
 /// Rounds up each element to the next highest integer-valued float.
 ///
 /// `T` must be a vector of floats.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_ceil<T>(_x: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_ceil<T>(_x: T) -> T;
 
 /// Rounds down each element to the next lowest integer-valued float.
 ///
 /// `T` must be a vector of floats.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_floor<T>(_x: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_floor<T>(_x: T) -> T;
 
 /// Rounds each element to the closest integer-valued float.
 /// Ties are resolved by rounding away from 0.
 ///
 /// `T` must be a vector of floats.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_round<T>(_x: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_round<T>(_x: T) -> T;
 
 /// Returns the integer part of each element as an integer-valued float.
 /// In other words, non-integer values are truncated towards zero.
 ///
 /// `T` must be a vector of floats.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_trunc<T>(_x: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_trunc<T>(_x: T) -> T;
 
 /// Takes the square root of each element.
 ///
 /// `T` must be a vector of floats.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_fsqrt<T>(_x: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_fsqrt<T>(_x: T) -> T;
 
 /// Computes `(x*y) + z` for each element, but without any intermediate rounding.
 ///
 /// `T` must be a vector of floats.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_fma<T>(_x: T, _y: T, _z: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_fma<T>(_x: T, _y: T, _z: T) -> T;
 
 /// Computes `(x*y) + z` for each element, non-deterministically executing either
 /// a fused multiply-add or two operations with rounding of the intermediate result.
@@ -863,78 +683,54 @@ pub unsafe fn simd_fma<T>(_x: T, _y: T, _z: T) -> T {
 ///
 /// `T` must be a vector of floats.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_relaxed_fma<T>(_x: T, _y: T, _z: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_relaxed_fma<T>(_x: T, _y: T, _z: T) -> T;
 
 // Computes the sine of each element.
 ///
 /// `T` must be a vector of floats.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_fsin<T>(_a: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_fsin<T>(_a: T) -> T;
 
 // Computes the cosine of each element.
 ///
 /// `T` must be a vector of floats.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_fcos<T>(_a: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_fcos<T>(_a: T) -> T;
 
 // Computes the exponential function of each element.
 ///
 /// `T` must be a vector of floats.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_fexp<T>(_a: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_fexp<T>(_a: T) -> T;
 
 // Computes 2 raised to the power of each element.
 ///
 /// `T` must be a vector of floats.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_fexp2<T>(_a: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_fexp2<T>(_a: T) -> T;
 
 // Computes the base 10 logarithm of each element.
 ///
 /// `T` must be a vector of floats.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_flog10<T>(_a: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_flog10<T>(_a: T) -> T;
 
 // Computes the base 2 logarithm of each element.
 ///
 /// `T` must be a vector of floats.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_flog2<T>(_a: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_flog2<T>(_a: T) -> T;
 
 // Computes the natural logarithm of each element.
 ///
 /// `T` must be a vector of floats.
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
 #[rustc_nounwind]
-pub unsafe fn simd_flog<T>(_a: T) -> T {
-    unreachable!()
-}
+pub unsafe fn simd_flog<T>(_a: T) -> T;
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 842a48e1606..b0571bf7247 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -1302,6 +1302,7 @@ pub trait FnPtr: Copy + Clone {
 /// ```
 #[rustc_builtin_macro(CoercePointee, attributes(pointee))]
 #[allow_internal_unstable(dispatch_from_dyn, coerce_unsized, unsize, coerce_pointee_validated)]
+#[cfg_attr(not(test), rustc_diagnostic_item = "CoercePointee")]
 #[unstable(feature = "derive_coerce_pointee", issue = "123430")]
 pub macro CoercePointee($item:item) {
     /* compiler built-in */
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index adbd6889624..4a071b4e1fa 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -668,7 +668,9 @@ pub fn home_dir() -> Option<PathBuf> {
 /// On Unix, returns the value of the `TMPDIR` environment variable if it is
 /// set, otherwise the value is OS-specific:
 /// - On Android, there is no global temporary folder (it is usually allocated
-///   per-app), it returns `/data/local/tmp`.
+///   per-app), it will return the application's cache dir if the program runs
+///   in application's namespace and system version is Android 13 (or above), or
+///   `/data/local/tmp` otherwise.
 /// - On Darwin-based OSes (macOS, iOS, etc) it returns the directory provided
 ///   by `confstr(_CS_DARWIN_USER_TEMP_DIR, ...)`, as recommended by [Apple's
 ///   security guidelines][appledoc].
diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs
index c7833c7dc71..38dcd816d26 100644
--- a/library/std/src/fs/tests.rs
+++ b/library/std/src/fs/tests.rs
@@ -1962,6 +1962,10 @@ fn test_rename_directory_to_non_empty_directory() {
 #[test]
 fn test_rename_symlink() {
     let tmpdir = tmpdir();
+    if !got_symlink_permission(&tmpdir) {
+        return;
+    };
+
     let original = tmpdir.join("original");
     let dest = tmpdir.join("dest");
     let not_exist = Path::new("does not exist");
diff --git a/src/doc/book b/src/doc/book
-Subproject d4d2c18cbd20876b2130a546e790446a8444cb3
+Subproject 4a01a9182496f807aaa5f72d93a25ce18bcbe10
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
-Subproject 8dbdda7cae4fa030f09f8f5b63994d4d1dde74b
+Subproject daa4b763cd848f986813b5cf8069e1649f7147a
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject 336f75835a6c0514852cc65aba9a698b699b13c
+Subproject 8f5c7322b65d079aa5b242eb10d89a98e12471e
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 6195dbd70fc6f0980c314b4d23875ac570d8253
+Subproject 615b4cec60c269cfc105d511c93287620032d5b
diff --git a/src/doc/unstable-book/src/language-features/intrinsics.md b/src/doc/unstable-book/src/language-features/intrinsics.md
index 13a6814d31b..975b400447e 100644
--- a/src/doc/unstable-book/src/language-features/intrinsics.md
+++ b/src/doc/unstable-book/src/language-features/intrinsics.md
@@ -62,13 +62,19 @@ These must be implemented by all backends.
 
 ### `#[rustc_intrinsic]` declarations
 
-These are written like intrinsics with fallback bodies, but the body is irrelevant.
-Use `loop {}` for the body or call the intrinsic recursively and add
-`#[rustc_intrinsic_must_be_overridden]` to the function to ensure that backends don't
-invoke the body.
+These are written without a body:
+```rust
+#![feature(intrinsics)]
+#![allow(internal_features)]
+
+#[rustc_intrinsic]
+pub fn abort() -> !;
+```
 
 ### Legacy extern ABI based intrinsics
 
+*This style is deprecated, always prefer the above form.*
+
 These are imported as if they were FFI functions, with the special
 `rust-intrinsic` ABI. For example, if one was in a freestanding
 context, but wished to be able to `transmute` between types, and
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index dcc5fd12d81..ceffe5e5ce0 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2737,13 +2737,13 @@ fn add_without_unwanted_attributes<'hir>(
     import_parent: Option<DefId>,
 ) {
     for attr in new_attrs {
-        if matches!(attr.kind, hir::AttrKind::DocComment(..)) {
+        if attr.is_doc_comment() {
             attrs.push((Cow::Borrowed(attr), import_parent));
             continue;
         }
         let mut attr = attr.clone();
-        match attr.kind {
-            hir::AttrKind::Normal(ref mut normal) => {
+        match attr {
+            hir::Attribute::Unparsed(ref mut normal) => {
                 if let [ident] = &*normal.path.segments {
                     let ident = ident.name;
                     if ident == sym::doc {
@@ -2755,7 +2755,11 @@ fn add_without_unwanted_attributes<'hir>(
                     }
                 }
             }
-            _ => unreachable!(),
+            hir::Attribute::Parsed(..) => {
+                if is_inline {
+                    attrs.push((Cow::Owned(attr), import_parent));
+                }
+            }
         }
     }
 }
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index fc7c4b42047..178b6a60b41 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -265,7 +265,7 @@ impl ExternalCrate {
                     let attr_value = attr.value_str().expect("syntax should already be validated");
                     let Some(prim) = PrimitiveType::from_symbol(attr_value) else {
                         span_bug!(
-                            attr.span,
+                            attr.span(),
                             "primitive `{attr_value}` is not a member of `PrimitiveType`"
                         );
                     };
diff --git a/src/librustdoc/doctest/rust.rs b/src/librustdoc/doctest/rust.rs
index 1ac3c040b59..3ac7abd0aa5 100644
--- a/src/librustdoc/doctest/rust.rs
+++ b/src/librustdoc/doctest/rust.rs
@@ -123,7 +123,7 @@ impl HirCollector<'_> {
                     .iter()
                     .find(|attr| attr.doc_str().is_some())
                     .map(|attr| {
-                        attr.span.ctxt().outer_expn().expansion_cause().unwrap_or(attr.span)
+                        attr.span().ctxt().outer_expn().expansion_cause().unwrap_or(attr.span())
                     })
                     .unwrap_or(DUMMY_SP)
             };
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index a92f3ded774..8f6496e9626 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -30,7 +30,7 @@ pub type FxHashMap<K, V> = HashMap<K, V>; // re-export for use in src/librustdoc
 /// This integer is incremented with every breaking change to the API,
 /// and is returned along with the JSON blob as [`Crate::format_version`].
 /// Consuming code should assert that this value matches the format version(s) that it supports.
-pub const FORMAT_VERSION: u32 = 39;
+pub const FORMAT_VERSION: u32 = 40;
 
 /// The root of the emitted JSON blob.
 ///
@@ -120,7 +120,9 @@ pub struct Item {
     pub docs: Option<String>,
     /// This mapping resolves [intra-doc links](https://github.com/rust-lang/rfcs/blob/master/text/1946-intra-rustdoc-links.md) from the docstring to their IDs
     pub links: HashMap<String, Id>,
-    /// Stringified versions of the attributes on this item (e.g. `"#[inline]"`)
+    /// Stringified versions of parsed attributes on this item.
+    /// Essentially debug printed (e.g. `#[inline]` becomes something similar to `#[attr="Inline(Hint)"]`).
+    /// Equivalent to the hir pretty-printing of attributes.
     pub attrs: Vec<String>,
     /// Information about the item’s deprecation, if present.
     pub deprecation: Option<Deprecation>,
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 1d1d646c06a84c1aa53967b394b7f1218f85db8
+Subproject ce948f4616e3d4277e30c75c8bb01e094910df3
diff --git a/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs b/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs
index 2325f914b0b..cb63fadb4e2 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs
@@ -20,7 +20,7 @@ pub(super) fn check(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Att
                 span_lint(
                     cx,
                     INLINE_ALWAYS,
-                    attr.span,
+                    attr.span(),
                     format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"),
                 );
             }
diff --git a/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs
index 6d1ab46aa0c..6cc47596bbb 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs
@@ -1,6 +1,7 @@
+use rustc_attr_parsing::{find_attr, AttributeKind, ReprAttr};
 use rustc_hir::Attribute;
 use rustc_lint::LateContext;
-use rustc_span::{Span, sym};
+use rustc_span::Span;
 
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::msrvs;
@@ -14,30 +15,21 @@ pub(super) fn check(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute],
 }
 
 fn check_packed(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute]) {
-    if let Some(items) = attrs.iter().find_map(|attr| {
-        if attr.ident().is_some_and(|ident| matches!(ident.name, sym::repr)) {
-            attr.meta_item_list()
-        } else {
-            None
+    if let Some(reprs) = find_attr!(attrs, AttributeKind::Repr(r) => r) {
+        let packed_span = reprs.iter().find(|(r, _)| matches!(r, ReprAttr::ReprPacked(..))).map(|(_, s)| *s);
+
+        if let Some(packed_span) = packed_span && !reprs.iter().any(|(x, _)| *x == ReprAttr::ReprC || *x == ReprAttr::ReprRust) {
+            span_lint_and_then(
+                cx,
+                REPR_PACKED_WITHOUT_ABI,
+                item_span,
+                "item uses `packed` representation without ABI-qualification",
+                |diag| {
+                    diag.warn("unqualified `#[repr(packed)]` defaults to `#[repr(Rust, packed)]`, which has no stable ABI")
+                        .help("qualify the desired ABI explicity via `#[repr(C, packed)]` or `#[repr(Rust, packed)]`")
+                        .span_label(packed_span, "`packed` representation set here");
+                },
+            );
         }
-    }) && let Some(packed) = items
-        .iter()
-        .find(|item| item.ident().is_some_and(|ident| matches!(ident.name, sym::packed)))
-        && !items.iter().any(|item| {
-            item.ident()
-                .is_some_and(|ident| matches!(ident.name, sym::C | sym::Rust))
-        })
-    {
-        span_lint_and_then(
-            cx,
-            REPR_PACKED_WITHOUT_ABI,
-            item_span,
-            "item uses `packed` representation without ABI-qualification",
-            |diag| {
-                diag.warn("unqualified `#[repr(packed)]` defaults to `#[repr(Rust, packed)]`, which has no stable ABI")
-                    .help("qualify the desired ABI explicity via `#[repr(C, packed)]` or `#[repr(Rust, packed)]`")
-                    .span_label(packed.span(), "`packed` representation set here");
-            },
-        );
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs b/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs
index 478ba7a187b..6ee3290fa76 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/unnecessary_clippy_cfg.rs
@@ -15,7 +15,7 @@ pub(super) fn check(
 ) {
     if cfg_attr.has_name(sym::clippy)
         && let Some(ident) = behind_cfg_attr.ident()
-        && Level::from_symbol(ident.name, Some(attr.id)).is_some()
+        && Level::from_symbol(ident.name, || Some(attr.id)).is_some()
         && let Some(items) = behind_cfg_attr.meta_item_list()
     {
         let nb_items = items.len();
diff --git a/src/tools/clippy/clippy_lints/src/attrs/utils.rs b/src/tools/clippy/clippy_lints/src/attrs/utils.rs
index a667649f734..0e650e49392 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/utils.rs
@@ -17,7 +17,7 @@ pub(super) fn is_word(nmi: &MetaItemInner, expected: Symbol) -> bool {
 }
 
 pub(super) fn is_lint_level(symbol: Symbol, attr_id: AttrId) -> bool {
-    Level::from_symbol(symbol, Some(attr_id)).is_some()
+    Level::from_symbol(symbol, || Some(attr_id)).is_some()
 }
 
 pub(super) fn is_relevant_item(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
index 9f020d3081c..6e6d81db11c 100644
--- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
@@ -1,10 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_attr_parsing::{find_attr, AttributeKind, ReprAttr};
 use rustc_hir::{HirId, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::{self, FieldDef};
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -97,16 +97,7 @@ fn is_zst<'tcx>(cx: &LateContext<'tcx>, field: &FieldDef, args: ty::GenericArgsR
 }
 
 fn has_c_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool {
-    cx.tcx.hir().attrs(hir_id).iter().any(|attr| {
-        if attr.has_name(sym::repr) {
-            if let Some(items) = attr.meta_item_list() {
-                for item in items {
-                    if item.is_word() && matches!(item.name_or_empty(), sym::C) {
-                        return true;
-                    }
-                }
-            }
-        }
-        false
-    })
+    let attrs = cx.tcx.hir().attrs(hir_id);
+
+    find_attr!(attrs, AttributeKind::Repr(r) if r.iter().any(|(x, _)| *x == ReprAttr::ReprC))
 }
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
index 4e8853821c3..6de16e306c9 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
@@ -1,3 +1,4 @@
+
 use clippy_config::Conf;
 use clippy_config::types::create_disallowed_map;
 use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
diff --git a/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs b/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs
index 4b40fc0b1ee..aa29705cf93 100644
--- a/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/include_in_doc_without_cfg.rs
@@ -1,18 +1,17 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_opt;
-use rustc_ast::AttrStyle;
 use rustc_errors::Applicability;
-use rustc_hir::{AttrArgs, AttrKind, Attribute};
-use rustc_lint::LateContext;
+use rustc_lint::EarlyContext;
+use rustc_ast::{Attribute, AttrKind, AttrArgs, AttrStyle};
 
 use super::DOC_INCLUDE_WITHOUT_CFG;
 
-pub fn check(cx: &LateContext<'_>, attrs: &[Attribute]) {
+pub fn check(cx: &EarlyContext<'_>, attrs: &[Attribute]) {
     for attr in attrs {
         if !attr.span.from_expansion()
             && let AttrKind::Normal(ref item) = attr.kind
             && attr.doc_str().is_some()
-            && let AttrArgs::Eq { expr: meta, .. } = &item.args
+            && let AttrArgs::Eq { expr: meta, .. } = &item.item.args
             && !attr.span.contains(meta.span)
             // Since the `include_str` is already expanded at this point, we can only take the
             // whole attribute snippet and then modify for our suggestion.
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index 713d62a8801..42192801af7 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -20,7 +20,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{AnonConst, Attribute, Expr, ImplItemKind, ItemKind, Node, Safety, TraitItemKind};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty;
 use rustc_resolve::rustdoc::{
@@ -577,6 +577,13 @@ impl_lint_pass!(Documentation => [
     DOC_INCLUDE_WITHOUT_CFG,
 ]);
 
+
+impl EarlyLintPass for Documentation {
+    fn check_attributes(&mut self, cx: &EarlyContext<'_>, attrs: &[rustc_ast::Attribute]) {
+        include_in_doc_without_cfg::check(cx, attrs);
+    }
+}
+
 impl<'tcx> LateLintPass<'tcx> for Documentation {
     fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute]) {
         let Some(headers) = check_attrs(cx, &self.valid_idents, attrs) else {
@@ -704,14 +711,13 @@ fn check_attrs(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, attrs: &[
         Some(("fake".into(), "fake".into()))
     }
 
-    include_in_doc_without_cfg::check(cx, attrs);
     if suspicious_doc_comments::check(cx, attrs) || is_doc_hidden(attrs) {
         return None;
     }
 
     let (fragments, _) = attrs_to_doc_fragments(
         attrs.iter().filter_map(|attr| {
-            if attr.span.in_external_macro(cx.sess().source_map()) {
+            if !attr.doc_str_and_comment_kind().is_some() || attr.span().in_external_macro(cx.sess().source_map()) {
                 None
             } else {
                 Some((attr, None))
diff --git a/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs b/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs
index 84393213e6f..bfc36deea7b 100644
--- a/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/suspicious_doc_comments.rs
@@ -3,6 +3,7 @@ use rustc_ast::AttrStyle;
 use rustc_ast::token::CommentKind;
 use rustc_errors::Applicability;
 use rustc_hir::Attribute;
+use rustc_attr_parsing::AttributeKind;
 use rustc_lint::LateContext;
 use rustc_span::Span;
 
@@ -36,15 +37,14 @@ fn collect_doc_replacements(attrs: &[Attribute]) -> Vec<(Span, String)> {
     attrs
         .iter()
         .filter_map(|attr| {
-            if let Some((sym, com_kind)) = attr.doc_str_and_comment_kind()
-                && let AttrStyle::Outer = attr.style
-                && let Some(com) = sym.as_str().strip_prefix('!')
+            if let Attribute::Parsed(AttributeKind::DocComment{ style: AttrStyle::Outer, kind, comment, ..}) = attr
+                && let Some(com) = comment.as_str().strip_prefix('!')
             {
-                let sugg = match com_kind {
+                let sugg = match kind {
                     CommentKind::Line => format!("//!{com}"),
                     CommentKind::Block => format!("/*!{com}*/"),
                 };
-                Some((attr.span, sugg))
+                Some((attr.span(), sugg))
             } else {
                 None
             }
diff --git a/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs b/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs
index 1f89cab9148..1eda73a9672 100644
--- a/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/too_long_first_doc_paragraph.rs
@@ -1,5 +1,6 @@
 use rustc_errors::Applicability;
 use rustc_hir::{Attribute, Item, ItemKind};
+use rustc_attr_parsing::AttributeKind;
 use rustc_lint::LateContext;
 
 use clippy_utils::diagnostics::span_lint_and_then;
@@ -43,9 +44,9 @@ pub(super) fn check(
     let mut should_suggest_empty_doc = false;
 
     for attr in attrs {
-        if let Some(doc) = attr.doc_str() {
-            spans.push(attr.span);
-            let doc = doc.as_str();
+        if let Attribute::Parsed(AttributeKind::DocComment {span, comment, ..}) = attr {
+            spans.push(span);
+            let doc = comment.as_str();
             let doc = doc.trim();
             if spans.len() == 1 {
                 // We make this suggestion only if the first doc line ends with a punctuation
@@ -78,7 +79,7 @@ pub(super) fn check(
                 && let new_span = first_span.with_hi(second_span.lo()).with_lo(first_span.hi())
                 && let Some(snippet) = snippet_opt(cx, new_span)
             {
-                let Some(first) = snippet_opt(cx, first_span) else {
+                let Some(first) = snippet_opt(cx, *first_span) else {
                     return;
                 };
                 let Some(comment_form) = first.get(..3) else {
diff --git a/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs b/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs
index 0599e08e6c0..0bdb99d7b9a 100644
--- a/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs
+++ b/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs
@@ -46,7 +46,8 @@ impl<'tcx> LateLintPass<'tcx> for FourForwardSlashes {
             .hir()
             .attrs(item.hir_id())
             .iter()
-            .fold(item.span.shrink_to_lo(), |span, attr| span.to(attr.span));
+            .filter(|i| i.is_doc_comment())
+            .fold(item.span.shrink_to_lo(), |span, attr| span.to(attr.span()));
         let (Some(file), _, _, end_line, _) = sm.span_to_location_info(span) else {
             return;
         };
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index e6e3ea59a9f..0ed4426d6e9 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -95,6 +95,7 @@ pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Tr
     }
 }
 
+// FIXME: needs to be an EARLY LINT. all attribute lints should be
 #[allow(clippy::too_many_arguments)]
 fn check_needless_must_use(
     cx: &LateContext<'_>,
@@ -117,38 +118,22 @@ fn check_needless_must_use(
                 fn_header_span,
                 "this unit-returning function has a `#[must_use]` attribute",
                 |diag| {
-                    diag.span_suggestion(attr.span, "remove the attribute", "", Applicability::MachineApplicable);
+                    diag.span_suggestion(attr.span(), "remove the attribute", "", Applicability::MachineApplicable);
                 },
             );
         } else {
             // When there are multiple attributes, it is not sufficient to simply make `must_use` empty, see
             // issue #12320.
-            span_lint_and_then(
+            // FIXME(jdonszelmann): this used to give a machine-applicable fix. However, it was super fragile,
+            // honestly looked incorrect, and is a little hard to support for a little bit now. Some day this could be
+            // re-added.
+            span_lint_and_help(
                 cx,
-                MUST_USE_UNIT,
+                DOUBLE_MUST_USE,
                 fn_header_span,
                 "this unit-returning function has a `#[must_use]` attribute",
-                |diag| {
-                    let mut attrs_without_must_use = attrs.to_vec();
-                    attrs_without_must_use.retain(|a| a.id != attr.id);
-                    let sugg_str = attrs_without_must_use
-                        .iter()
-                        .map(|a| {
-                            if a.value_str().is_none() {
-                                return a.name_or_empty().to_string();
-                            }
-                            format!("{} = \"{}\"", a.name_or_empty(), a.value_str().unwrap())
-                        })
-                        .collect::<Vec<_>>()
-                        .join(", ");
-
-                    diag.span_suggestion(
-                        attrs[0].span.with_hi(attrs[attrs.len() - 1].span.hi()),
-                        "change these attributes to",
-                        sugg_str,
-                        Applicability::MachineApplicable,
-                    );
-                },
+                Some(attr.span()),
+                "remove `must_use`",
             );
         }
     } else if attr.value_str().is_none() && is_must_use_ty(cx, return_ty(cx, item_id)) {
diff --git a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
index 39ff3c13bcc..5b58113169b 100644
--- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
+++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
@@ -183,7 +183,7 @@ fn suggestion<'tcx>(
 
 fn field_with_attrs_span(tcx: TyCtxt<'_>, field: &hir::ExprField<'_>) -> Span {
     if let Some(attr) = tcx.hir().attrs(field.hir_id).first() {
-        field.span.with_lo(attr.span.lo())
+        field.span.with_lo(attr.span().lo())
     } else {
         field.span
     }
diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
index 1b900f6be8e..9b4a3b3f9c8 100644
--- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
+++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
@@ -42,10 +42,10 @@ impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody {
             span_lint_and_then(
                 cx,
                 INLINE_FN_WITHOUT_BODY,
-                attr.span,
+                attr.span(),
                 format!("use of `#[inline]` on trait method `{}` which has no body", item.ident),
                 |diag| {
-                    diag.suggest_remove_item(cx, attr.span, "remove", Applicability::MachineApplicable);
+                    diag.suggest_remove_item(cx, attr.span(), "remove", Applicability::MachineApplicable);
                 },
             );
         }
diff --git a/src/tools/clippy/clippy_lints/src/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs
index f3d62b513e8..53dc070833b 100644
--- a/src/tools/clippy/clippy_lints/src/large_include_file.rs
+++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs
@@ -3,10 +3,11 @@ use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::root_macro_call_first_node;
 use clippy_utils::source::snippet_opt;
 use rustc_ast::LitKind;
-use rustc_hir::{AttrArgs, AttrKind, Attribute, Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_hir::{Expr, ExprKind};
+use rustc_ast::{Attribute, AttrArgs, AttrKind};
+use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
-use rustc_span::{Span, sym};
+use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -52,24 +53,6 @@ impl LargeIncludeFile {
 
 impl_lint_pass!(LargeIncludeFile => [LARGE_INCLUDE_FILE]);
 
-impl LargeIncludeFile {
-    fn emit_lint(&self, cx: &LateContext<'_>, span: Span) {
-        #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
-        span_lint_and_then(
-            cx,
-            LARGE_INCLUDE_FILE,
-            span,
-            "attempted to include a large file",
-            |diag| {
-                diag.note(format!(
-                    "the configuration allows a maximum size of {} bytes",
-                    self.max_file_size
-                ));
-            },
-        );
-    }
-}
-
 impl LateLintPass<'_> for LargeIncludeFile {
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
         if let ExprKind::Lit(lit) = &expr.kind
@@ -85,18 +68,32 @@ impl LateLintPass<'_> for LargeIncludeFile {
             && (cx.tcx.is_diagnostic_item(sym::include_bytes_macro, macro_call.def_id)
                 || cx.tcx.is_diagnostic_item(sym::include_str_macro, macro_call.def_id))
         {
-            self.emit_lint(cx, expr.span.source_callsite());
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
+                cx,
+                LARGE_INCLUDE_FILE,
+                expr.span.source_callsite(),
+                "attempted to include a large file",
+                |diag| {
+                    diag.note(format!(
+                        "the configuration allows a maximum size of {} bytes",
+                        self.max_file_size
+                    ));
+                },
+            );
         }
     }
+}
 
-    fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &Attribute) {
+impl EarlyLintPass for LargeIncludeFile {
+    fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
         if !attr.span.from_expansion()
             // Currently, rustc limits the usage of macro at the top-level of attributes,
             // so we don't need to recurse into each level.
             && let AttrKind::Normal(ref item) = attr.kind
             && let Some(doc) = attr.doc_str()
             && doc.as_str().len() as u64 > self.max_file_size
-            && let AttrArgs::Eq { expr: meta, .. } = &item.args
+            && let AttrArgs::Eq { expr: meta, .. } = &item.item.args
             && !attr.span.contains(meta.span)
             // Since the `include_str` is already expanded at this point, we can only take the
             // whole attribute snippet and then modify for our suggestion.
@@ -113,7 +110,19 @@ impl LateLintPass<'_> for LargeIncludeFile {
             && let sub_snippet = sub_snippet.trim()
             && (sub_snippet.starts_with("include_str!") || sub_snippet.starts_with("include_bytes!"))
         {
-            self.emit_lint(cx, attr.span);
+            #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+            span_lint_and_then(
+                cx,
+                LARGE_INCLUDE_FILE,
+                attr.span,
+                "attempted to include a large file",
+                |diag| {
+                    diag.note(format!(
+                        "the configuration allows a maximum size of {} bytes",
+                        self.max_file_size
+                    ));
+                },
+            );
         }
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 13218331a67..177f83921cd 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -407,9 +407,9 @@ mod zombie_processes;
 
 use clippy_config::{Conf, get_configuration_metadata, sanitize_explanation};
 use clippy_utils::macros::FormatArgsStorage;
+use utils::attr_collector::{AttrCollector, AttrStorage};
 use rustc_data_structures::fx::FxHashSet;
 use rustc_lint::{Lint, LintId};
-use utils::attr_collector::{AttrCollector, AttrStorage};
 
 /// Register all pre expansion lints
 ///
@@ -717,6 +717,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_late_pass(move |_| Box::new(disallowed_names::DisallowedNames::new(conf)));
     store.register_late_pass(move |tcx| Box::new(functions::Functions::new(tcx, conf)));
     store.register_late_pass(move |_| Box::new(doc::Documentation::new(conf)));
+    store.register_early_pass(move || Box::new(doc::Documentation::new(conf)));
     store.register_late_pass(|_| Box::new(neg_multiply::NegMultiply));
     store.register_late_pass(|_| Box::new(let_if_seq::LetIfSeq));
     store.register_late_pass(|_| Box::new(mixed_read_write_in_expression::EvalOrderDependence));
@@ -860,6 +861,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
     store.register_early_pass(|| Box::new(pub_use::PubUse));
     store.register_late_pass(|_| Box::new(format_push_string::FormatPushString));
     store.register_late_pass(move |_| Box::new(large_include_file::LargeIncludeFile::new(conf)));
+    store.register_early_pass(move || Box::new(large_include_file::LargeIncludeFile::new(conf)));
     store.register_late_pass(|_| Box::new(strings::TrimSplitWhitespace));
     store.register_late_pass(|_| Box::new(rc_clone_in_vec_init::RcCloneInVecInit));
     store.register_early_pass(|| Box::<duplicate_mod::DuplicateMod>::default());
diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs
index 37412866539..165e8c2ea05 100644
--- a/src/tools/clippy/clippy_lints/src/macro_use.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_use.rs
@@ -94,7 +94,7 @@ impl LateLintPass<'_> for MacroUseImports {
         {
             for kid in cx.tcx.module_children(id) {
                 if let Res::Def(DefKind::Macro(_mac_type), mac_id) = kid.res {
-                    let span = mac_attr.span;
+                    let span = mac_attr.span();
                     let def_path = cx.tcx.def_path_str(mac_id);
                     self.imports.push((def_path, span, hir_id));
                 }
@@ -104,8 +104,8 @@ impl LateLintPass<'_> for MacroUseImports {
         }
     }
     fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &hir::Attribute) {
-        if attr.span.from_expansion() {
-            self.push_unique_macro(cx, attr.span);
+        if attr.span().from_expansion() {
+            self.push_unique_macro(cx, attr.span());
         }
     }
     fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
index 00800231fe4..83d8a509390 100644
--- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
@@ -116,7 +116,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustive {
                             if let Some(non_exhaustive) =
                                 attr::find_by_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive)
                             {
-                                diag.span_note(non_exhaustive.span, "the struct is already non-exhaustive");
+                                diag.span_note(non_exhaustive.span(), "the struct is already non-exhaustive");
                             } else {
                                 let indent = snippet_indent(cx, item.span).unwrap_or_default();
                                 diag.span_suggestion_verbose(
diff --git a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs
index b73b9083a99..6eca3f12cf2 100644
--- a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs
+++ b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs
@@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi {
                         .span
                         .with_lo(fn_sig.span.lo() + BytePos::from_usize(fn_attrs.len()))
                         .shrink_to_lo();
-                    let attr_snippet = snippet(cx, attr.span, "..");
+                    let attr_snippet = snippet(cx, attr.span(), "..");
 
                     span_lint_and_then(
                         cx,
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 93abf95e357..16916e3aaad 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -432,7 +432,7 @@ fn include_attrs_in_span(cx: &LateContext<'_>, hir_id: HirId, span: Span) -> Spa
         .hir()
         .attrs(hir_id)
         .iter()
-        .fold(span, |acc, attr| acc.to(attr.span)))
+        .fold(span, |acc, attr| acc.to(attr.span())))
 }
 
 enum HasSafetyComment {
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 40ddd75b7fa..7fc25e3617d 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -93,6 +93,7 @@ use std::sync::{Mutex, MutexGuard, OnceLock};
 
 use itertools::Itertools;
 use rustc_ast::ast::{self, LitKind, RangeLimits};
+use rustc_attr_parsing::{find_attr, AttributeKind};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::packed::Pu128;
 use rustc_data_structures::unhash::UnhashMap;
@@ -1949,7 +1950,7 @@ pub fn has_attr(attrs: &[hir::Attribute], symbol: Symbol) -> bool {
 }
 
 pub fn has_repr_attr(cx: &LateContext<'_>, hir_id: HirId) -> bool {
-    has_attr(cx.tcx.hir().attrs(hir_id), sym::repr)
+    find_attr!(cx.tcx.hir().attrs(hir_id), AttributeKind::Repr(..))
 }
 
 pub fn any_parent_has_attr(tcx: TyCtxt<'_>, node: HirId, symbol: Symbol) -> bool {
diff --git a/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr b/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr
index 82b926cc53b..c9f0e661dbd 100644
--- a/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr
+++ b/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.stderr
@@ -1,26 +1,26 @@
 error: attempted to include a large file
-  --> tests/ui-toml/large_include_file/large_include_file.rs:14:43
+  --> tests/ui-toml/large_include_file/large_include_file.rs:19:1
    |
-LL | const TOO_BIG_INCLUDE_BYTES: &[u8; 654] = include_bytes!("too_big.txt");
-   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[doc = include_str!("too_big.txt")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the configuration allows a maximum size of 600 bytes
    = note: `-D clippy::large-include-file` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::large_include_file)]`
 
 error: attempted to include a large file
-  --> tests/ui-toml/large_include_file/large_include_file.rs:16:35
+  --> tests/ui-toml/large_include_file/large_include_file.rs:14:43
    |
-LL | const TOO_BIG_INCLUDE_STR: &str = include_str!("too_big.txt");
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | const TOO_BIG_INCLUDE_BYTES: &[u8; 654] = include_bytes!("too_big.txt");
+   |                                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the configuration allows a maximum size of 600 bytes
 
 error: attempted to include a large file
-  --> tests/ui-toml/large_include_file/large_include_file.rs:19:1
+  --> tests/ui-toml/large_include_file/large_include_file.rs:16:35
    |
-LL | #[doc = include_str!("too_big.txt")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | const TOO_BIG_INCLUDE_STR: &str = include_str!("too_big.txt");
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: the configuration allows a maximum size of 600 bytes
 
diff --git a/src/tools/clippy/tests/ui/must_use_unit.fixed b/src/tools/clippy/tests/ui/must_use_unit.fixed
index b92d9379c90..7e2a7296049 100644
--- a/src/tools/clippy/tests/ui/must_use_unit.fixed
+++ b/src/tools/clippy/tests/ui/must_use_unit.fixed
@@ -24,8 +24,3 @@ fn main() {
     );
 }
 
-#[cfg_attr(all(), deprecated)]
-fn issue_12320() {}
-
-#[cfg_attr(all(), deprecated, doc = "foo")]
-fn issue_12320_2() {}
diff --git a/src/tools/clippy/tests/ui/must_use_unit.rs b/src/tools/clippy/tests/ui/must_use_unit.rs
index c77e7282750..f41b1a7c800 100644
--- a/src/tools/clippy/tests/ui/must_use_unit.rs
+++ b/src/tools/clippy/tests/ui/must_use_unit.rs
@@ -27,8 +27,3 @@ fn main() {
     );
 }
 
-#[cfg_attr(all(), must_use, deprecated)]
-fn issue_12320() {}
-
-#[cfg_attr(all(), deprecated, doc = "foo", must_use)]
-fn issue_12320_2() {}
diff --git a/src/tools/clippy/tests/ui/must_use_unit.stderr b/src/tools/clippy/tests/ui/must_use_unit.stderr
index b435568deea..c2ee2edda7d 100644
--- a/src/tools/clippy/tests/ui/must_use_unit.stderr
+++ b/src/tools/clippy/tests/ui/must_use_unit.stderr
@@ -25,21 +25,5 @@ LL | #[must_use = "With note"]
 LL | pub fn must_use_with_note() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: this unit-returning function has a `#[must_use]` attribute
-  --> tests/ui/must_use_unit.rs:31:1
-   |
-LL | #[cfg_attr(all(), must_use, deprecated)]
-   |                   -------------------- help: change these attributes to: `deprecated`
-LL | fn issue_12320() {}
-   | ^^^^^^^^^^^^^^^^
-
-error: this unit-returning function has a `#[must_use]` attribute
-  --> tests/ui/must_use_unit.rs:34:1
-   |
-LL | #[cfg_attr(all(), deprecated, doc = "foo", must_use)]
-   |                   --------------------------------- help: change these attributes to: `deprecated, doc = "foo"`
-LL | fn issue_12320_2() {}
-   | ^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/must_use_unit_12320.rs b/src/tools/clippy/tests/ui/must_use_unit_12320.rs
new file mode 100644
index 00000000000..39dcafdb38b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/must_use_unit_12320.rs
@@ -0,0 +1,11 @@
+//@aux-build:proc_macros.rs
+//@no-rustfix
+
+#![warn(clippy::must_use_unit)]
+#![allow(clippy::unused_unit)]
+
+#[cfg_attr(all(), must_use, deprecated)]
+fn issue_12320() {}
+
+#[cfg_attr(all(), deprecated, doc = "foo", must_use)]
+fn issue_12320_2() {}
diff --git a/src/tools/clippy/tests/ui/must_use_unit_12320.stderr b/src/tools/clippy/tests/ui/must_use_unit_12320.stderr
new file mode 100644
index 00000000000..b3e1cbc0457
--- /dev/null
+++ b/src/tools/clippy/tests/ui/must_use_unit_12320.stderr
@@ -0,0 +1,28 @@
+error: this unit-returning function has a `#[must_use]` attribute
+  --> tests/ui/must_use_unit_12320.rs:8:1
+   |
+LL | fn issue_12320() {}
+   | ^^^^^^^^^^^^^^^^
+   |
+help: remove `must_use`
+  --> tests/ui/must_use_unit_12320.rs:7:19
+   |
+LL | #[cfg_attr(all(), must_use, deprecated)]
+   |                   ^^^^^^^^
+   = note: `-D clippy::double-must-use` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::double_must_use)]`
+
+error: this unit-returning function has a `#[must_use]` attribute
+  --> tests/ui/must_use_unit_12320.rs:11:1
+   |
+LL | fn issue_12320_2() {}
+   | ^^^^^^^^^^^^^^^^^^
+   |
+help: remove `must_use`
+  --> tests/ui/must_use_unit_12320.rs:10:44
+   |
+LL | #[cfg_attr(all(), deprecated, doc = "foo", must_use)]
+   |                                            ^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs
index 45e316b190a..3e8b3ef46e4 100644
--- a/src/tools/miri/src/intrinsics/simd.rs
+++ b/src/tools/miri/src/intrinsics/simd.rs
@@ -633,7 +633,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     this.write_immediate(*val, &dest)?;
                 }
             }
-            "shuffle_generic" => {
+            "shuffle_const_generic" => {
                 let [left, right] = check_arg_count(args)?;
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -657,7 +657,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         this.read_immediate(&this.project_index(&right, right_idx)?)?
                     } else {
                         throw_ub_format!(
-                            "`simd_shuffle_generic` index {src_index} is out-of-bounds for 2 vectors with length {dest_len}"
+                            "`simd_shuffle_const_generic` index {src_index} is out-of-bounds for 2 vectors with length {dest_len}"
                         );
                     };
                     this.write_immediate(*val, &dest)?;
diff --git a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
index b6c5522b3d2..f043bb7ce9f 100644
--- a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
+++ b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
@@ -16,7 +16,7 @@ use std::simd::prelude::*;
 
 #[rustc_intrinsic]
 #[rustc_nounwind]
-pub unsafe fn simd_shuffle_generic<T, U, const IDX: &'static [u32]>(_x: T, _y: T) -> U;
+pub unsafe fn simd_shuffle_const_generic<T, U, const IDX: &'static [u32]>(_x: T, _y: T) -> U;
 
 fn simd_ops_f32() {
     let a = f32x4::splat(10.0);
@@ -619,13 +619,13 @@ fn simd_intrinsics() {
             simd_select(i8x4::from_array([0, -1, -1, 0]), b, a),
             i32x4::from_array([10, 2, 10, 10])
         );
-        assert_eq!(simd_shuffle_generic::<_, i32x4, { &[3, 1, 0, 2] }>(a, b), a,);
+        assert_eq!(simd_shuffle_const_generic::<_, i32x4, { &[3, 1, 0, 2] }>(a, b), a,);
         assert_eq!(
             simd_shuffle::<_, _, i32x4>(a, b, const { u32x4::from_array([3u32, 1, 0, 2]) }),
             a,
         );
         assert_eq!(
-            simd_shuffle_generic::<_, i32x4, { &[7, 5, 4, 6] }>(a, b),
+            simd_shuffle_const_generic::<_, i32x4, { &[7, 5, 4, 6] }>(a, b),
             i32x4::from_array([4, 2, 1, 10]),
         );
         assert_eq!(
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index 1cb47353469..253e13375c7 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -3827,7 +3827,6 @@ ui/suggestions/issue-103646.rs
 ui/suggestions/issue-104086-suggest-let.rs
 ui/suggestions/issue-104287.rs
 ui/suggestions/issue-104327.rs
-ui/suggestions/issue-104328.rs
 ui/suggestions/issue-104961.rs
 ui/suggestions/issue-105226.rs
 ui/suggestions/issue-105494.rs
diff --git a/tests/assembly/dwarf-mixed-versions-lto.rs b/tests/assembly/dwarf-mixed-versions-lto.rs
index 5b8e5ff4f4a..f1fc0814c9d 100644
--- a/tests/assembly/dwarf-mixed-versions-lto.rs
+++ b/tests/assembly/dwarf-mixed-versions-lto.rs
@@ -1,5 +1,6 @@
 // This test ensures that if LTO occurs between crates with different DWARF versions, we
 // will choose the highest DWARF version for the final binary. This matches Clang's behavior.
+// Note: `.2byte` directive is used on MIPS.
 
 //@ only-linux
 //@ aux-build:dwarf-mixed-versions-lto-aux.rs
@@ -14,6 +15,6 @@ fn main() {
 }
 
 // CHECK: .section .debug_info
-// CHECK-NOT: {{\.(short|hword)}} 2
-// CHECK-NOT: {{\.(short|hword)}} 4
-// CHECK: {{\.(short|hword)}} 5
+// CHECK-NOT: {{\.(short|hword|2byte)}} 2
+// CHECK-NOT: {{\.(short|hword|2byte)}} 4
+// CHECK: {{\.(short|hword|2byte)}} 5
diff --git a/tests/assembly/rust-abi-arg-attr.rs b/tests/assembly/rust-abi-arg-attr.rs
index e55a53fbdeb..5b5eeb29f0f 100644
--- a/tests/assembly/rust-abi-arg-attr.rs
+++ b/tests/assembly/rust-abi-arg-attr.rs
@@ -51,10 +51,7 @@ enum Ordering {
 }
 
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-fn three_way_compare<T: Copy>(lhs: T, rhs: T) -> Ordering {
-    loop {}
-}
+fn three_way_compare<T: Copy>(lhs: T, rhs: T) -> Ordering;
 
 // ^^^^^ core
 
diff --git a/tests/pretty/hir-pretty-attr.pp b/tests/pretty/hir-pretty-attr.pp
new file mode 100644
index 00000000000..586810b0046
--- /dev/null
+++ b/tests/pretty/hir-pretty-attr.pp
@@ -0,0 +1,11 @@
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+//@ pretty-compare-only
+//@ pretty-mode:hir
+//@ pp-exact:hir-pretty-attr.pp
+
+#[attr="Repr([ReprC, ReprPacked(Align(4 bytes)), ReprTransparent])")]
+struct Example {
+}
diff --git a/tests/pretty/hir-pretty-attr.rs b/tests/pretty/hir-pretty-attr.rs
new file mode 100644
index 00000000000..eb5a677024a
--- /dev/null
+++ b/tests/pretty/hir-pretty-attr.rs
@@ -0,0 +1,7 @@
+//@ pretty-compare-only
+//@ pretty-mode:hir
+//@ pp-exact:hir-pretty-attr.pp
+
+#[repr(C, packed(4))]
+#[repr(transparent)]
+struct Example {}
diff --git a/tests/rustdoc-json/enums/discriminant/struct.rs b/tests/rustdoc-json/enums/discriminant/struct.rs
index 0ac40cda733..24d5f5b08c2 100644
--- a/tests/rustdoc-json/enums/discriminant/struct.rs
+++ b/tests/rustdoc-json/enums/discriminant/struct.rs
@@ -1,7 +1,7 @@
 // ignore-tidy-linelength
 
 #[repr(i32)]
-//@ is "$.index[*][?(@.name=='Foo')].attrs" '["#[repr(i32)]"]'
+//@ is "$.index[*][?(@.name=='Foo')].attrs" '["#[attr=\"Repr([ReprInt(SignedInt(I32))])\")]\n"]'
 pub enum Foo {
     //@ is    "$.index[*][?(@.name=='Struct')].inner.variant.discriminant" null
     //@ count "$.index[*][?(@.name=='Struct')].inner.variant.kind.struct.fields[*]" 0
diff --git a/tests/rustdoc-json/enums/discriminant/tuple.rs b/tests/rustdoc-json/enums/discriminant/tuple.rs
index fbff5aacd67..a50ae8b9189 100644
--- a/tests/rustdoc-json/enums/discriminant/tuple.rs
+++ b/tests/rustdoc-json/enums/discriminant/tuple.rs
@@ -1,7 +1,7 @@
 // ignore-tidy-linelength
 
 #[repr(u32)]
-//@ is "$.index[*][?(@.name=='Foo')].attrs" '["#[repr(u32)]"]'
+//@ is "$.index[*][?(@.name=='Foo')].attrs" '["#[attr=\"Repr([ReprInt(UnsignedInt(U32))])\")]\n"]'
 pub enum Foo {
     //@ is    "$.index[*][?(@.name=='Tuple')].inner.variant.discriminant" null
     //@ count "$.index[*][?(@.name=='Tuple')].inner.variant.kind.tuple[*]" 0
diff --git a/tests/rustdoc/const-intrinsic.rs b/tests/rustdoc/const-intrinsic.rs
index 8444d4a3aa7..7dedb083b7d 100644
--- a/tests/rustdoc/const-intrinsic.rs
+++ b/tests/rustdoc/const-intrinsic.rs
@@ -9,19 +9,13 @@
 #[stable(since="1.0.0", feature="rust1")]
 #[rustc_const_stable(feature = "const_transmute", since = "1.56.0")]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub const unsafe fn transmute<T, U>(_: T) -> U {
-    loop {}
-}
+pub const unsafe fn transmute<T, U>(_: T) -> U;
 
 //@ has 'foo/fn.unreachable.html'
 //@ has - '//pre[@class="rust item-decl"]' 'pub unsafe fn unreachable() -> !'
 #[stable(since="1.0.0", feature="rust1")]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub unsafe fn unreachable() -> ! {
-    loop {}
-}
+pub unsafe fn unreachable() -> !;
 
 extern "C" {
     //@ has 'foo/fn.needs_drop.html'
diff --git a/tests/rustdoc/safe-intrinsic.rs b/tests/rustdoc/safe-intrinsic.rs
index 1edc1d9f79b..0d2ee89415d 100644
--- a/tests/rustdoc/safe-intrinsic.rs
+++ b/tests/rustdoc/safe-intrinsic.rs
@@ -11,14 +11,8 @@ trait Sized {}
 //@ has 'foo/fn.abort.html'
 //@ has - '//pre[@class="rust item-decl"]' 'pub fn abort() -> !'
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub fn abort() -> ! {
-    loop {}
-}
+pub fn abort() -> !;
 //@ has 'foo/fn.unreachable.html'
 //@ has - '//pre[@class="rust item-decl"]' 'pub unsafe fn unreachable() -> !'
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-pub unsafe fn unreachable() -> ! {
-    loop {}
-}
+pub unsafe fn unreachable() -> !;
diff --git a/tests/ui-fulldeps/stable-mir/check_attribute.rs b/tests/ui-fulldeps/stable-mir/check_attribute.rs
index 11cb63f3f8a..de5ba15f6ea 100644
--- a/tests/ui-fulldeps/stable-mir/check_attribute.rs
+++ b/tests/ui-fulldeps/stable-mir/check_attribute.rs
@@ -27,63 +27,23 @@ fn test_stable_mir() -> ControlFlow<()> {
     // Find items in the local crate.
     let items = stable_mir::all_local_items();
 
-    test_builtins(&items);
-    test_derive(&items);
     test_tool(&items);
-    test_all_attrs(&items);
 
     ControlFlow::Continue(())
 }
 
-// Test built-in attributes.
-fn test_builtins(items: &CrateItems) {
-    let target_fn = *get_item(&items, "builtins_fn").unwrap();
-    let allow_attrs = target_fn.attrs_by_path(&["allow".to_string()]);
-    assert_eq!(allow_attrs[0].as_str(), "#![allow(unused_variables)]");
-
-    let inline_attrs = target_fn.attrs_by_path(&["inline".to_string()]);
-    assert_eq!(inline_attrs[0].as_str(), "#[inline]");
-
-    let deprecated_attrs = target_fn.attrs_by_path(&["deprecated".to_string()]);
-    assert_eq!(deprecated_attrs[0].as_str(), "#[deprecated(since = \"5.2.0\")]");
-}
-
-// Test derive attribute.
-fn test_derive(items: &CrateItems) {
-    let target_struct = *get_item(&items, "Foo").unwrap();
-    let attrs = target_struct.attrs_by_path(&["derive".to_string()]);
-    // No `derive` attribute since it's expanded before MIR.
-    assert_eq!(attrs.len(), 0);
-
-    // Check derived trait method's attributes.
-    let derived_fmt = *get_item(&items, "<Foo as std::fmt::Debug>::fmt").unwrap();
-    // The Rust reference lies about this attribute. It doesn't show up in `clone` or `fmt` impl.
-    let _fmt_attrs = derived_fmt.attrs_by_path(&["automatically_derived".to_string()]);
-}
-
 // Test tool attributes.
 fn test_tool(items: &CrateItems) {
     let rustfmt_fn = *get_item(&items, "do_not_format").unwrap();
-    let rustfmt_attrs = rustfmt_fn.attrs_by_path(&["rustfmt".to_string(), "skip".to_string()]);
+    let rustfmt_attrs = rustfmt_fn.tool_attrs(&["rustfmt".to_string(), "skip".to_string()]);
     assert_eq!(rustfmt_attrs[0].as_str(), "#[rustfmt::skip]");
 
     let clippy_fn = *get_item(&items, "complex_fn").unwrap();
-    let clippy_attrs = clippy_fn.attrs_by_path(&["clippy".to_string(),
+    let clippy_attrs = clippy_fn.tool_attrs(&["clippy".to_string(),
                                                "cyclomatic_complexity".to_string()]);
     assert_eq!(clippy_attrs[0].as_str(), "#[clippy::cyclomatic_complexity = \"100\"]");
 }
 
-fn test_all_attrs(items: &CrateItems) {
-    let target_fn = *get_item(&items, "many_attrs").unwrap();
-    let all_attrs = target_fn.all_attrs();
-    assert_eq!(all_attrs[0].as_str(), "#[inline]");
-    assert_eq!(all_attrs[1].as_str(), "#[allow(unused_variables)]");
-    assert_eq!(all_attrs[2].as_str(), "#[allow(dead_code)]");
-    assert_eq!(all_attrs[3].as_str(), "#[allow(unused_imports)]");
-    assert_eq!(all_attrs[4].as_str(), "#![allow(clippy::filter_map)]");
-}
-
-
 fn get_item<'a>(
     items: &'a CrateItems,
     name: &str,
diff --git a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs
index 2f772b97886..07a2a62e066 100644
--- a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs
+++ b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs
@@ -51,13 +51,11 @@ fn test_intrinsics() -> ControlFlow<()> {
 
 /// This check is unfortunately tight to the implementation of intrinsics.
 ///
-/// We want to ensure that StableMIR can handle intrinsics with and without fallback body.
+/// We want to ensure that StableMIR can handle intrinsics with and without fallback body:
+/// for intrinsics without a body, obviously we cannot expose anything.
 ///
 /// If by any chance this test breaks because you changed how an intrinsic is implemented, please
 /// update the test to invoke a different intrinsic.
-///
-/// In StableMIR, we only expose intrinsic body if they are not marked with
-/// `rustc_intrinsic_must_be_overridden`.
 fn check_instance(instance: &Instance) {
     assert_eq!(instance.kind, InstanceKind::Intrinsic);
     let name = instance.intrinsic_name().unwrap();
diff --git a/tests/ui/asm/conditionally-sized-ptr-fail.rs b/tests/ui/asm/conditionally-sized-ptr-fail.rs
new file mode 100644
index 00000000000..b0a93495ffa
--- /dev/null
+++ b/tests/ui/asm/conditionally-sized-ptr-fail.rs
@@ -0,0 +1,19 @@
+//@ needs-asm-support
+
+use std::arch::asm;
+
+fn _f<T: ?Sized>(p: *mut T) {
+    unsafe {
+        asm!("/* {} */", in(reg) p);
+        //~^ ERROR cannot use value of unsized pointer type `*mut T` for inline assembly
+    }
+}
+
+fn _g(p: *mut [u8]) {
+    unsafe {
+        asm!("/* {} */", in(reg) p);
+        //~^ ERROR cannot use value of unsized pointer type `*mut [u8]` for inline assembly
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/asm/conditionally-sized-ptr-fail.stderr b/tests/ui/asm/conditionally-sized-ptr-fail.stderr
new file mode 100644
index 00000000000..b88f59f569c
--- /dev/null
+++ b/tests/ui/asm/conditionally-sized-ptr-fail.stderr
@@ -0,0 +1,18 @@
+error: cannot use value of unsized pointer type `*mut T` for inline assembly
+  --> $DIR/conditionally-sized-ptr-fail.rs:7:34
+   |
+LL |         asm!("/* {} */", in(reg) p);
+   |                                  ^
+   |
+   = note: only sized pointers can be used in inline assembly
+
+error: cannot use value of unsized pointer type `*mut [u8]` for inline assembly
+  --> $DIR/conditionally-sized-ptr-fail.rs:14:34
+   |
+LL |         asm!("/* {} */", in(reg) p);
+   |                                  ^
+   |
+   = note: only sized pointers can be used in inline assembly
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/asm/conditionally-sized-ptr.rs b/tests/ui/asm/conditionally-sized-ptr.rs
new file mode 100644
index 00000000000..8ff18fd1da1
--- /dev/null
+++ b/tests/ui/asm/conditionally-sized-ptr.rs
@@ -0,0 +1,12 @@
+//@ check-pass
+//@ needs-asm-support
+
+use std::arch::asm;
+
+fn _f<T>(p: *mut T) {
+    unsafe {
+        asm!("/* {} */", in(reg) p);
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/attributes/arg-error-issue-121425.stderr b/tests/ui/attributes/arg-error-issue-121425.stderr
index 1beb99b1703..6e71f15fdc8 100644
--- a/tests/ui/attributes/arg-error-issue-121425.stderr
+++ b/tests/ui/attributes/arg-error-issue-121425.stderr
@@ -1,3 +1,9 @@
+error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
+  --> $DIR/arg-error-issue-121425.rs:16:8
+   |
+LL | #[repr(align())]
+   |        ^^^^^^^
+
 error[E0693]: incorrect `repr(align)` attribute format: `align` expects a literal integer as argument
   --> $DIR/arg-error-issue-121425.rs:4:14
    |
@@ -16,12 +22,6 @@ error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer
 LL | #[repr(align("str"))]
    |              ^^^^^
 
-error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
-  --> $DIR/arg-error-issue-121425.rs:16:8
-   |
-LL | #[repr(align())]
-   |        ^^^^^^^
-
 error[E0552]: incorrect `repr(packed)` attribute format: `packed` expects a literal integer as argument
   --> $DIR/arg-error-issue-121425.rs:21:15
    |
diff --git a/tests/ui/attributes/issue-100631.stderr b/tests/ui/attributes/issue-100631.stderr
index 6e8e4f3b418..b2bd0a96325 100644
--- a/tests/ui/attributes/issue-100631.stderr
+++ b/tests/ui/attributes/issue-100631.stderr
@@ -1,8 +1,8 @@
 error[E0084]: unsupported representation for zero-variant enum
-  --> $DIR/issue-100631.rs:4:1
+  --> $DIR/issue-100631.rs:4:8
    |
 LL | #[repr(C)]
-   | ^^^^^^^^^^
+   |        ^
 LL | #[repr(C)]
 LL | enum Foo {}
    | -------- zero-variant enum
diff --git a/tests/ui/attributes/malformed-fn-align.rs b/tests/ui/attributes/malformed-fn-align.rs
new file mode 100644
index 00000000000..4aaad01b723
--- /dev/null
+++ b/tests/ui/attributes/malformed-fn-align.rs
@@ -0,0 +1,7 @@
+#![feature(fn_align)]
+#![crate_type = "lib"]
+
+trait MyTrait {
+    #[repr(align)] //~ ERROR invalid `repr(align)` attribute: `align` needs an argument
+    fn myfun();
+}
diff --git a/tests/ui/attributes/malformed-fn-align.stderr b/tests/ui/attributes/malformed-fn-align.stderr
new file mode 100644
index 00000000000..57913c48ef7
--- /dev/null
+++ b/tests/ui/attributes/malformed-fn-align.stderr
@@ -0,0 +1,9 @@
+error[E0589]: invalid `repr(align)` attribute: `align` needs an argument
+  --> $DIR/malformed-fn-align.rs:5:12
+   |
+LL |     #[repr(align)]
+   |            ^^^^^ help: supply an argument here: `align(...)`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0589`.
diff --git a/tests/ui/attributes/mixed_export_name_and_no_mangle.fixed b/tests/ui/attributes/mixed_export_name_and_no_mangle.fixed
index 7224d4289e3..d8b5235c52f 100644
--- a/tests/ui/attributes/mixed_export_name_and_no_mangle.fixed
+++ b/tests/ui/attributes/mixed_export_name_and_no_mangle.fixed
@@ -3,7 +3,7 @@
 //@ check-pass
 
 #![warn(unused_attributes)]
-//~^ WARN `#[no_mangle]` attribute may not be used in combination with `#[export_name]` [unused_attributes]
+//~^ WARN `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[export_name]` [unused_attributes]
 #[export_name = "foo"]
 pub fn bar() {}
 
diff --git a/tests/ui/attributes/mixed_export_name_and_no_mangle.rs b/tests/ui/attributes/mixed_export_name_and_no_mangle.rs
index 149a7904e1e..83a673a7d13 100644
--- a/tests/ui/attributes/mixed_export_name_and_no_mangle.rs
+++ b/tests/ui/attributes/mixed_export_name_and_no_mangle.rs
@@ -4,7 +4,7 @@
 
 #![warn(unused_attributes)]
 #[no_mangle]
-//~^ WARN `#[no_mangle]` attribute may not be used in combination with `#[export_name]` [unused_attributes]
+//~^ WARN `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[export_name]` [unused_attributes]
 #[export_name = "foo"]
 pub fn bar() {}
 
diff --git a/tests/ui/attributes/mixed_export_name_and_no_mangle.stderr b/tests/ui/attributes/mixed_export_name_and_no_mangle.stderr
index ba63127ba2d..c760d27db25 100644
--- a/tests/ui/attributes/mixed_export_name_and_no_mangle.stderr
+++ b/tests/ui/attributes/mixed_export_name_and_no_mangle.stderr
@@ -1,8 +1,8 @@
-warning: `#[no_mangle]` attribute may not be used in combination with `#[export_name]`
+warning: `#[unsafe(no_mangle)]` attribute may not be used in combination with `#[export_name]`
   --> $DIR/mixed_export_name_and_no_mangle.rs:6:1
    |
 LL | #[no_mangle]
-   | ^^^^^^^^^^^^ `#[no_mangle]` is ignored
+   | ^^^^^^^^^^^^ `#[unsafe(no_mangle)]` is ignored
    |
 note: `#[export_name]` takes precedence
   --> $DIR/mixed_export_name_and_no_mangle.rs:8:1
@@ -14,7 +14,7 @@ note: the lint level is defined here
    |
 LL | #![warn(unused_attributes)]
    |         ^^^^^^^^^^^^^^^^^
-help: remove the `#[no_mangle]` attribute
+help: remove the `#[unsafe(no_mangle)]` attribute
    |
 LL - #[no_mangle]
    |
diff --git a/tests/ui/attributes/nonterminal-expansion.rs b/tests/ui/attributes/nonterminal-expansion.rs
index 1b2e92a3170..5ea30bb8627 100644
--- a/tests/ui/attributes/nonterminal-expansion.rs
+++ b/tests/ui/attributes/nonterminal-expansion.rs
@@ -6,6 +6,7 @@ macro_rules! pass_nonterminal {
     ($n:expr) => {
         #[repr(align($n))]
         //~^ ERROR expected unsuffixed literal, found `n!()`
+        //~^^ ERROR incorrect `repr(align)` attribute format: `align` expects a literal integer as argument [E0693]
         struct S;
     };
 }
@@ -15,6 +16,5 @@ macro_rules! n {
 }
 
 pass_nonterminal!(n!());
-//~^ ERROR incorrect `repr(align)` attribute format: `align` expects a literal integer as argument [E0693]
 
 fn main() {}
diff --git a/tests/ui/attributes/nonterminal-expansion.stderr b/tests/ui/attributes/nonterminal-expansion.stderr
index b640575d17d..cce5c453d52 100644
--- a/tests/ui/attributes/nonterminal-expansion.stderr
+++ b/tests/ui/attributes/nonterminal-expansion.stderr
@@ -10,10 +10,15 @@ LL | pass_nonterminal!(n!());
    = note: this error originates in the macro `pass_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0693]: incorrect `repr(align)` attribute format: `align` expects a literal integer as argument
-  --> $DIR/nonterminal-expansion.rs:17:19
+  --> $DIR/nonterminal-expansion.rs:7:22
    |
+LL |         #[repr(align($n))]
+   |                      ^^
+...
 LL | pass_nonterminal!(n!());
-   |                   ^
+   | ----------------------- in this macro invocation
+   |
+   = note: this error originates in the macro `pass_nonterminal` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/attributes/repr-align-in-trait-issue-132391.rs b/tests/ui/attributes/repr-align-in-trait-issue-132391.rs
new file mode 100644
index 00000000000..b3b79e93e9b
--- /dev/null
+++ b/tests/ui/attributes/repr-align-in-trait-issue-132391.rs
@@ -0,0 +1,6 @@
+trait MyTrait {
+    #[repr(align)] //~ ERROR invalid `repr(align)` attribute: `align` needs an argument
+    fn myfun();
+}
+
+pub fn main() {}
diff --git a/tests/ui/attributes/repr-align-in-trait-issue-132391.stderr b/tests/ui/attributes/repr-align-in-trait-issue-132391.stderr
new file mode 100644
index 00000000000..4208b018f52
--- /dev/null
+++ b/tests/ui/attributes/repr-align-in-trait-issue-132391.stderr
@@ -0,0 +1,9 @@
+error[E0589]: invalid `repr(align)` attribute: `align` needs an argument
+  --> $DIR/repr-align-in-trait-issue-132391.rs:2:12
+   |
+LL |     #[repr(align)]
+   |            ^^^^^ help: supply an argument here: `align(...)`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0589`.
diff --git a/tests/ui/attributes/rustc_confusables.stderr b/tests/ui/attributes/rustc_confusables.stderr
index dc71d974daf..55c9219a08a 100644
--- a/tests/ui/attributes/rustc_confusables.stderr
+++ b/tests/ui/attributes/rustc_confusables.stderr
@@ -4,12 +4,6 @@ error: malformed `rustc_confusables` attribute input
 LL |     #[rustc_confusables]
    |     ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]`
 
-error: attribute should be applied to an inherent method
-  --> $DIR/rustc_confusables.rs:45:1
-   |
-LL | #[rustc_confusables("blah")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error: expected at least one confusable name
   --> $DIR/rustc_confusables.rs:30:5
    |
@@ -27,6 +21,12 @@ help: consider surrounding this with quotes
 LL |     #[rustc_confusables("invalid_meta_item")]
    |                         +                 +
 
+error: attribute should be applied to an inherent method
+  --> $DIR/rustc_confusables.rs:45:1
+   |
+LL | #[rustc_confusables("blah")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0599]: no method named `inser` found for struct `rustc_confusables_across_crate::BTreeSet` in the current scope
   --> $DIR/rustc_confusables.rs:12:7
    |
diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr
index 51808c5c7bc..8675f7a61c7 100644
--- a/tests/ui/check-cfg/target_feature.stderr
+++ b/tests/ui/check-cfg/target_feature.stderr
@@ -290,9 +290,14 @@ LL |     cfg!(target_feature = "_UNEXPECTED_VALUE");
 `xsavec`
 `xsaveopt`
 `xsaves`
+`za128rs`
+`za64rs`
 `zaamo`
 `zabha`
+`zacas`
 `zalrsc`
+`zama16b`
+`zawrs`
 `zba`
 `zbb`
 `zbc`
diff --git a/tests/ui/coercion/issue-26905.stderr b/tests/ui/coercion/issue-26905.stderr
index 86f6a14cd10..17387ae992b 100644
--- a/tests/ui/coercion/issue-26905.stderr
+++ b/tests/ui/coercion/issue-26905.stderr
@@ -1,11 +1,16 @@
-error[E0375]: implementing the trait `CoerceUnsized` requires multiple coercions
+error[E0375]: implementing `CoerceUnsized` does not allow multiple fields to be coerced
   --> $DIR/issue-26905.rs:16:40
    |
 LL | impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<MyRc<U>> for MyRc<T>{ }
-   |                                        ^^^^^^^^^^^^^^^^^^^^^^ requires multiple coercions
+   |                                        ^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced
-   = note: currently, 2 fields need coercions: `_ptr` (`*const T` to `*const U`), `_boo` (`NotPhantomData<T>` to `NotPhantomData<U>`)
+note: the trait `CoerceUnsized` may only be implemented when a single field is being coerced
+  --> $DIR/issue-26905.rs:12:5
+   |
+LL |     _ptr: *const T,
+   |     ^^^^^^^^^^^^^^
+LL |     _boo: NotPhantomData<T>,
+   |     ^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/coherence/coherence-unsafe-trait-object-impl.rs b/tests/ui/coherence/coherence-unsafe-trait-object-impl.rs
deleted file mode 100644
index 16baf0958a6..00000000000
--- a/tests/ui/coherence/coherence-unsafe-trait-object-impl.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Check that unsafe trait object do not implement themselves
-// automatically
-
-#![feature(dyn_compatible_for_dispatch)]
-
-trait Trait: Sized {
-    fn call(&self);
-}
-
-fn takes_t<S: Trait>(s: S) {
-    s.call();
-}
-
-fn takes_t_obj(t: &dyn Trait) {
-    takes_t(t); //~ ERROR E0277
-}
-
-fn main() {}
diff --git a/tests/ui/coherence/coherence-unsafe-trait-object-impl.stderr b/tests/ui/coherence/coherence-unsafe-trait-object-impl.stderr
deleted file mode 100644
index 4f898ec127b..00000000000
--- a/tests/ui/coherence/coherence-unsafe-trait-object-impl.stderr
+++ /dev/null
@@ -1,22 +0,0 @@
-error[E0277]: the trait bound `&dyn Trait: Trait` is not satisfied
-  --> $DIR/coherence-unsafe-trait-object-impl.rs:15:13
-   |
-LL |     takes_t(t);
-   |     ------- ^ the trait `Trait` is not implemented for `&dyn Trait`
-   |     |
-   |     required by a bound introduced by this call
-   |
-help: this trait has no implementations, consider adding one
-  --> $DIR/coherence-unsafe-trait-object-impl.rs:6:1
-   |
-LL | trait Trait: Sized {
-   | ^^^^^^^^^^^^^^^^^^
-note: required by a bound in `takes_t`
-  --> $DIR/coherence-unsafe-trait-object-impl.rs:10:15
-   |
-LL | fn takes_t<S: Trait>(s: S) {
-   |               ^^^^^ required by this bound in `takes_t`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/const-generics/issues/cg-in-dyn-issue-128176.rs b/tests/ui/const-generics/issues/cg-in-dyn-issue-128176.rs
index 5a67d34d6e5..dac5429f678 100644
--- a/tests/ui/const-generics/issues/cg-in-dyn-issue-128176.rs
+++ b/tests/ui/const-generics/issues/cg-in-dyn-issue-128176.rs
@@ -1,10 +1,7 @@
-//@ check-pass
-
 // Regression test for #128176. Previously we would call `type_of` on the `1` anon const
 // before the anon const had been lowered and had the `type_of` fed with a result.
 
 #![feature(generic_const_exprs)]
-#![feature(dyn_compatible_for_dispatch)]
 #![allow(incomplete_features)]
 
 trait X {
@@ -13,6 +10,7 @@ trait X {
 
 const _: () = {
     fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {}
+    //~^ ERROR the trait `X` is not dyn compatible
 };
 
 fn main() {}
diff --git a/tests/ui/const-generics/issues/cg-in-dyn-issue-128176.stderr b/tests/ui/const-generics/issues/cg-in-dyn-issue-128176.stderr
new file mode 100644
index 00000000000..7d563e3b605
--- /dev/null
+++ b/tests/ui/const-generics/issues/cg-in-dyn-issue-128176.stderr
@@ -0,0 +1,19 @@
+error[E0038]: the trait `X` is not dyn compatible
+  --> $DIR/cg-in-dyn-issue-128176.rs:12:24
+   |
+LL |     fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {}
+   |                        ^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/cg-in-dyn-issue-128176.rs:8:10
+   |
+LL | trait X {
+   |       - this trait is not dyn compatible...
+LL |     type Y<const N: i16>;
+   |          ^ ...because it contains the generic associated type `Y`
+   = help: consider moving `Y` to another trait
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/deprecation/deprecation-sanity.rs b/tests/ui/deprecation/deprecation-sanity.rs
index 9ea75b68f81..d5b149b18ed 100644
--- a/tests/ui/deprecation/deprecation-sanity.rs
+++ b/tests/ui/deprecation/deprecation-sanity.rs
@@ -4,16 +4,16 @@ mod bogus_attribute_types_1 {
     #[deprecated(since = "a", note = "a", reason)] //~ ERROR unknown meta item 'reason'
     fn f1() { }
 
-    #[deprecated(since = "a", note)] //~ ERROR incorrect meta item
+    #[deprecated(since = "a", note)] //~ ERROR expected a quoted string literal
     fn f2() { }
 
-    #[deprecated(since, note = "a")] //~ ERROR incorrect meta item
+    #[deprecated(since, note = "a")] //~ ERROR expected a quoted string literal
     fn f3() { }
 
-    #[deprecated(since = "a", note(b))] //~ ERROR incorrect meta item
+    #[deprecated(since = "a", note(b))] //~ ERROR expected a quoted string literal
     fn f5() { }
 
-    #[deprecated(since(b), note = "a")] //~ ERROR incorrect meta item
+    #[deprecated(since(b), note = "a")] //~ ERROR expected a quoted string literal
     fn f6() { }
 
     #[deprecated(note = b"test")] //~ ERROR literal in `deprecated` value must be a string
diff --git a/tests/ui/deprecation/deprecation-sanity.stderr b/tests/ui/deprecation/deprecation-sanity.stderr
index 383212ad9b4..53047d40cb2 100644
--- a/tests/ui/deprecation/deprecation-sanity.stderr
+++ b/tests/ui/deprecation/deprecation-sanity.stderr
@@ -1,40 +1,28 @@
-error: multiple `deprecated` attributes
-  --> $DIR/deprecation-sanity.rs:27:1
-   |
-LL | #[deprecated(since = "a", note = "b")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
-   |
-note: attribute also specified here
-  --> $DIR/deprecation-sanity.rs:26:1
-   |
-LL | #[deprecated(since = "a", note = "b")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error[E0541]: unknown meta item 'reason'
   --> $DIR/deprecation-sanity.rs:4:43
    |
 LL |     #[deprecated(since = "a", note = "a", reason)]
    |                                           ^^^^^^ expected one of `since`, `note`
 
-error[E0539]: incorrect meta item
+error[E0539]: expected a quoted string literal
   --> $DIR/deprecation-sanity.rs:7:31
    |
 LL |     #[deprecated(since = "a", note)]
    |                               ^^^^
 
-error[E0539]: incorrect meta item
+error[E0539]: expected a quoted string literal
   --> $DIR/deprecation-sanity.rs:10:18
    |
 LL |     #[deprecated(since, note = "a")]
    |                  ^^^^^
 
-error[E0539]: incorrect meta item
+error[E0539]: expected a quoted string literal
   --> $DIR/deprecation-sanity.rs:13:31
    |
 LL |     #[deprecated(since = "a", note(b))]
    |                               ^^^^^^^
 
-error[E0539]: incorrect meta item
+error[E0539]: expected a quoted string literal
   --> $DIR/deprecation-sanity.rs:16:18
    |
 LL |     #[deprecated(since(b), note = "a")]
@@ -54,6 +42,18 @@ error[E0565]: item in `deprecated` must be a key/value pair
 LL |     #[deprecated("test")]
    |                  ^^^^^^
 
+error: multiple `deprecated` attributes
+  --> $DIR/deprecation-sanity.rs:27:1
+   |
+LL | #[deprecated(since = "a", note = "b")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+note: attribute also specified here
+  --> $DIR/deprecation-sanity.rs:26:1
+   |
+LL | #[deprecated(since = "a", note = "b")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0538]: multiple 'since' items
   --> $DIR/deprecation-sanity.rs:30:27
    |
diff --git a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs
index 6653bd15ddd..c5433151a8f 100644
--- a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs
+++ b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.rs
@@ -3,7 +3,7 @@
 // was a well-formed `MetaItem`.
 
 fn main() {
-    foo()
+    foo() //~ WARNING use of deprecated function `foo`
 }
 
 #[deprecated(note = test)]
diff --git a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr
index a030da5068c..2ff8534b276 100644
--- a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr
+++ b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr
@@ -9,5 +9,13 @@ help: surround the identifier with quotation marks to make it into a string lite
 LL | #[deprecated(note = "test")]
    |                     +    +
 
-error: aborting due to 1 previous error
+warning: use of deprecated function `foo`
+  --> $DIR/issue-66340-deprecated-attr-non-meta-grammar.rs:6:5
+   |
+LL |     foo()
+   |     ^^^
+   |
+   = note: `#[warn(deprecated)]` on by default
+
+error: aborting due to 1 previous error; 1 warning emitted
 
diff --git a/tests/ui/deriving/deriving-coerce-pointee-neg.rs b/tests/ui/deriving/deriving-coerce-pointee-neg.rs
index 6577500d8eb..2713366945e 100644
--- a/tests/ui/deriving/deriving-coerce-pointee-neg.rs
+++ b/tests/ui/deriving/deriving-coerce-pointee-neg.rs
@@ -142,4 +142,27 @@ struct TryToWipeRepr<'a, #[pointee] T: ?Sized> {
     ptr: &'a T,
 }
 
+#[repr(transparent)]
+#[derive(CoercePointee)]
+//~^ ERROR for `RcWithId<T>` to have a valid implementation of `CoerceUnsized`, it must be possible to coerce the field of type `Rc<(i32, Box<T>)>`
+struct RcWithId<T: ?Sized> {
+    inner: std::rc::Rc<(i32, Box<T>)>,
+}
+
+#[repr(transparent)]
+#[derive(CoercePointee)]
+//~^ ERROR implementing `CoerceUnsized` does not allow multiple fields to be coerced
+struct MoreThanOneField<T: ?Sized> {
+    //~^ ERROR transparent struct needs at most one field with non-trivial size or alignment, but has 2
+    inner1: Box<T>,
+    inner2: Box<T>,
+}
+
+struct NotCoercePointeeData<T: ?Sized>(T);
+
+#[repr(transparent)]
+#[derive(CoercePointee)]
+//~^ ERROR for `UsingNonCoercePointeeData<T>` to have a valid implementation of `CoerceUnsized`, it must be possible to coerce the field of type `NotCoercePointeeData<T>`
+struct UsingNonCoercePointeeData<T: ?Sized>(NotCoercePointeeData<T>);
+
 fn main() {}
diff --git a/tests/ui/deriving/deriving-coerce-pointee-neg.stderr b/tests/ui/deriving/deriving-coerce-pointee-neg.stderr
index 999214bfa9f..d3d73132078 100644
--- a/tests/ui/deriving/deriving-coerce-pointee-neg.stderr
+++ b/tests/ui/deriving/deriving-coerce-pointee-neg.stderr
@@ -118,7 +118,55 @@ error[E0802]: `derive(CoercePointee)` is only applicable to `struct` with `repr(
 LL | struct TryToWipeRepr<'a, #[pointee] T: ?Sized> {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 17 previous errors
+error: for `RcWithId<T>` to have a valid implementation of `CoerceUnsized`, it must be possible to coerce the field of type `Rc<(i32, Box<T>)>`
+  --> $DIR/deriving-coerce-pointee-neg.rs:146:10
+   |
+LL | #[derive(CoercePointee)]
+   |          ^^^^^^^^^^^^^
+...
+LL |     inner: std::rc::Rc<(i32, Box<T>)>,
+   |     --------------------------------- `Rc<(i32, Box<T>)>` must be a pointer, reference, or smart pointer that is allowed to be unsized
+   |
+   = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0375]: implementing `CoerceUnsized` does not allow multiple fields to be coerced
+  --> $DIR/deriving-coerce-pointee-neg.rs:153:10
+   |
+LL | #[derive(CoercePointee)]
+   |          ^^^^^^^^^^^^^
+   |
+note: the trait `CoerceUnsized` may only be implemented when a single field is being coerced
+  --> $DIR/deriving-coerce-pointee-neg.rs:157:5
+   |
+LL |     inner1: Box<T>,
+   |     ^^^^^^^^^^^^^^
+LL |     inner2: Box<T>,
+   |     ^^^^^^^^^^^^^^
+   = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: for `UsingNonCoercePointeeData<T>` to have a valid implementation of `CoerceUnsized`, it must be possible to coerce the field of type `NotCoercePointeeData<T>`
+  --> $DIR/deriving-coerce-pointee-neg.rs:164:10
+   |
+LL | #[derive(CoercePointee)]
+   |          ^^^^^^^^^^^^^
+LL |
+LL | struct UsingNonCoercePointeeData<T: ?Sized>(NotCoercePointeeData<T>);
+   |                                             ----------------------- `NotCoercePointeeData<T>` must be a pointer, reference, or smart pointer that is allowed to be unsized
+   |
+   = note: this error originates in the derive macro `CoercePointee` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0690]: transparent struct needs at most one field with non-trivial size or alignment, but has 2
+  --> $DIR/deriving-coerce-pointee-neg.rs:155:1
+   |
+LL | struct MoreThanOneField<T: ?Sized> {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ needs at most one field with non-trivial size or alignment, but has 2
+LL |
+LL |     inner1: Box<T>,
+   |     -------------- this field has non-zero size or requires alignment
+LL |     inner2: Box<T>,
+   |     -------------- this field has non-zero size or requires alignment
+
+error: aborting due to 21 previous errors
 
-Some errors have detailed explanations: E0392, E0802.
-For more information about an error, try `rustc --explain E0392`.
+Some errors have detailed explanations: E0375, E0392, E0690, E0802.
+For more information about an error, try `rustc --explain E0375`.
diff --git a/tests/ui/dropck/dropck-after-failed-type-lowering.rs b/tests/ui/dropck/dropck-after-failed-type-lowering.rs
new file mode 100644
index 00000000000..2441e26fec9
--- /dev/null
+++ b/tests/ui/dropck/dropck-after-failed-type-lowering.rs
@@ -0,0 +1,14 @@
+// Regression test for #137329
+
+trait B {
+    type C<'a>;
+    fn d<E>() -> F<E> {
+        todo!()
+    }
+}
+struct F<G> {
+    h: Option<<G as B>::C>,
+    //~^ ERROR missing generics for associated type `B::C`
+}
+
+fn main() {}
diff --git a/tests/ui/dropck/dropck-after-failed-type-lowering.stderr b/tests/ui/dropck/dropck-after-failed-type-lowering.stderr
new file mode 100644
index 00000000000..56ea72de0c5
--- /dev/null
+++ b/tests/ui/dropck/dropck-after-failed-type-lowering.stderr
@@ -0,0 +1,19 @@
+error[E0107]: missing generics for associated type `B::C`
+  --> $DIR/dropck-after-failed-type-lowering.rs:10:25
+   |
+LL |     h: Option<<G as B>::C>,
+   |                         ^ expected 1 lifetime argument
+   |
+note: associated type defined here, with 1 lifetime parameter: `'a`
+  --> $DIR/dropck-after-failed-type-lowering.rs:4:10
+   |
+LL |     type C<'a>;
+   |          ^ --
+help: add missing lifetime argument
+   |
+LL |     h: Option<<G as B>::C<'a>>,
+   |                          ++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0107`.
diff --git a/tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr
deleted file mode 100644
index 704d833f00b..00000000000
--- a/tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error[E0038]: the trait `Bar` is not dyn compatible
-  --> $DIR/associated-consts.rs:14:5
-   |
-LL |     t
-   |     ^ `Bar` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/associated-consts.rs:9:11
-   |
-LL | trait Bar {
-   |       --- this trait is not dyn compatible...
-LL |     const X: usize;
-   |           ^ ...because it contains this associated `const`
-   = help: consider moving `X` to another trait
-   = note: required for the cast from `&T` to `&dyn Bar`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/dyn-compatibility/associated-consts.rs b/tests/ui/dyn-compatibility/associated-consts.rs
index fc7b372b782..10d151d9a8b 100644
--- a/tests/ui/dyn-compatibility/associated-consts.rs
+++ b/tests/ui/dyn-compatibility/associated-consts.rs
@@ -1,16 +1,12 @@
 // Check that we correctly prevent users from making trait objects
 // from traits with associated consts.
-//
-//@ revisions: curr dyn_compatible_for_dispatch
-
-#![cfg_attr(dyn_compatible_for_dispatch, feature(dyn_compatible_for_dispatch))]
 
 trait Bar {
     const X: usize;
 }
 
 fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-    //[curr]~^ ERROR E0038
+    //~^ ERROR E0038
     t
     //~^ ERROR E0038
 }
diff --git a/tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/associated-consts.stderr
index b3565a766fe..beaf263af07 100644
--- a/tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/dyn-compatibility/associated-consts.stderr
@@ -1,35 +1,34 @@
 error[E0038]: the trait `Bar` is not dyn compatible
-  --> $DIR/generics.rs:20:5
+  --> $DIR/associated-consts.rs:8:31
    |
-LL |     t
-   |     ^ `Bar` is not dyn compatible
+LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
+   |                               ^^^^^^^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
       for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/generics.rs:10:8
+  --> $DIR/associated-consts.rs:5:11
    |
 LL | trait Bar {
    |       --- this trait is not dyn compatible...
-LL |     fn bar<T>(&self, t: T);
-   |        ^^^ ...because method `bar` has generic type parameters
-   = help: consider moving `bar` to another trait
-   = note: required for the cast from `&T` to `&dyn Bar`
+LL |     const X: usize;
+   |           ^ ...because it contains this associated `const`
+   = help: consider moving `X` to another trait
 
 error[E0038]: the trait `Bar` is not dyn compatible
-  --> $DIR/generics.rs:27:5
+  --> $DIR/associated-consts.rs:10:5
    |
-LL |     t as &dyn Bar
+LL |     t
    |     ^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
       for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/generics.rs:10:8
+  --> $DIR/associated-consts.rs:5:11
    |
 LL | trait Bar {
    |       --- this trait is not dyn compatible...
-LL |     fn bar<T>(&self, t: T);
-   |        ^^^ ...because method `bar` has generic type parameters
-   = help: consider moving `bar` to another trait
+LL |     const X: usize;
+   |           ^ ...because it contains this associated `const`
+   = help: consider moving `X` to another trait
    = note: required for the cast from `&T` to `&dyn Bar`
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/dyn-compatibility/generics.rs b/tests/ui/dyn-compatibility/generics.rs
index b51555aa500..dcce17f925b 100644
--- a/tests/ui/dyn-compatibility/generics.rs
+++ b/tests/ui/dyn-compatibility/generics.rs
@@ -1,9 +1,6 @@
 // Check that we correctly prevent users from making trait objects
 // from traits with generic methods, unless `where Self : Sized` is
 // present.
-//@ revisions: curr dyn_compatible_for_dispatch
-
-#![cfg_attr(dyn_compatible_for_dispatch, feature(dyn_compatible_for_dispatch))]
 
 
 trait Bar {
@@ -16,18 +13,16 @@ trait Quux {
 }
 
 fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-    //[curr]~^ ERROR E0038
+    //~^ ERROR E0038
     t
-    //[dyn_compatible_for_dispatch]~^ ERROR E0038
-    //[curr]~^^ ERROR E0038
+    //~^ ERROR E0038
 }
 
 fn make_bar_explicit<T:Bar>(t: &T) -> &dyn Bar {
-    //[curr]~^ ERROR E0038
+    //~^ ERROR E0038
     t as &dyn Bar
-    //[dyn_compatible_for_dispatch]~^ ERROR E0038
-    //[curr]~^^ ERROR E0038
-    //[curr]~| ERROR E0038
+    //~^ ERROR E0038
+    //~| ERROR E0038
 }
 
 fn make_quux<T:Quux>(t: &T) -> &dyn Quux {
diff --git a/tests/ui/dyn-compatibility/generics.stderr b/tests/ui/dyn-compatibility/generics.stderr
new file mode 100644
index 00000000000..c0193010541
--- /dev/null
+++ b/tests/ui/dyn-compatibility/generics.stderr
@@ -0,0 +1,85 @@
+error[E0038]: the trait `Bar` is not dyn compatible
+  --> $DIR/generics.rs:15:31
+   |
+LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
+   |                               ^^^^^^^ `Bar` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/generics.rs:7:8
+   |
+LL | trait Bar {
+   |       --- this trait is not dyn compatible...
+LL |     fn bar<T>(&self, t: T);
+   |        ^^^ ...because method `bar` has generic type parameters
+   = help: consider moving `bar` to another trait
+
+error[E0038]: the trait `Bar` is not dyn compatible
+  --> $DIR/generics.rs:21:40
+   |
+LL | fn make_bar_explicit<T:Bar>(t: &T) -> &dyn Bar {
+   |                                        ^^^^^^^ `Bar` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/generics.rs:7:8
+   |
+LL | trait Bar {
+   |       --- this trait is not dyn compatible...
+LL |     fn bar<T>(&self, t: T);
+   |        ^^^ ...because method `bar` has generic type parameters
+   = help: consider moving `bar` to another trait
+
+error[E0038]: the trait `Bar` is not dyn compatible
+  --> $DIR/generics.rs:17:5
+   |
+LL |     t
+   |     ^ `Bar` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/generics.rs:7:8
+   |
+LL | trait Bar {
+   |       --- this trait is not dyn compatible...
+LL |     fn bar<T>(&self, t: T);
+   |        ^^^ ...because method `bar` has generic type parameters
+   = help: consider moving `bar` to another trait
+   = note: required for the cast from `&T` to `&dyn Bar`
+
+error[E0038]: the trait `Bar` is not dyn compatible
+  --> $DIR/generics.rs:23:10
+   |
+LL |     t as &dyn Bar
+   |          ^^^^^^^^ `Bar` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/generics.rs:7:8
+   |
+LL | trait Bar {
+   |       --- this trait is not dyn compatible...
+LL |     fn bar<T>(&self, t: T);
+   |        ^^^ ...because method `bar` has generic type parameters
+   = help: consider moving `bar` to another trait
+
+error[E0038]: the trait `Bar` is not dyn compatible
+  --> $DIR/generics.rs:23:5
+   |
+LL |     t as &dyn Bar
+   |     ^ `Bar` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/generics.rs:7:8
+   |
+LL | trait Bar {
+   |       --- this trait is not dyn compatible...
+LL |     fn bar<T>(&self, t: T);
+   |        ^^^ ...because method `bar` has generic type parameters
+   = help: consider moving `bar` to another trait
+   = note: required for the cast from `&T` to `&dyn Bar`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/dyn-compatibility/mentions-Self.curr.stderr b/tests/ui/dyn-compatibility/mentions-Self.curr.stderr
index 2d3fe5ce636..6d1ae90152e 100644
--- a/tests/ui/dyn-compatibility/mentions-Self.curr.stderr
+++ b/tests/ui/dyn-compatibility/mentions-Self.curr.stderr
@@ -1,12 +1,12 @@
 error[E0038]: the trait `Bar` is not dyn compatible
-  --> $DIR/mentions-Self.rs:22:31
+  --> $DIR/mentions-Self.rs:18:31
    |
 LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
    |                               ^^^^^^^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
       for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/mentions-Self.rs:11:22
+  --> $DIR/mentions-Self.rs:7:22
    |
 LL | trait Bar {
    |       --- this trait is not dyn compatible...
@@ -15,14 +15,14 @@ LL |     fn bar(&self, x: &Self);
    = help: consider moving `bar` to another trait
 
 error[E0038]: the trait `Baz` is not dyn compatible
-  --> $DIR/mentions-Self.rs:28:31
+  --> $DIR/mentions-Self.rs:24:31
    |
 LL | fn make_baz<T:Baz>(t: &T) -> &dyn Baz {
    |                               ^^^^^^^ `Baz` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
       for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/mentions-Self.rs:15:22
+  --> $DIR/mentions-Self.rs:11:22
    |
 LL | trait Baz {
    |       --- this trait is not dyn compatible...
@@ -31,14 +31,14 @@ LL |     fn baz(&self) -> Self;
    = help: consider moving `baz` to another trait
 
 error[E0038]: the trait `Bar` is not dyn compatible
-  --> $DIR/mentions-Self.rs:24:5
+  --> $DIR/mentions-Self.rs:20:5
    |
 LL |     t
    |     ^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
       for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/mentions-Self.rs:11:22
+  --> $DIR/mentions-Self.rs:7:22
    |
 LL | trait Bar {
    |       --- this trait is not dyn compatible...
@@ -48,14 +48,14 @@ LL |     fn bar(&self, x: &Self);
    = note: required for the cast from `&T` to `&dyn Bar`
 
 error[E0038]: the trait `Baz` is not dyn compatible
-  --> $DIR/mentions-Self.rs:30:5
+  --> $DIR/mentions-Self.rs:26:5
    |
 LL |     t
    |     ^ `Baz` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
       for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/mentions-Self.rs:15:22
+  --> $DIR/mentions-Self.rs:11:22
    |
 LL | trait Baz {
    |       --- this trait is not dyn compatible...
diff --git a/tests/ui/dyn-compatibility/mentions-Self.rs b/tests/ui/dyn-compatibility/mentions-Self.rs
index 84c229e252d..ce210f4776f 100644
--- a/tests/ui/dyn-compatibility/mentions-Self.rs
+++ b/tests/ui/dyn-compatibility/mentions-Self.rs
@@ -1,10 +1,6 @@
 // Check that we correctly prevent users from making trait objects
 // form traits that make use of `Self` in an argument or return
 // position, unless `where Self : Sized` is present..
-//
-//@ revisions: curr dyn_compatible_for_dispatch
-
-#![cfg_attr(dyn_compatible_for_dispatch, feature(dyn_compatible_for_dispatch))]
 
 
 trait Bar {
@@ -20,13 +16,13 @@ trait Quux {
 }
 
 fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-    //[curr]~^ ERROR E0038
+    //~^ ERROR E0038
     t
     //~^ ERROR E0038
 }
 
 fn make_baz<T:Baz>(t: &T) -> &dyn Baz {
-    //[curr]~^ ERROR E0038
+    //~^ ERROR E0038
     t
     //~^ ERROR E0038
 }
diff --git a/tests/ui/dyn-compatibility/mentions-Self.stderr b/tests/ui/dyn-compatibility/mentions-Self.stderr
new file mode 100644
index 00000000000..6d1ae90152e
--- /dev/null
+++ b/tests/ui/dyn-compatibility/mentions-Self.stderr
@@ -0,0 +1,69 @@
+error[E0038]: the trait `Bar` is not dyn compatible
+  --> $DIR/mentions-Self.rs:18:31
+   |
+LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
+   |                               ^^^^^^^ `Bar` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/mentions-Self.rs:7:22
+   |
+LL | trait Bar {
+   |       --- this trait is not dyn compatible...
+LL |     fn bar(&self, x: &Self);
+   |                      ^^^^^ ...because method `bar` references the `Self` type in this parameter
+   = help: consider moving `bar` to another trait
+
+error[E0038]: the trait `Baz` is not dyn compatible
+  --> $DIR/mentions-Self.rs:24:31
+   |
+LL | fn make_baz<T:Baz>(t: &T) -> &dyn Baz {
+   |                               ^^^^^^^ `Baz` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/mentions-Self.rs:11:22
+   |
+LL | trait Baz {
+   |       --- this trait is not dyn compatible...
+LL |     fn baz(&self) -> Self;
+   |                      ^^^^ ...because method `baz` references the `Self` type in its return type
+   = help: consider moving `baz` to another trait
+
+error[E0038]: the trait `Bar` is not dyn compatible
+  --> $DIR/mentions-Self.rs:20:5
+   |
+LL |     t
+   |     ^ `Bar` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/mentions-Self.rs:7:22
+   |
+LL | trait Bar {
+   |       --- this trait is not dyn compatible...
+LL |     fn bar(&self, x: &Self);
+   |                      ^^^^^ ...because method `bar` references the `Self` type in this parameter
+   = help: consider moving `bar` to another trait
+   = note: required for the cast from `&T` to `&dyn Bar`
+
+error[E0038]: the trait `Baz` is not dyn compatible
+  --> $DIR/mentions-Self.rs:26:5
+   |
+LL |     t
+   |     ^ `Baz` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/mentions-Self.rs:11:22
+   |
+LL | trait Baz {
+   |       --- this trait is not dyn compatible...
+LL |     fn baz(&self) -> Self;
+   |                      ^^^^ ...because method `baz` references the `Self` type in its return type
+   = help: consider moving `baz` to another trait
+   = note: required for the cast from `&T` to `&dyn Baz`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr
deleted file mode 100644
index d5ad4510334..00000000000
--- a/tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr
+++ /dev/null
@@ -1,28 +0,0 @@
-error[E0038]: the trait `Foo` is not dyn compatible
-  --> $DIR/no-static.rs:22:27
-   |
-LL |     let b: Box<dyn Foo> = Box::new(Bar);
-   |                           ^^^^^^^^^^^^^ `Foo` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/no-static.rs:9:8
-   |
-LL | trait Foo {
-   |       --- this trait is not dyn compatible...
-LL |     fn foo() {}
-   |        ^^^ ...because associated function `foo` has no `self` parameter
-   = help: only type `Bar` implements `Foo`; consider using it directly instead.
-   = note: required for the cast from `Box<Bar>` to `Box<dyn Foo>`
-help: consider turning `foo` into a method by giving it a `&self` argument
-   |
-LL |     fn foo(&self) {}
-   |            +++++
-help: alternatively, consider constraining `foo` so it does not apply to trait objects
-   |
-LL |     fn foo() where Self: Sized {}
-   |              +++++++++++++++++
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/dyn-compatibility/no-static.rs b/tests/ui/dyn-compatibility/no-static.rs
index 54af16fe18e..9bd87161972 100644
--- a/tests/ui/dyn-compatibility/no-static.rs
+++ b/tests/ui/dyn-compatibility/no-static.rs
@@ -1,16 +1,12 @@
 // Check that we correctly prevent users from making trait objects
 // from traits with static methods.
-//
-//@ revisions: curr dyn_compatible_for_dispatch
-
-#![cfg_attr(dyn_compatible_for_dispatch, feature(dyn_compatible_for_dispatch))]
 
 trait Foo {
     fn foo() {}
 }
 
 fn diverges() -> Box<dyn Foo> {
-    //[curr]~^ ERROR E0038
+    //~^ ERROR E0038
     loop { }
 }
 
@@ -21,5 +17,5 @@ impl Foo for Bar {}
 fn main() {
     let b: Box<dyn Foo> = Box::new(Bar);
     //~^ ERROR E0038
-    //[curr]~| ERROR E0038
+    //~| ERROR E0038
 }
diff --git a/tests/ui/dyn-compatibility/no-static.stderr b/tests/ui/dyn-compatibility/no-static.stderr
new file mode 100644
index 00000000000..814ab0d53c3
--- /dev/null
+++ b/tests/ui/dyn-compatibility/no-static.stderr
@@ -0,0 +1,76 @@
+error[E0038]: the trait `Foo` is not dyn compatible
+  --> $DIR/no-static.rs:8:22
+   |
+LL | fn diverges() -> Box<dyn Foo> {
+   |                      ^^^^^^^ `Foo` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/no-static.rs:5:8
+   |
+LL | trait Foo {
+   |       --- this trait is not dyn compatible...
+LL |     fn foo() {}
+   |        ^^^ ...because associated function `foo` has no `self` parameter
+   = help: only type `Bar` implements `Foo`; consider using it directly instead.
+help: consider turning `foo` into a method by giving it a `&self` argument
+   |
+LL |     fn foo(&self) {}
+   |            +++++
+help: alternatively, consider constraining `foo` so it does not apply to trait objects
+   |
+LL |     fn foo() where Self: Sized {}
+   |              +++++++++++++++++
+
+error[E0038]: the trait `Foo` is not dyn compatible
+  --> $DIR/no-static.rs:18:12
+   |
+LL |     let b: Box<dyn Foo> = Box::new(Bar);
+   |            ^^^^^^^^^^^^ `Foo` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/no-static.rs:5:8
+   |
+LL | trait Foo {
+   |       --- this trait is not dyn compatible...
+LL |     fn foo() {}
+   |        ^^^ ...because associated function `foo` has no `self` parameter
+   = help: only type `Bar` implements `Foo`; consider using it directly instead.
+help: consider turning `foo` into a method by giving it a `&self` argument
+   |
+LL |     fn foo(&self) {}
+   |            +++++
+help: alternatively, consider constraining `foo` so it does not apply to trait objects
+   |
+LL |     fn foo() where Self: Sized {}
+   |              +++++++++++++++++
+
+error[E0038]: the trait `Foo` is not dyn compatible
+  --> $DIR/no-static.rs:18:27
+   |
+LL |     let b: Box<dyn Foo> = Box::new(Bar);
+   |                           ^^^^^^^^^^^^^ `Foo` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/no-static.rs:5:8
+   |
+LL | trait Foo {
+   |       --- this trait is not dyn compatible...
+LL |     fn foo() {}
+   |        ^^^ ...because associated function `foo` has no `self` parameter
+   = help: only type `Bar` implements `Foo`; consider using it directly instead.
+   = note: required for the cast from `Box<Bar>` to `Box<dyn Foo>`
+help: consider turning `foo` into a method by giving it a `&self` argument
+   |
+LL |     fn foo(&self) {}
+   |            +++++
+help: alternatively, consider constraining `foo` so it does not apply to trait objects
+   |
+LL |     fn foo() where Self: Sized {}
+   |              +++++++++++++++++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr
deleted file mode 100644
index 1fbc10c0c3f..00000000000
--- a/tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0038]: the trait `Bar` is not dyn compatible
-  --> $DIR/sized-2.rs:16:5
-   |
-LL |     t
-   |     ^ `Bar` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/sized-2.rs:9:18
-   |
-LL | trait Bar
-   |       --- this trait is not dyn compatible...
-LL |     where Self : Sized
-   |                  ^^^^^ ...because it requires `Self: Sized`
-   = note: required for the cast from `&T` to `&dyn Bar`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/dyn-compatibility/sized-2.rs b/tests/ui/dyn-compatibility/sized-2.rs
index f5edd287f24..f61d49ee8df 100644
--- a/tests/ui/dyn-compatibility/sized-2.rs
+++ b/tests/ui/dyn-compatibility/sized-2.rs
@@ -1,9 +1,5 @@
 // Check that we correctly prevent users from making trait objects
 // from traits where `Self : Sized`.
-//
-//@ revisions: curr dyn_compatible_for_dispatch
-
-#![cfg_attr(dyn_compatible_for_dispatch, feature(dyn_compatible_for_dispatch))]
 
 trait Bar
     where Self : Sized
@@ -12,7 +8,7 @@ trait Bar
 }
 
 fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
-    //[curr]~^ ERROR E0038
+    //~^ ERROR E0038
     t
     //~^ ERROR E0038
 }
diff --git a/tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/sized-2.stderr
index 91c26a86025..1834d906bb8 100644
--- a/tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/dyn-compatibility/sized-2.stderr
@@ -1,36 +1,33 @@
 error[E0038]: the trait `Bar` is not dyn compatible
-  --> $DIR/mentions-Self.rs:24:5
+  --> $DIR/sized-2.rs:10:31
    |
-LL |     t
-   |     ^ `Bar` is not dyn compatible
+LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar {
+   |                               ^^^^^^^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
       for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/mentions-Self.rs:11:22
+  --> $DIR/sized-2.rs:5:18
    |
-LL | trait Bar {
+LL | trait Bar
    |       --- this trait is not dyn compatible...
-LL |     fn bar(&self, x: &Self);
-   |                      ^^^^^ ...because method `bar` references the `Self` type in this parameter
-   = help: consider moving `bar` to another trait
-   = note: required for the cast from `&T` to `&dyn Bar`
+LL |     where Self : Sized
+   |                  ^^^^^ ...because it requires `Self: Sized`
 
-error[E0038]: the trait `Baz` is not dyn compatible
-  --> $DIR/mentions-Self.rs:30:5
+error[E0038]: the trait `Bar` is not dyn compatible
+  --> $DIR/sized-2.rs:12:5
    |
 LL |     t
-   |     ^ `Baz` is not dyn compatible
+   |     ^ `Bar` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
       for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/mentions-Self.rs:15:22
+  --> $DIR/sized-2.rs:5:18
    |
-LL | trait Baz {
+LL | trait Bar
    |       --- this trait is not dyn compatible...
-LL |     fn baz(&self) -> Self;
-   |                      ^^^^ ...because method `baz` references the `Self` type in its return type
-   = help: consider moving `baz` to another trait
-   = note: required for the cast from `&T` to `&dyn Baz`
+LL |     where Self : Sized
+   |                  ^^^^^ ...because it requires `Self: Sized`
+   = note: required for the cast from `&T` to `&dyn Bar`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr
deleted file mode 100644
index 350c8992c6f..00000000000
--- a/tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr
+++ /dev/null
@@ -1,19 +0,0 @@
-error[E0038]: the trait `Bar` is not dyn compatible
-  --> $DIR/sized.rs:14:5
-   |
-LL |     t
-   |     ^ `Bar` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/sized.rs:8:12
-   |
-LL | trait Bar: Sized {
-   |       ---  ^^^^^ ...because it requires `Self: Sized`
-   |       |
-   |       this trait is not dyn compatible...
-   = note: required for the cast from `&T` to `&dyn Bar`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/dyn-compatibility/sized.rs b/tests/ui/dyn-compatibility/sized.rs
index 4c4fe3f8f25..eb5279c17e6 100644
--- a/tests/ui/dyn-compatibility/sized.rs
+++ b/tests/ui/dyn-compatibility/sized.rs
@@ -1,16 +1,12 @@
 // Check that we correctly prevent users from making trait objects
 // from traits where `Self : Sized`.
-//
-//@ revisions: curr dyn_compatible_for_dispatch
-
-#![cfg_attr(dyn_compatible_for_dispatch, feature(dyn_compatible_for_dispatch))]
 
 trait Bar: Sized {
     fn bar<T>(&self, t: T);
 }
 
 fn make_bar<T: Bar>(t: &T) -> &dyn Bar {
-    //[curr]~^ ERROR E0038
+    //~^ ERROR E0038
     t
     //~^ ERROR E0038
 }
diff --git a/tests/ui/dyn-compatibility/sized.stderr b/tests/ui/dyn-compatibility/sized.stderr
new file mode 100644
index 00000000000..c66e299cf6f
--- /dev/null
+++ b/tests/ui/dyn-compatibility/sized.stderr
@@ -0,0 +1,34 @@
+error[E0038]: the trait `Bar` is not dyn compatible
+  --> $DIR/sized.rs:8:32
+   |
+LL | fn make_bar<T: Bar>(t: &T) -> &dyn Bar {
+   |                                ^^^^^^^ `Bar` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/sized.rs:4:12
+   |
+LL | trait Bar: Sized {
+   |       ---  ^^^^^ ...because it requires `Self: Sized`
+   |       |
+   |       this trait is not dyn compatible...
+
+error[E0038]: the trait `Bar` is not dyn compatible
+  --> $DIR/sized.rs:10:5
+   |
+LL |     t
+   |     ^ `Bar` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/sized.rs:4:12
+   |
+LL | trait Bar: Sized {
+   |       ---  ^^^^^ ...because it requires `Self: Sized`
+   |       |
+   |       this trait is not dyn compatible...
+   = note: required for the cast from `&T` to `&dyn Bar`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/dyn-compatibility/taint-const-eval.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/taint-const-eval.dyn_compatible_for_dispatch.stderr
deleted file mode 100644
index 0bc7d0b14d3..00000000000
--- a/tests/ui/dyn-compatibility/taint-const-eval.dyn_compatible_for_dispatch.stderr
+++ /dev/null
@@ -1,27 +0,0 @@
-error[E0038]: the trait `Qux` is not dyn compatible
-  --> $DIR/taint-const-eval.rs:11:33
-   |
-LL | static FOO: &(dyn Qux + Sync) = "desc";
-   |                                 ^^^^^^ `Qux` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/taint-const-eval.rs:8:8
-   |
-LL | trait Qux {
-   |       --- this trait is not dyn compatible...
-LL |     fn bar();
-   |        ^^^ ...because associated function `bar` has no `self` parameter
-   = note: required for the cast from `&'static str` to `&'static (dyn Qux + Sync + 'static)`
-help: consider turning `bar` into a method by giving it a `&self` argument
-   |
-LL |     fn bar(&self);
-   |            +++++
-help: alternatively, consider constraining `bar` so it does not apply to trait objects
-   |
-LL |     fn bar() where Self: Sized;
-   |              +++++++++++++++++
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/dyn-compatibility/taint-const-eval.rs b/tests/ui/dyn-compatibility/taint-const-eval.rs
index 2feae58080b..7ea763e1846 100644
--- a/tests/ui/dyn-compatibility/taint-const-eval.rs
+++ b/tests/ui/dyn-compatibility/taint-const-eval.rs
@@ -1,16 +1,12 @@
 // Test that we do not attempt to create dyn-incompatible trait objects in const eval.
 
-//@ revisions: curr dyn_compatible_for_dispatch
-
-#![cfg_attr(dyn_compatible_for_dispatch, feature(dyn_compatible_for_dispatch))]
-
 trait Qux {
     fn bar();
 }
 
 static FOO: &(dyn Qux + Sync) = "desc";
 //~^ the trait `Qux` is not dyn compatible
-//[curr]~| the trait `Qux` is not dyn compatible
-//[curr]~| the trait `Qux` is not dyn compatible
+//~| the trait `Qux` is not dyn compatible
+//~| the trait `Qux` is not dyn compatible
 
 fn main() {}
diff --git a/tests/ui/dyn-compatibility/taint-const-eval.stderr b/tests/ui/dyn-compatibility/taint-const-eval.stderr
new file mode 100644
index 00000000000..942c20db6ce
--- /dev/null
+++ b/tests/ui/dyn-compatibility/taint-const-eval.stderr
@@ -0,0 +1,74 @@
+error[E0038]: the trait `Qux` is not dyn compatible
+  --> $DIR/taint-const-eval.rs:7:15
+   |
+LL | static FOO: &(dyn Qux + Sync) = "desc";
+   |               ^^^^^^^^^^^^^^ `Qux` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/taint-const-eval.rs:4:8
+   |
+LL | trait Qux {
+   |       --- this trait is not dyn compatible...
+LL |     fn bar();
+   |        ^^^ ...because associated function `bar` has no `self` parameter
+help: consider turning `bar` into a method by giving it a `&self` argument
+   |
+LL |     fn bar(&self);
+   |            +++++
+help: alternatively, consider constraining `bar` so it does not apply to trait objects
+   |
+LL |     fn bar() where Self: Sized;
+   |              +++++++++++++++++
+
+error[E0038]: the trait `Qux` is not dyn compatible
+  --> $DIR/taint-const-eval.rs:7:33
+   |
+LL | static FOO: &(dyn Qux + Sync) = "desc";
+   |                                 ^^^^^^ `Qux` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/taint-const-eval.rs:4:8
+   |
+LL | trait Qux {
+   |       --- this trait is not dyn compatible...
+LL |     fn bar();
+   |        ^^^ ...because associated function `bar` has no `self` parameter
+   = note: required for the cast from `&'static str` to `&'static (dyn Qux + Sync + 'static)`
+help: consider turning `bar` into a method by giving it a `&self` argument
+   |
+LL |     fn bar(&self);
+   |            +++++
+help: alternatively, consider constraining `bar` so it does not apply to trait objects
+   |
+LL |     fn bar() where Self: Sized;
+   |              +++++++++++++++++
+
+error[E0038]: the trait `Qux` is not dyn compatible
+  --> $DIR/taint-const-eval.rs:7:15
+   |
+LL | static FOO: &(dyn Qux + Sync) = "desc";
+   |               ^^^^^^^^^^^^^^ `Qux` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/taint-const-eval.rs:4:8
+   |
+LL | trait Qux {
+   |       --- this trait is not dyn compatible...
+LL |     fn bar();
+   |        ^^^ ...because associated function `bar` has no `self` parameter
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: consider turning `bar` into a method by giving it a `&self` argument
+   |
+LL |     fn bar(&self);
+   |            +++++
+help: alternatively, consider constraining `bar` so it does not apply to trait objects
+   |
+LL |     fn bar() where Self: Sized;
+   |              +++++++++++++++++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/error-codes/E0084.stderr b/tests/ui/error-codes/E0084.stderr
index f1fbe6c2532..3df2e4a322b 100644
--- a/tests/ui/error-codes/E0084.stderr
+++ b/tests/ui/error-codes/E0084.stderr
@@ -1,8 +1,8 @@
 error[E0084]: unsupported representation for zero-variant enum
-  --> $DIR/E0084.rs:1:1
+  --> $DIR/E0084.rs:1:8
    |
 LL | #[repr(i32)]
-   | ^^^^^^^^^^^^
+   |        ^^^
 LL | enum Foo {}
    | -------- zero-variant enum
 
diff --git a/tests/ui/error-codes/E0094.rs b/tests/ui/error-codes/E0094.rs
index da59d3decac..2067179b26a 100644
--- a/tests/ui/error-codes/E0094.rs
+++ b/tests/ui/error-codes/E0094.rs
@@ -1,10 +1,7 @@
 #![feature(intrinsics)]
 
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-fn size_of<T, U>() -> usize {
-    //~^ ERROR E0094
-    loop {}
-}
+fn size_of<T, U>() -> usize;
+//~^ ERROR E0094
 
 fn main() {}
diff --git a/tests/ui/error-codes/E0094.stderr b/tests/ui/error-codes/E0094.stderr
index e45cc0ea063..da29987f8b1 100644
--- a/tests/ui/error-codes/E0094.stderr
+++ b/tests/ui/error-codes/E0094.stderr
@@ -1,7 +1,7 @@
 error[E0094]: intrinsic has wrong number of type parameters: found 2, expected 1
-  --> $DIR/E0094.rs:5:11
+  --> $DIR/E0094.rs:4:11
    |
-LL | fn size_of<T, U>() -> usize {
+LL | fn size_of<T, U>() -> usize;
    |           ^^^^^^ expected 1 type parameter
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/error-codes/E0308.rs b/tests/ui/error-codes/E0308.rs
index f8f93d49a8e..c27d4245471 100644
--- a/tests/ui/error-codes/E0308.rs
+++ b/tests/ui/error-codes/E0308.rs
@@ -2,10 +2,7 @@
 #![feature(rustc_attrs)]
 
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-fn size_of<T>() {
-    //~^ ERROR E0308
-    loop {}
-}
+fn size_of<T>();
+//~^ ERROR E0308
 
 fn main() {}
diff --git a/tests/ui/error-codes/E0308.stderr b/tests/ui/error-codes/E0308.stderr
index 77e5c06e06a..a1077481a81 100644
--- a/tests/ui/error-codes/E0308.stderr
+++ b/tests/ui/error-codes/E0308.stderr
@@ -1,7 +1,7 @@
 error[E0308]: intrinsic has wrong type
-  --> $DIR/E0308.rs:6:16
+  --> $DIR/E0308.rs:5:16
    |
-LL | fn size_of<T>() {
+LL | fn size_of<T>();
    |                ^ expected `usize`, found `()`
    |
    = note: expected signature `fn() -> usize`
diff --git a/tests/ui/error-codes/E0374.stderr b/tests/ui/error-codes/E0374.stderr
index 71eec4c16fd..95e6b95e0d5 100644
--- a/tests/ui/error-codes/E0374.stderr
+++ b/tests/ui/error-codes/E0374.stderr
@@ -6,7 +6,7 @@ LL | struct Foo<T: ?Sized> {
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
 
-error[E0374]: the trait `CoerceUnsized` may only be implemented for a coercion between structures
+error[E0374]: implementing `CoerceUnsized` requires a field to be coerced
   --> $DIR/E0374.rs:8:1
    |
 LL | / impl<T, U> CoerceUnsized<Foo<U>> for Foo<T>
diff --git a/tests/ui/error-codes/E0375.stderr b/tests/ui/error-codes/E0375.stderr
index af720bd40e7..a797ba9d461 100644
--- a/tests/ui/error-codes/E0375.stderr
+++ b/tests/ui/error-codes/E0375.stderr
@@ -23,14 +23,19 @@ help: the `Box` type always has a statically known size and allocates its conten
 LL |     b: Box<T>,
    |        ++++ +
 
-error[E0375]: implementing the trait `CoerceUnsized` requires multiple coercions
+error[E0375]: implementing `CoerceUnsized` does not allow multiple fields to be coerced
   --> $DIR/E0375.rs:10:12
    |
 LL | impl<T, U> CoerceUnsized<Foo<U, T>> for Foo<T, U> {}
-   |            ^^^^^^^^^^^^^^^^^^^^^^^^ requires multiple coercions
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: `CoerceUnsized` may only be implemented for a coercion between structures with one field being coerced
-   = note: currently, 2 fields need coercions: `b` (`T` to `U`), `c` (`U` to `T`)
+note: the trait `CoerceUnsized` may only be implemented when a single field is being coerced
+  --> $DIR/E0375.rs:6:5
+   |
+LL |     b: T,
+   |     ^^^^
+LL |     c: U,
+   |     ^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/error-codes/E0376.rs b/tests/ui/error-codes/E0376.rs
deleted file mode 100644
index f092eb02c2b..00000000000
--- a/tests/ui/error-codes/E0376.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-#![feature(coerce_unsized)]
-use std::ops::CoerceUnsized;
-
-struct Foo<T: ?Sized> {
-    a: T,
-}
-
-impl<T, U> CoerceUnsized<U> for Foo<T> {} //~ ERROR E0376
-
-fn main() {}
diff --git a/tests/ui/error-codes/E0376.stderr b/tests/ui/error-codes/E0376.stderr
deleted file mode 100644
index 46668e05a42..00000000000
--- a/tests/ui/error-codes/E0376.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0376]: the trait `CoerceUnsized` may only be implemented for a coercion between structures
-  --> $DIR/E0376.rs:8:1
-   |
-LL | impl<T, U> CoerceUnsized<U> for Foo<T> {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0376`.
diff --git a/tests/ui/error-codes/E0565.stderr b/tests/ui/error-codes/E0565.stderr
index 68f4a37dcff..6e56600133d 100644
--- a/tests/ui/error-codes/E0565.stderr
+++ b/tests/ui/error-codes/E0565.stderr
@@ -1,8 +1,8 @@
 error[E0565]: meta item in `repr` must be an identifier
-  --> $DIR/E0565.rs:2:8
+  --> $DIR/E0565.rs:2:1
    |
 LL | #[repr("C")]
-   |        ^^^
+   | ^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/error-codes/E0789.rs b/tests/ui/error-codes/E0789.rs
index 08471e1b3f3..4a55e174315 100644
--- a/tests/ui/error-codes/E0789.rs
+++ b/tests/ui/error-codes/E0789.rs
@@ -8,5 +8,3 @@
 // #[stable(feature = "foo", since = "1.0")]
 struct Foo;
 //~^ ERROR `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute
-//~^^ ERROR `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute
-// FIXME: we shouldn't have two errors here, only occurs when using `-Zdeduplicate-diagnostics=no`
diff --git a/tests/ui/error-codes/E0789.stderr b/tests/ui/error-codes/E0789.stderr
index 6df9daafec7..23631ee1b03 100644
--- a/tests/ui/error-codes/E0789.stderr
+++ b/tests/ui/error-codes/E0789.stderr
@@ -4,14 +4,6 @@ error[E0789]: `rustc_allowed_through_unstable_modules` attribute must be paired
 LL | struct Foo;
    | ^^^^^^^^^^^
 
-error[E0789]: `rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute
-  --> $DIR/E0789.rs:9:1
-   |
-LL | struct Foo;
-   | ^^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
 For more information about this error, try `rustc --explain E0789`.
diff --git a/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.rs b/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.rs
index 8b13f1bf278..81b7fe3db2b 100644
--- a/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.rs
+++ b/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.rs
@@ -1,7 +1,9 @@
 // checks that this attribute is caught on non-macro items.
 // this needs a different test since this is done after expansion
 
-#[allow_internal_unstable()] //~ ERROR allow_internal_unstable side-steps
+// FIXME(jdonszelmann): empty attributes are currently ignored, since when its empty no actual
+// change is applied. This should be fixed when later moving this check to attribute parsing.
+#[allow_internal_unstable(something)] //~ ERROR allow_internal_unstable side-steps
 //~| ERROR attribute should
 struct S;
 
diff --git a/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr b/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr
index 28f1a0d6ed5..076f2df28e3 100644
--- a/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr
+++ b/tests/ui/feature-gates/feature-gate-allow-internal-unstable-struct.stderr
@@ -1,17 +1,17 @@
 error[E0658]: allow_internal_unstable side-steps feature gating and stability checks
-  --> $DIR/feature-gate-allow-internal-unstable-struct.rs:4:1
+  --> $DIR/feature-gate-allow-internal-unstable-struct.rs:6:1
    |
-LL | #[allow_internal_unstable()]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[allow_internal_unstable(something)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: add `#![feature(allow_internal_unstable)]` 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: attribute should be applied to a macro
-  --> $DIR/feature-gate-allow-internal-unstable-struct.rs:4:1
+  --> $DIR/feature-gate-allow-internal-unstable-struct.rs:6:1
    |
-LL | #[allow_internal_unstable()]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | #[allow_internal_unstable(something)]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 LL |
 LL | struct S;
    | --------- not a macro
diff --git a/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.rs b/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.rs
deleted file mode 100644
index e38ab66dbe5..00000000000
--- a/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-// Test that the use of the dyn-incompatible trait objects
-// are gated by the `dyn_compatible_for_dispatch` feature gate.
-
-trait DynIncompatible1: Sized {}
-
-trait DynIncompatible2 {
-    fn static_fn() {}
-}
-
-trait DynIncompatible3 {
-    fn foo<T>(&self);
-}
-
-trait DynIncompatible4 {
-    fn foo(&self, s: &Self);
-}
-
-fn takes_dyn_incompatible_ref<T>(obj: &dyn DynIncompatible1) {
-    //~^ ERROR E0038
-}
-
-fn return_dyn_incompatible_ref() -> &'static dyn DynIncompatible2 {
-    //~^ ERROR E0038
-    loop {}
-}
-
-fn takes_dyn_incompatible_box(obj: Box<dyn DynIncompatible3>) {
-    //~^ ERROR E0038
-}
-
-fn return_dyn_incompatible_rc() -> std::rc::Rc<dyn DynIncompatible4> {
-    //~^ ERROR E0038
-    loop {}
-}
-
-trait Trait {}
-
-impl Trait for dyn DynIncompatible1 {}
-//~^ ERROR E0038
-
-fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr b/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr
deleted file mode 100644
index 2c3edd6e6a5..00000000000
--- a/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr
+++ /dev/null
@@ -1,88 +0,0 @@
-error[E0038]: the trait `DynIncompatible1` is not dyn compatible
-  --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:18:40
-   |
-LL | fn takes_dyn_incompatible_ref<T>(obj: &dyn DynIncompatible1) {
-   |                                        ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible1` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:4:25
-   |
-LL | trait DynIncompatible1: Sized {}
-   |       ----------------  ^^^^^ ...because it requires `Self: Sized`
-   |       |
-   |       this trait is not dyn compatible...
-
-error[E0038]: the trait `DynIncompatible2` is not dyn compatible
-  --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:22:46
-   |
-LL | fn return_dyn_incompatible_ref() -> &'static dyn DynIncompatible2 {
-   |                                              ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible2` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:7:8
-   |
-LL | trait DynIncompatible2 {
-   |       ---------------- this trait is not dyn compatible...
-LL |     fn static_fn() {}
-   |        ^^^^^^^^^ ...because associated function `static_fn` has no `self` parameter
-help: consider turning `static_fn` into a method by giving it a `&self` argument
-   |
-LL |     fn static_fn(&self) {}
-   |                  +++++
-help: alternatively, consider constraining `static_fn` so it does not apply to trait objects
-   |
-LL |     fn static_fn() where Self: Sized {}
-   |                    +++++++++++++++++
-
-error[E0038]: the trait `DynIncompatible3` is not dyn compatible
-  --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:27:40
-   |
-LL | fn takes_dyn_incompatible_box(obj: Box<dyn DynIncompatible3>) {
-   |                                        ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible3` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:11:8
-   |
-LL | trait DynIncompatible3 {
-   |       ---------------- this trait is not dyn compatible...
-LL |     fn foo<T>(&self);
-   |        ^^^ ...because method `foo` has generic type parameters
-   = help: consider moving `foo` to another trait
-
-error[E0038]: the trait `DynIncompatible4` is not dyn compatible
-  --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:31:48
-   |
-LL | fn return_dyn_incompatible_rc() -> std::rc::Rc<dyn DynIncompatible4> {
-   |                                                ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible4` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:15:22
-   |
-LL | trait DynIncompatible4 {
-   |       ---------------- this trait is not dyn compatible...
-LL |     fn foo(&self, s: &Self);
-   |                      ^^^^^ ...because method `foo` references the `Self` type in this parameter
-   = help: consider moving `foo` to another trait
-
-error[E0038]: the trait `DynIncompatible1` is not dyn compatible
-  --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:38:16
-   |
-LL | impl Trait for dyn DynIncompatible1 {}
-   |                ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible1` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:4:25
-   |
-LL | trait DynIncompatible1: Sized {}
-   |       ----------------  ^^^^^ ...because it requires `Self: Sized`
-   |       |
-   |       this trait is not dyn compatible...
-
-error: aborting due to 5 previous errors
-
-For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/feature-gates/feature-gate-fn_align.rs b/tests/ui/feature-gates/feature-gate-fn_align.rs
index 06784a45d76..744877704dd 100644
--- a/tests/ui/feature-gates/feature-gate-fn_align.rs
+++ b/tests/ui/feature-gates/feature-gate-fn_align.rs
@@ -4,6 +4,6 @@
 fn requires_alignment() {}
 
 trait MyTrait {
-    #[repr(align)] //~ ERROR `repr(align)` attributes on functions are unstable
+    #[repr(align)] //~ ERROR invalid `repr(align)` attribute: `align` needs an argument
     fn myfun();
 }
diff --git a/tests/ui/feature-gates/feature-gate-fn_align.stderr b/tests/ui/feature-gates/feature-gate-fn_align.stderr
index cd9900c6051..ff17c29fe02 100644
--- a/tests/ui/feature-gates/feature-gate-fn_align.stderr
+++ b/tests/ui/feature-gates/feature-gate-fn_align.stderr
@@ -1,3 +1,9 @@
+error[E0589]: invalid `repr(align)` attribute: `align` needs an argument
+  --> $DIR/feature-gate-fn_align.rs:7:12
+   |
+LL |     #[repr(align)]
+   |            ^^^^^ help: supply an argument here: `align(...)`
+
 error[E0658]: `repr(align)` attributes on functions are unstable
   --> $DIR/feature-gate-fn_align.rs:3:8
    |
@@ -8,16 +14,7 @@ LL | #[repr(align(16))]
    = help: add `#![feature(fn_align)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0658]: `repr(align)` attributes on functions are unstable
-  --> $DIR/feature-gate-fn_align.rs:7:12
-   |
-LL |     #[repr(align)]
-   |            ^^^^^
-   |
-   = note: see issue #82232 <https://github.com/rust-lang/rust/issues/82232> for more information
-   = help: add `#![feature(fn_align)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0658`.
+Some errors have detailed explanations: E0589, E0658.
+For more information about an error, try `rustc --explain E0589`.
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 648bafe6460..5c2a3ae699c 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
@@ -130,21 +130,6 @@ LL - #![rustc_main]
 LL + #[rustc_main]
    |
 
-error: `repr` attribute cannot be used at crate level
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:17:1
-   |
-LL | #![repr()]
-   | ^^^^^^^^^^
-...
-LL | mod inline {
-   |     ------ the inner attribute doesn't annotate this module
-   |
-help: perhaps you meant to use an outer attribute
-   |
-LL - #![repr()]
-LL + #[repr()]
-   |
-
 error: `path` attribute cannot be used at crate level
   --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1
    |
@@ -175,6 +160,21 @@ LL - #![automatically_derived]
 LL + #[automatically_derived]
    |
 
+error: `repr` attribute cannot be used at crate level
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:17:1
+   |
+LL | #![repr()]
+   | ^^^^^^^^^^
+...
+LL | mod inline {
+   |     ------ the inner attribute doesn't annotate this module
+   |
+help: perhaps you meant to use an outer attribute
+   |
+LL - #![repr()]
+LL + #[repr()]
+   |
+
 error[E0518]: attribute should be applied to function or closure
   --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:40:17
    |
diff --git a/tests/ui/internal/internal-unstable.rs b/tests/ui/internal/internal-unstable.rs
index 35a2941633a..381c1337148 100644
--- a/tests/ui/internal/internal-unstable.rs
+++ b/tests/ui/internal/internal-unstable.rs
@@ -7,7 +7,7 @@
 extern crate internal_unstable;
 
 struct Baz {
-    #[allow_internal_unstable]
+    #[allow_internal_unstable] //~ ERROR `allow_internal_unstable` expects a list of feature names
     baz: u8,
 }
 
@@ -56,7 +56,7 @@ fn main() {
     bar!(internal_unstable::unstable()); //~ ERROR use of unstable
 
     match true {
-        #[allow_internal_unstable]
+        #[allow_internal_unstable] //~ ERROR `allow_internal_unstable` expects a list of feature names
         _ => {}
     }
 
diff --git a/tests/ui/internal/internal-unstable.stderr b/tests/ui/internal/internal-unstable.stderr
index ea74175f09b..bbf589d3f92 100644
--- a/tests/ui/internal/internal-unstable.stderr
+++ b/tests/ui/internal/internal-unstable.stderr
@@ -1,3 +1,15 @@
+error: `allow_internal_unstable` expects a list of feature names
+  --> $DIR/internal-unstable.rs:10:5
+   |
+LL |     #[allow_internal_unstable]
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: `allow_internal_unstable` expects a list of feature names
+  --> $DIR/internal-unstable.rs:59:9
+   |
+LL |         #[allow_internal_unstable]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0658]: use of unstable library feature `function`
   --> $DIR/internal-unstable.rs:48:25
    |
@@ -47,6 +59,6 @@ LL |     bar!(internal_unstable::unstable());
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
    = note: this error originates in the macro `foo` which comes from the expansion of the macro `bar` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 5 previous errors
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/intrinsics/always-gets-overridden.rs b/tests/ui/intrinsics/always-gets-overridden.rs
index 2fb64f96d83..aaac5415c21 100644
--- a/tests/ui/intrinsics/always-gets-overridden.rs
+++ b/tests/ui/intrinsics/always-gets-overridden.rs
@@ -1,5 +1,5 @@
-//! Check that `vtable_size` gets overridden by llvm backend even if there is no
-//! `rustc_intrinsic_must_be_overridden` attribute on this usage.
+//! Check that `vtable_size` gets overridden by llvm backend even if there is a
+//! fallback body.
 #![feature(intrinsics)]
 //@run-pass
 
diff --git a/tests/ui/invalid_dispatch_from_dyn_impls.rs b/tests/ui/invalid_dispatch_from_dyn_impls.rs
index b7bc766fbe0..972465d7197 100644
--- a/tests/ui/invalid_dispatch_from_dyn_impls.rs
+++ b/tests/ui/invalid_dispatch_from_dyn_impls.rs
@@ -8,9 +8,10 @@ use std::{
 struct WrapperWithExtraField<T>(T, i32);
 
 impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T>
+//~^ ERROR [E0378]
 where
     T: DispatchFromDyn<U>,
-{} //~^^^ ERROR [E0378]
+{}
 
 
 struct MultiplePointers<T: ?Sized>{
@@ -19,9 +20,10 @@ struct MultiplePointers<T: ?Sized>{
 }
 
 impl<T: ?Sized, U: ?Sized> DispatchFromDyn<MultiplePointers<U>> for MultiplePointers<T>
+//~^ implementing `DispatchFromDyn` does not allow multiple fields to be coerced
 where
     T: Unsize<U>,
-{} //~^^^ ERROR [E0378]
+{}
 
 
 struct NothingToCoerce<T: ?Sized> {
@@ -29,23 +31,25 @@ struct NothingToCoerce<T: ?Sized> {
 }
 
 impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NothingToCoerce<T>> for NothingToCoerce<U> {}
-//~^ ERROR [E0378]
+//~^ ERROR implementing `DispatchFromDyn` requires a field to be coerced
 
 #[repr(C)]
 struct HasReprC<T: ?Sized>(Box<T>);
 
 impl<T: ?Sized, U: ?Sized> DispatchFromDyn<HasReprC<U>> for HasReprC<T>
+//~^ ERROR [E0378]
 where
     T: Unsize<U>,
-{} //~^^^ ERROR [E0378]
+{}
 
 #[repr(align(64))]
 struct OverAlignedZst;
 struct OverAligned<T: ?Sized>(Box<T>, OverAlignedZst);
 
 impl<T: ?Sized, U: ?Sized> DispatchFromDyn<OverAligned<U>> for OverAligned<T>
+//~^ ERROR [E0378]
     where
         T: Unsize<U>,
-{} //~^^^ ERROR [E0378]
+{}
 
 fn main() {}
diff --git a/tests/ui/invalid_dispatch_from_dyn_impls.stderr b/tests/ui/invalid_dispatch_from_dyn_impls.stderr
index 02718334c73..93ec6bbe089 100644
--- a/tests/ui/invalid_dispatch_from_dyn_impls.stderr
+++ b/tests/ui/invalid_dispatch_from_dyn_impls.stderr
@@ -2,25 +2,32 @@ error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs co
   --> $DIR/invalid_dispatch_from_dyn_impls.rs:10:1
    |
 LL | / impl<T, U> DispatchFromDyn<WrapperWithExtraField<U>> for WrapperWithExtraField<T>
+LL | |
 LL | | where
 LL | |     T: DispatchFromDyn<U>,
    | |__________________________^
    |
    = note: extra field `1` of type `i32` is not allowed
 
-error[E0378]: implementing the `DispatchFromDyn` trait requires multiple coercions
-  --> $DIR/invalid_dispatch_from_dyn_impls.rs:21:1
+error[E0375]: implementing `DispatchFromDyn` does not allow multiple fields to be coerced
+  --> $DIR/invalid_dispatch_from_dyn_impls.rs:22:1
    |
 LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<MultiplePointers<U>> for MultiplePointers<T>
+LL | |
 LL | | where
 LL | |     T: Unsize<U>,
    | |_________________^
    |
-   = note: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced
-   = note: currently, 2 fields need coercions: `ptr1` (`*const T` to `*const U`), `ptr2` (`*const T` to `*const U`)
+note: the trait `DispatchFromDyn` may only be implemented when a single field is being coerced
+  --> $DIR/invalid_dispatch_from_dyn_impls.rs:18:5
+   |
+LL |     ptr1: *const T,
+   |     ^^^^^^^^^^^^^^
+LL |     ptr2: *const T,
+   |     ^^^^^^^^^^^^^^
 
-error[E0378]: the trait `DispatchFromDyn` may only be implemented for a coercion between structures
-  --> $DIR/invalid_dispatch_from_dyn_impls.rs:31:1
+error[E0374]: implementing `DispatchFromDyn` requires a field to be coerced
+  --> $DIR/invalid_dispatch_from_dyn_impls.rs:33:1
    |
 LL | impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NothingToCoerce<T>> for NothingToCoerce<U> {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -28,17 +35,19 @@ LL | impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NothingToCoerce<T>> for NothingT
    = note: expected a single field to be coerced, none found
 
 error[E0378]: structs implementing `DispatchFromDyn` may not have `#[repr(packed)]` or `#[repr(C)]`
-  --> $DIR/invalid_dispatch_from_dyn_impls.rs:37:1
+  --> $DIR/invalid_dispatch_from_dyn_impls.rs:39:1
    |
 LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<HasReprC<U>> for HasReprC<T>
+LL | |
 LL | | where
 LL | |     T: Unsize<U>,
    | |_________________^
 
 error[E0378]: the trait `DispatchFromDyn` may only be implemented for structs containing the field being coerced, ZST fields with 1 byte alignment that don't mention type/const generics, and nothing else
-  --> $DIR/invalid_dispatch_from_dyn_impls.rs:46:1
+  --> $DIR/invalid_dispatch_from_dyn_impls.rs:49:1
    |
 LL | / impl<T: ?Sized, U: ?Sized> DispatchFromDyn<OverAligned<U>> for OverAligned<T>
+LL | |
 LL | |     where
 LL | |         T: Unsize<U>,
    | |_____________________^
@@ -47,4 +56,5 @@ LL | |         T: Unsize<U>,
 
 error: aborting due to 5 previous errors
 
-For more information about this error, try `rustc --explain E0378`.
+Some errors have detailed explanations: E0374, E0375, E0378.
+For more information about an error, try `rustc --explain E0374`.
diff --git a/tests/ui/issues/issue-43988.stderr b/tests/ui/issues/issue-43988.stderr
index 7bbb8ed2ca9..d629f199b22 100644
--- a/tests/ui/issues/issue-43988.stderr
+++ b/tests/ui/issues/issue-43988.stderr
@@ -10,22 +10,6 @@ error: malformed `repr` attribute input
 LL |     let _z = #[repr] 1;
    |              ^^^^^^^ help: must be of the form: `#[repr(C)]`
 
-error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43988.rs:5:5
-   |
-LL |     #[inline]
-   |     ^^^^^^^^^
-LL |     let _a = 4;
-   |     ----------- not a function or closure
-
-error[E0518]: attribute should be applied to function or closure
-  --> $DIR/issue-43988.rs:10:5
-   |
-LL |     #[inline(XYZ)]
-   |     ^^^^^^^^^^^^^^
-LL |     let _b = 4;
-   |     ----------- not a function or closure
-
 error[E0552]: unrecognized representation hint
   --> $DIR/issue-43988.rs:14:12
    |
@@ -43,6 +27,22 @@ 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`
 
 error[E0518]: attribute should be applied to function or closure
+  --> $DIR/issue-43988.rs:5:5
+   |
+LL |     #[inline]
+   |     ^^^^^^^^^
+LL |     let _a = 4;
+   |     ----------- not a function or closure
+
+error[E0518]: attribute should be applied to function or closure
+  --> $DIR/issue-43988.rs:10:5
+   |
+LL |     #[inline(XYZ)]
+   |     ^^^^^^^^^^^^^^
+LL |     let _b = 4;
+   |     ----------- not a function or closure
+
+error[E0518]: attribute should be applied to function or closure
   --> $DIR/issue-43988.rs:30:5
    |
 LL |     #[inline(ABC)]
diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.rs b/tests/ui/kindck/kindck-inherited-copy-bound.rs
index dda95229ddf..20d54a3fb10 100644
--- a/tests/ui/kindck/kindck-inherited-copy-bound.rs
+++ b/tests/ui/kindck/kindck-inherited-copy-bound.rs
@@ -1,8 +1,4 @@
 // Test that Copy bounds inherited by trait are checked.
-//
-//@ revisions: curr dyn_compatible_for_dispatch
-
-#![cfg_attr(dyn_compatible_for_dispatch, feature(dyn_compatible_for_dispatch))]
 
 
 use std::any::Any;
@@ -18,17 +14,15 @@ fn take_param<T:Foo>(foo: &T) { }
 
 fn a() {
     let x: Box<_> = Box::new(3);
-    take_param(&x); //[curr]~ ERROR E0277
-    //[dyn_compatible_for_dispatch]~^ ERROR E0277
+    take_param(&x); //~ ERROR E0277
 }
 
 fn b() {
     let x: Box<_> = Box::new(3);
     let y = &x;
     let z = &x as &dyn Foo;
-    //[curr]~^ ERROR E0038
-    //[curr]~| ERROR E0038
-    //[dyn_compatible_for_dispatch]~^^^ ERROR E0038
+    //~^ ERROR E0038
+    //~| ERROR E0038
 }
 
 fn main() { }
diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.stderr
index 296f011193e..edfa7ae7769 100644
--- a/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr
+++ b/tests/ui/kindck/kindck-inherited-copy-bound.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied
-  --> $DIR/kindck-inherited-copy-bound.rs:21:16
+  --> $DIR/kindck-inherited-copy-bound.rs:17:16
    |
 LL |     take_param(&x);
    |     ---------- ^^ the trait `Copy` is not implemented for `Box<{integer}>`
@@ -7,35 +7,50 @@ LL |     take_param(&x);
    |     required by a bound introduced by this call
    |
 note: required for `Box<{integer}>` to implement `Foo`
-  --> $DIR/kindck-inherited-copy-bound.rs:14:14
+  --> $DIR/kindck-inherited-copy-bound.rs:10:14
    |
 LL | impl<T:Copy> Foo for T {
    |        ----  ^^^     ^
    |        |
    |        unsatisfied trait bound introduced here
 note: required by a bound in `take_param`
-  --> $DIR/kindck-inherited-copy-bound.rs:17:17
+  --> $DIR/kindck-inherited-copy-bound.rs:13:17
    |
 LL | fn take_param<T:Foo>(foo: &T) { }
    |                 ^^^ required by this bound in `take_param`
 
 error[E0038]: the trait `Foo` is not dyn compatible
-  --> $DIR/kindck-inherited-copy-bound.rs:28:13
+  --> $DIR/kindck-inherited-copy-bound.rs:23:19
+   |
+LL |     let z = &x as &dyn Foo;
+   |                   ^^^^^^^^ `Foo` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/kindck-inherited-copy-bound.rs:6:13
+   |
+LL | trait Foo : Copy {
+   |       ---   ^^^^ ...because it requires `Self: Sized`
+   |       |
+   |       this trait is not dyn compatible...
+
+error[E0038]: the trait `Foo` is not dyn compatible
+  --> $DIR/kindck-inherited-copy-bound.rs:23:13
    |
 LL |     let z = &x as &dyn Foo;
    |             ^^ `Foo` is not dyn compatible
    |
 note: for a trait to be dyn compatible it needs to allow building a vtable
       for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/kindck-inherited-copy-bound.rs:10:13
+  --> $DIR/kindck-inherited-copy-bound.rs:6:13
    |
 LL | trait Foo : Copy {
    |       ---   ^^^^ ...because it requires `Self: Sized`
    |       |
    |       this trait is not dyn compatible...
-   = note: required for the cast from `&Box<i32>` to `&dyn Foo`
+   = note: required for the cast from `&Box<{integer}>` to `&dyn Foo`
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0038, E0277.
 For more information about an error, try `rustc --explain E0038`.
diff --git a/tests/ui/repr/16-bit-repr-c-enum.rs b/tests/ui/repr/16-bit-repr-c-enum.rs
index 011076882d2..8c2d2fafce0 100644
--- a/tests/ui/repr/16-bit-repr-c-enum.rs
+++ b/tests/ui/repr/16-bit-repr-c-enum.rs
@@ -24,10 +24,7 @@ enum Foo {
 #[stable(feature = "intrinsics_for_test", since = "3.3.3")]
 #[rustc_const_stable(feature = "intrinsics_for_test", since = "3.3.3")]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-const fn size_of<T>() -> usize {
-    loop {}
-}
+const fn size_of<T>() -> usize;
 
 #[lang="sized"]
 trait Sized {}
diff --git a/tests/ui/repr/invalid_repr_list_help.stderr b/tests/ui/repr/invalid_repr_list_help.stderr
index e87cbd37a99..763ad9c2795 100644
--- a/tests/ui/repr/invalid_repr_list_help.stderr
+++ b/tests/ui/repr/invalid_repr_list_help.stderr
@@ -30,14 +30,6 @@ 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`
 
-error: unknown `doc` attribute `owo`
-  --> $DIR/invalid_repr_list_help.rs:20:7
-   |
-LL | #[doc(owo)]
-   |       ^^^
-   |
-   = note: `#[deny(invalid_doc_attributes)]` on by default
-
 error[E0552]: unrecognized representation hint
   --> $DIR/invalid_repr_list_help.rs:19:8
    |
@@ -46,6 +38,14 @@ 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`
 
+error: unknown `doc` attribute `owo`
+  --> $DIR/invalid_repr_list_help.rs:20:7
+   |
+LL | #[doc(owo)]
+   |       ^^^
+   |
+   = note: `#[deny(invalid_doc_attributes)]` on by default
+
 error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0552`.
diff --git a/tests/ui/repr/issue-83505-repr-simd.stderr b/tests/ui/repr/issue-83505-repr-simd.stderr
index 44e154b4bb6..57cfbeb95de 100644
--- a/tests/ui/repr/issue-83505-repr-simd.stderr
+++ b/tests/ui/repr/issue-83505-repr-simd.stderr
@@ -26,10 +26,10 @@ LL | enum Es {}
    | ---------- not a struct
 
 error[E0084]: unsupported representation for zero-variant enum
-  --> $DIR/issue-83505-repr-simd.rs:5:1
+  --> $DIR/issue-83505-repr-simd.rs:5:8
    |
 LL | #[repr(simd)]
-   | ^^^^^^^^^^^^^
+   |        ^^^^
 ...
 LL | enum Es {}
    | ------- zero-variant enum
diff --git a/tests/ui/repr/malformed-repr-hints.stderr b/tests/ui/repr/malformed-repr-hints.stderr
index 6fb92755761..7a6e9ccc73e 100644
--- a/tests/ui/repr/malformed-repr-hints.stderr
+++ b/tests/ui/repr/malformed-repr-hints.stderr
@@ -1,15 +1,3 @@
-error[E0552]: incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all
-  --> $DIR/malformed-repr-hints.rs:6:8
-   |
-LL | #[repr(packed())]
-   |        ^^^^^^^^
-
-error[E0589]: invalid `repr(align)` attribute: `align` needs an argument
-  --> $DIR/malformed-repr-hints.rs:10:8
-   |
-LL | #[repr(align)]
-   |        ^^^^^ help: supply an argument here: `align(...)`
-
 error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
   --> $DIR/malformed-repr-hints.rs:14:8
    |
@@ -22,6 +10,18 @@ error[E0693]: incorrect `repr(align)` attribute format: `align` takes exactly on
 LL | #[repr(align())]
    |        ^^^^^^^
 
+error[E0552]: incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all
+  --> $DIR/malformed-repr-hints.rs:6:8
+   |
+LL | #[repr(packed())]
+   |        ^^^^^^^^
+
+error[E0589]: invalid `repr(align)` attribute: `align` needs an argument
+  --> $DIR/malformed-repr-hints.rs:10:8
+   |
+LL | #[repr(align)]
+   |        ^^^^^ help: supply an argument here: `align(...)`
+
 error[E0552]: invalid representation hint: `Rust` does not take a parenthesized argument list
   --> $DIR/malformed-repr-hints.rs:23:8
    |
diff --git a/tests/ui/repr/repr-align-assign.fixed b/tests/ui/repr/repr-align-assign.fixed
index d40fcadf57b..96f9866611b 100644
--- a/tests/ui/repr/repr-align-assign.fixed
+++ b/tests/ui/repr/repr-align-assign.fixed
@@ -3,11 +3,9 @@
 #![allow(dead_code)]
 
 #[repr(align(8))] //~ ERROR incorrect `repr(align)` attribute format
-                 //~| ERROR incorrect `repr(align)` attribute format
 struct A(u64);
 
 #[repr(align(8))] //~ ERROR incorrect `repr(align)` attribute format
-                   //~| ERROR incorrect `repr(align)` attribute format
 struct B(u64);
 
 fn main() {}
diff --git a/tests/ui/repr/repr-align-assign.rs b/tests/ui/repr/repr-align-assign.rs
index 3aff84a91f7..0b30ee65664 100644
--- a/tests/ui/repr/repr-align-assign.rs
+++ b/tests/ui/repr/repr-align-assign.rs
@@ -3,11 +3,9 @@
 #![allow(dead_code)]
 
 #[repr(align=8)] //~ ERROR incorrect `repr(align)` attribute format
-                 //~| ERROR incorrect `repr(align)` attribute format
 struct A(u64);
 
 #[repr(align="8")] //~ ERROR incorrect `repr(align)` attribute format
-                   //~| ERROR incorrect `repr(align)` attribute format
 struct B(u64);
 
 fn main() {}
diff --git a/tests/ui/repr/repr-align-assign.stderr b/tests/ui/repr/repr-align-assign.stderr
index 3606d02210b..cc046e04de5 100644
--- a/tests/ui/repr/repr-align-assign.stderr
+++ b/tests/ui/repr/repr-align-assign.stderr
@@ -5,27 +5,11 @@ LL | #[repr(align=8)]
    |        ^^^^^^^ help: use parentheses instead: `align(8)`
 
 error[E0693]: incorrect `repr(align)` attribute format
-  --> $DIR/repr-align-assign.rs:9:8
+  --> $DIR/repr-align-assign.rs:8:8
    |
 LL | #[repr(align="8")]
    |        ^^^^^^^^^ help: use parentheses instead: `align(8)`
 
-error[E0693]: incorrect `repr(align)` attribute format
-  --> $DIR/repr-align-assign.rs:5:8
-   |
-LL | #[repr(align=8)]
-   |        ^^^^^^^ help: use parentheses instead: `align(8)`
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0693]: incorrect `repr(align)` attribute format
-  --> $DIR/repr-align-assign.rs:9:8
-   |
-LL | #[repr(align="8")]
-   |        ^^^^^^^^^ help: use parentheses instead: `align(8)`
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 4 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0693`.
diff --git a/tests/ui/repr/repr-align.rs b/tests/ui/repr/repr-align.rs
index 33aa727d4bd..6b60a765461 100644
--- a/tests/ui/repr/repr-align.rs
+++ b/tests/ui/repr/repr-align.rs
@@ -1,41 +1,33 @@
 #![allow(dead_code)]
 
 #[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer
-                     //~| ERROR: invalid `repr(align)` attribute: not an unsuffixed integer
 struct S0(i32);
 
 #[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two
-                   //~| ERROR: invalid `repr(align)` attribute: not a power of two
 struct S1(i32);
 
 #[repr(align(4294967296))] //~ ERROR: invalid `repr(align)` attribute: larger than 2^29
-                           //~| ERROR: invalid `repr(align)` attribute: larger than 2^29
 struct S2(i32);
 
 #[repr(align(536870912))] // ok: this is the largest accepted alignment
 struct S3(i32);
 
 #[repr(align(0))] //~ ERROR: invalid `repr(align)` attribute: not a power of two
-                  //~| ERROR: invalid `repr(align)` attribute: not a power of two
 struct S4(i32);
 
 #[repr(align(16.0))] //~ ERROR: invalid `repr(align)` attribute: not an unsuffixed integer
-                     //~| ERROR: invalid `repr(align)` attribute: not an unsuffixed integer
 enum E0 { A, B }
 
 #[repr(align(15))] //~ ERROR: invalid `repr(align)` attribute: not a power of two
-                   //~| ERROR: invalid `repr(align)` attribute: not a power of two
 enum E1 { A, B }
 
 #[repr(align(4294967296))] //~ ERROR: invalid `repr(align)` attribute: larger than 2^29
-                           //~| ERROR: invalid `repr(align)` attribute: larger than 2^29
 enum E2 { A, B }
 
 #[repr(align(536870912))] // ok: this is the largest accepted alignment
 enum E3 { A, B }
 
 #[repr(align(0))] //~ ERROR: invalid `repr(align)` attribute: not a power of two
-                  //~| ERROR: invalid `repr(align)` attribute: not a power of two
 enum E4 { A, B }
 
 fn main() {}
diff --git a/tests/ui/repr/repr-align.stderr b/tests/ui/repr/repr-align.stderr
index 660247840c4..fe919e30b15 100644
--- a/tests/ui/repr/repr-align.stderr
+++ b/tests/ui/repr/repr-align.stderr
@@ -5,111 +5,47 @@ LL | #[repr(align(16.0))]
    |              ^^^^
 
 error[E0589]: invalid `repr(align)` attribute: not a power of two
-  --> $DIR/repr-align.rs:7:14
+  --> $DIR/repr-align.rs:6:14
    |
 LL | #[repr(align(15))]
    |              ^^
 
 error[E0589]: invalid `repr(align)` attribute: larger than 2^29
-  --> $DIR/repr-align.rs:11:14
+  --> $DIR/repr-align.rs:9:14
    |
 LL | #[repr(align(4294967296))]
    |              ^^^^^^^^^^
 
 error[E0589]: invalid `repr(align)` attribute: not a power of two
-  --> $DIR/repr-align.rs:18:14
+  --> $DIR/repr-align.rs:15:14
    |
 LL | #[repr(align(0))]
    |              ^
 
 error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer
-  --> $DIR/repr-align.rs:22:14
-   |
-LL | #[repr(align(16.0))]
-   |              ^^^^
-
-error[E0589]: invalid `repr(align)` attribute: not a power of two
-  --> $DIR/repr-align.rs:26:14
-   |
-LL | #[repr(align(15))]
-   |              ^^
-
-error[E0589]: invalid `repr(align)` attribute: larger than 2^29
-  --> $DIR/repr-align.rs:30:14
-   |
-LL | #[repr(align(4294967296))]
-   |              ^^^^^^^^^^
-
-error[E0589]: invalid `repr(align)` attribute: not a power of two
-  --> $DIR/repr-align.rs:37:14
-   |
-LL | #[repr(align(0))]
-   |              ^
-
-error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer
-  --> $DIR/repr-align.rs:3:14
-   |
-LL | #[repr(align(16.0))]
-   |              ^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0589]: invalid `repr(align)` attribute: not a power of two
-  --> $DIR/repr-align.rs:7:14
-   |
-LL | #[repr(align(15))]
-   |              ^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0589]: invalid `repr(align)` attribute: larger than 2^29
-  --> $DIR/repr-align.rs:11:14
-   |
-LL | #[repr(align(4294967296))]
-   |              ^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0589]: invalid `repr(align)` attribute: not a power of two
   --> $DIR/repr-align.rs:18:14
    |
-LL | #[repr(align(0))]
-   |              ^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0589]: invalid `repr(align)` attribute: not an unsuffixed integer
-  --> $DIR/repr-align.rs:22:14
-   |
 LL | #[repr(align(16.0))]
    |              ^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0589]: invalid `repr(align)` attribute: not a power of two
-  --> $DIR/repr-align.rs:26:14
+  --> $DIR/repr-align.rs:21:14
    |
 LL | #[repr(align(15))]
    |              ^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0589]: invalid `repr(align)` attribute: larger than 2^29
-  --> $DIR/repr-align.rs:30:14
+  --> $DIR/repr-align.rs:24:14
    |
 LL | #[repr(align(4294967296))]
    |              ^^^^^^^^^^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0589]: invalid `repr(align)` attribute: not a power of two
-  --> $DIR/repr-align.rs:37:14
+  --> $DIR/repr-align.rs:30:14
    |
 LL | #[repr(align(0))]
    |              ^
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: aborting due to 16 previous errors
+error: aborting due to 8 previous errors
 
 For more information about this error, try `rustc --explain E0589`.
diff --git a/tests/ui/repr/repr-transparent.stderr b/tests/ui/repr/repr-transparent.stderr
index d0c78a8418a..2cafb989bce 100644
--- a/tests/ui/repr/repr-transparent.stderr
+++ b/tests/ui/repr/repr-transparent.stderr
@@ -35,10 +35,10 @@ LL | struct GenericAlign<T>(ZstAlign32<T>, u32);
    | needs at most one field with non-trivial size or alignment, but has 2
 
 error[E0084]: unsupported representation for zero-variant enum
-  --> $DIR/repr-transparent.rs:47:1
+  --> $DIR/repr-transparent.rs:47:8
    |
 LL | #[repr(transparent)]
-   | ^^^^^^^^^^^^^^^^^^^^
+   |        ^^^^^^^^^^^
 LL | enum Void {}
    | --------- zero-variant enum
 
diff --git a/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/downcast-unsafe-trait-objects.rs b/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/downcast-unsafe-trait-objects.rs
deleted file mode 100644
index b1b2dcf3eb9..00000000000
--- a/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/downcast-unsafe-trait-objects.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Check that we if we get ahold of a dyn-incompatible trait
-// object with auto traits and lifetimes, we can downcast it
-//
-//@ check-pass
-
-#![feature(dyn_compatible_for_dispatch)]
-
-trait Trait: Sized {}
-
-fn downcast_auto(t: &(dyn Trait + Send)) -> &dyn Trait {
-    t
-}
-
-fn downcast_lifetime<'a, 'b, 't>(t: &'a (dyn Trait + 't))
-                                 -> &'b (dyn Trait + 't)
-where
-    'a: 'b,
-    't: 'a + 'b,
-{
-    t
-}
-
-fn main() {}
diff --git a/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/manual-self-impl-for-unsafe-obj.current.stderr b/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/manual-self-impl-for-unsafe-obj.current.stderr
deleted file mode 100644
index 1489791b20d..00000000000
--- a/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/manual-self-impl-for-unsafe-obj.current.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-warning: methods `good_virt` and `good_indirect` are never used
-  --> $DIR/manual-self-impl-for-unsafe-obj.rs:23:8
-   |
-LL | trait Good {
-   |       ---- methods in this trait
-LL |     fn good_virt(&self) -> char {
-   |        ^^^^^^^^^
-...
-LL |     fn good_indirect(&self) -> char {
-   |        ^^^^^^^^^^^^^
-   |
-   = note: `#[warn(dead_code)]` on by default
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/manual-self-impl-for-unsafe-obj.next.stderr b/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/manual-self-impl-for-unsafe-obj.next.stderr
deleted file mode 100644
index 1489791b20d..00000000000
--- a/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/manual-self-impl-for-unsafe-obj.next.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-warning: methods `good_virt` and `good_indirect` are never used
-  --> $DIR/manual-self-impl-for-unsafe-obj.rs:23:8
-   |
-LL | trait Good {
-   |       ---- methods in this trait
-LL |     fn good_virt(&self) -> char {
-   |        ^^^^^^^^^
-...
-LL |     fn good_indirect(&self) -> char {
-   |        ^^^^^^^^^^^^^
-   |
-   = note: `#[warn(dead_code)]` on by default
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/manual-self-impl-for-unsafe-obj.rs b/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/manual-self-impl-for-unsafe-obj.rs
deleted file mode 100644
index 425dc130d45..00000000000
--- a/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/manual-self-impl-for-unsafe-obj.rs
+++ /dev/null
@@ -1,69 +0,0 @@
-// Check that we can manually implement a dyn-incompatible trait for its trait object.
-
-//@ revisions: current next
-//@ ignore-compare-mode-next-solver (explicit revisions)
-//@[next] compile-flags: -Znext-solver
-//@ run-pass
-
-#![feature(dyn_compatible_for_dispatch)]
-
-trait Bad {
-    fn stat() -> char {
-        'A'
-    }
-    fn virt(&self) -> char {
-        'B'
-    }
-    fn indirect(&self) -> char {
-        Self::stat()
-    }
-}
-
-trait Good {
-    fn good_virt(&self) -> char { //~ WARN methods `good_virt` and `good_indirect` are never used
-        panic!()
-    }
-    fn good_indirect(&self) -> char {
-        panic!()
-    }
-}
-
-impl<'a> Bad for dyn Bad + 'a {
-    fn stat() -> char {
-        'C'
-    }
-    fn virt(&self) -> char {
-        'D'
-    }
-}
-
-struct Struct {}
-
-impl Bad for Struct {}
-
-impl Good for Struct {}
-
-fn main() {
-    let s = Struct {};
-
-    let mut res = String::new();
-
-    // Directly call static.
-    res.push(Struct::stat()); // "A"
-    res.push(<dyn Bad>::stat()); // "AC"
-
-    let good: &dyn Good = &s;
-
-    // These look similar enough...
-    let bad = unsafe { std::mem::transmute::<&dyn Good, &dyn Bad>(good) };
-
-    // Call virtual.
-    res.push(s.virt()); // "ACB"
-    res.push(bad.virt()); // "ACBD"
-
-    // Indirectly call static.
-    res.push(s.indirect()); // "ACBDA"
-    res.push(bad.indirect()); // "ACBDAC"
-
-    assert_eq!(&res, "ACBDAC");
-}
diff --git a/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/static-dispatch-unsafe-object.rs b/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/static-dispatch-unsafe-object.rs
deleted file mode 100644
index c38928a9f44..00000000000
--- a/tests/ui/rfcs/rfc-2027-dyn-compatible-for-dispatch/static-dispatch-unsafe-object.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-// Check that we can statically dispatch methods for object
-// unsafe trait objects, directly and indirectly
-//
-//@ check-pass
-
-#![feature(dyn_compatible_for_dispatch)]
-
-trait Statics {
-    fn plain() {}
-    fn generic<T>() {}
-}
-
-trait Trait: Sized {}
-
-impl<'a> Statics for dyn Trait + 'a {}
-
-fn static_poly<T: Statics + ?Sized>() {
-    T::plain();
-    T::generic::<usize>();
-}
-
-fn inferred_poly<T: Statics + ?Sized>(t: &T) {
-    static_poly::<T>();
-    T::plain();
-    T::generic::<usize>();
-}
-
-fn call(t: &dyn Trait) {
-    static_poly::<dyn Trait>();
-    inferred_poly(t);
-}
-
-fn main() {
-    static_poly::<dyn Trait>();
-    <dyn Trait>::plain();
-    <dyn Trait>::generic::<usize>()
-}
diff --git a/tests/ui/rust-2021/ice-return-unsized-can-impl-2.rs b/tests/ui/rust-2021/ice-return-unsized-can-impl-2.rs
index e57e9ce4844..567d37e1b82 100644
--- a/tests/ui/rust-2021/ice-return-unsized-can-impl-2.rs
+++ b/tests/ui/rust-2021/ice-return-unsized-can-impl-2.rs
@@ -1,15 +1,17 @@
 // Doesn't trigger ICE when returning unsized trait that can be impl
 // issue https://github.com/rust-lang/rust/issues/125512
 //@ edition:2021
-#![feature(dyn_compatible_for_dispatch)]
+
 trait B {
     fn f(a: A) -> A;
     //~^ ERROR: expected a type, found a trait
     //~| ERROR: expected a type, found a trait
 }
+
 trait A {
     fn concrete(b: B) -> B;
     //~^ ERROR: expected a type, found a trait
     //~| ERROR: expected a type, found a trait
 }
+
 fn main() {}
diff --git a/tests/ui/rust-2021/ice-return-unsized-can-impl-2.stderr b/tests/ui/rust-2021/ice-return-unsized-can-impl-2.stderr
index ac19f91881d..f2942820e28 100644
--- a/tests/ui/rust-2021/ice-return-unsized-can-impl-2.stderr
+++ b/tests/ui/rust-2021/ice-return-unsized-can-impl-2.stderr
@@ -1,5 +1,5 @@
 error[E0782]: expected a type, found a trait
-  --> $DIR/ice-return-unsized-can-impl-2.rs:11:20
+  --> $DIR/ice-return-unsized-can-impl-2.rs:12:20
    |
 LL |     fn concrete(b: B) -> B;
    |                    ^
@@ -16,7 +16,7 @@ LL |     fn concrete(b: impl B) -> B;
    |                    ++++
 
 error[E0782]: expected a type, found a trait
-  --> $DIR/ice-return-unsized-can-impl-2.rs:11:26
+  --> $DIR/ice-return-unsized-can-impl-2.rs:12:26
    |
 LL |     fn concrete(b: B) -> B;
    |                          ^
diff --git a/tests/ui/rust-2021/ice-return-unsized-can-impl.rs b/tests/ui/rust-2021/ice-return-unsized-can-impl.rs
index 055b11b4424..8b83b7b537a 100644
--- a/tests/ui/rust-2021/ice-return-unsized-can-impl.rs
+++ b/tests/ui/rust-2021/ice-return-unsized-can-impl.rs
@@ -1,7 +1,6 @@
 // Doesn't trigger ICE when returning unsized trait that can be impl
 // issue https://github.com/rust-lang/rust/issues/120482
 //@ edition:2021
-#![feature(dyn_compatible_for_dispatch)]
 
 trait B {
     fn bar(&self, x: &Self);
diff --git a/tests/ui/rust-2021/ice-return-unsized-can-impl.stderr b/tests/ui/rust-2021/ice-return-unsized-can-impl.stderr
index 463c6892ca2..cfee506e29b 100644
--- a/tests/ui/rust-2021/ice-return-unsized-can-impl.stderr
+++ b/tests/ui/rust-2021/ice-return-unsized-can-impl.stderr
@@ -1,5 +1,5 @@
 error[E0782]: expected a type, found a trait
-  --> $DIR/ice-return-unsized-can-impl.rs:11:15
+  --> $DIR/ice-return-unsized-can-impl.rs:10:15
    |
 LL |     fn g(new: B) -> B;
    |               ^
@@ -16,7 +16,7 @@ LL |     fn g(new: impl B) -> B;
    |               ++++
 
 error[E0782]: expected a type, found a trait
-  --> $DIR/ice-return-unsized-can-impl.rs:11:21
+  --> $DIR/ice-return-unsized-can-impl.rs:10:21
    |
 LL |     fn g(new: B) -> B;
    |                     ^
diff --git a/tests/ui/rust-2021/ice-unsized-fn-params-2.rs b/tests/ui/rust-2021/ice-unsized-fn-params-2.rs
index 2b4f7bd088f..8af56ffe80d 100644
--- a/tests/ui/rust-2021/ice-unsized-fn-params-2.rs
+++ b/tests/ui/rust-2021/ice-unsized-fn-params-2.rs
@@ -1,7 +1,7 @@
 //@ edition:2021
 // Test that it doesn't trigger an ICE when using an unsized fn params.
 // https://github.com/rust-lang/rust/issues/120241
-#![feature(dyn_compatible_for_dispatch)]
+
 #![feature(unsized_fn_params)]
 
 fn guard(_s: Copy) -> bool {
diff --git a/tests/ui/rust-2021/ice-unsized-fn-params.rs b/tests/ui/rust-2021/ice-unsized-fn-params.rs
index 6d8c1c3f152..6ed67698e96 100644
--- a/tests/ui/rust-2021/ice-unsized-fn-params.rs
+++ b/tests/ui/rust-2021/ice-unsized-fn-params.rs
@@ -1,7 +1,6 @@
 //@ edition:2021
 // Test that it doesn't trigger an ICE when using an unsized fn params.
 // https://github.com/rust-lang/rust/issues/120241
-#![feature(dyn_compatible_for_dispatch)]
 
 trait B {
     fn f(a: A) -> A;
diff --git a/tests/ui/rust-2021/ice-unsized-fn-params.stderr b/tests/ui/rust-2021/ice-unsized-fn-params.stderr
index c31500ba800..4d900711ed6 100644
--- a/tests/ui/rust-2021/ice-unsized-fn-params.stderr
+++ b/tests/ui/rust-2021/ice-unsized-fn-params.stderr
@@ -1,5 +1,5 @@
 error[E0782]: expected a type, found a trait
-  --> $DIR/ice-unsized-fn-params.rs:13:13
+  --> $DIR/ice-unsized-fn-params.rs:12:13
    |
 LL |     fn g(b: B) -> B;
    |             ^
@@ -16,7 +16,7 @@ LL |     fn g(b: impl B) -> B;
    |             ++++
 
 error[E0782]: expected a type, found a trait
-  --> $DIR/ice-unsized-fn-params.rs:13:19
+  --> $DIR/ice-unsized-fn-params.rs:12:19
    |
 LL |     fn g(b: B) -> B;
    |                   ^
@@ -27,7 +27,7 @@ LL |     fn g(b: B) -> impl B;
    |                   ++++
 
 error[E0782]: expected a type, found a trait
-  --> $DIR/ice-unsized-fn-params.rs:7:13
+  --> $DIR/ice-unsized-fn-params.rs:6:13
    |
 LL |     fn f(a: A) -> A;
    |             ^
@@ -44,7 +44,7 @@ LL |     fn f(a: impl A) -> A;
    |             ++++
 
 error[E0782]: expected a type, found a trait
-  --> $DIR/ice-unsized-fn-params.rs:7:19
+  --> $DIR/ice-unsized-fn-params.rs:6:19
    |
 LL |     fn f(a: A) -> A;
    |                   ^
diff --git a/tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr b/tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr
deleted file mode 100644
index d324f4641cf..00000000000
--- a/tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-error[E0038]: the trait `Foo` is not dyn compatible
-  --> $DIR/arbitrary-self-types-dyn-incompatible.rs:33:13
-   |
-LL |     fn foo(self: &Rc<Self>) -> usize;
-   |                  --------- help: consider changing method `foo`'s `self` parameter to be `&self`: `&Self`
-...
-LL |     let x = Rc::new(5usize) as Rc<dyn Foo>;
-   |             ^^^^^^^^^^^^^^^ `Foo` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/arbitrary-self-types-dyn-incompatible.rs:8:18
-   |
-LL | trait Foo {
-   |       --- this trait is not dyn compatible...
-LL |     fn foo(self: &Rc<Self>) -> usize;
-   |                  ^^^^^^^^^ ...because method `foo`'s `self` parameter cannot be dispatched on
-   = help: only type `usize` implements `Foo`; consider using it directly instead.
-   = note: required for the cast from `Rc<usize>` to `Rc<dyn Foo>`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/self/arbitrary-self-types-dyn-incompatible.rs b/tests/ui/self/arbitrary-self-types-dyn-incompatible.rs
index 940b2f1e8e2..0477d9d79c7 100644
--- a/tests/ui/self/arbitrary-self-types-dyn-incompatible.rs
+++ b/tests/ui/self/arbitrary-self-types-dyn-incompatible.rs
@@ -1,7 +1,3 @@
-//@ revisions: curr dyn_compatible_for_dispatch
-
-#![cfg_attr(dyn_compatible_for_dispatch, feature(dyn_compatible_for_dispatch))]
-
 use std::rc::Rc;
 
 trait Foo {
@@ -31,9 +27,8 @@ impl Bar for usize {
 
 fn make_foo() {
     let x = Rc::new(5usize) as Rc<dyn Foo>;
-    //[curr]~^ ERROR E0038
-    //[curr]~| ERROR E0038
-    //[dyn_compatible_for_dispatch]~^^^ ERROR E0038
+    //~^ ERROR E0038
+    //~| ERROR E0038
 }
 
 fn make_bar() {
diff --git a/tests/ui/self/arbitrary-self-types-dyn-incompatible.stderr b/tests/ui/self/arbitrary-self-types-dyn-incompatible.stderr
new file mode 100644
index 00000000000..9fb4c80329d
--- /dev/null
+++ b/tests/ui/self/arbitrary-self-types-dyn-incompatible.stderr
@@ -0,0 +1,42 @@
+error[E0038]: the trait `Foo` is not dyn compatible
+  --> $DIR/arbitrary-self-types-dyn-incompatible.rs:29:32
+   |
+LL |     fn foo(self: &Rc<Self>) -> usize;
+   |                  --------- help: consider changing method `foo`'s `self` parameter to be `&self`: `&Self`
+...
+LL |     let x = Rc::new(5usize) as Rc<dyn Foo>;
+   |                                ^^^^^^^^^^^ `Foo` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/arbitrary-self-types-dyn-incompatible.rs:4:18
+   |
+LL | trait Foo {
+   |       --- this trait is not dyn compatible...
+LL |     fn foo(self: &Rc<Self>) -> usize;
+   |                  ^^^^^^^^^ ...because method `foo`'s `self` parameter cannot be dispatched on
+   = help: only type `usize` implements `Foo`; consider using it directly instead.
+
+error[E0038]: the trait `Foo` is not dyn compatible
+  --> $DIR/arbitrary-self-types-dyn-incompatible.rs:29:13
+   |
+LL |     fn foo(self: &Rc<Self>) -> usize;
+   |                  --------- help: consider changing method `foo`'s `self` parameter to be `&self`: `&Self`
+...
+LL |     let x = Rc::new(5usize) as Rc<dyn Foo>;
+   |             ^^^^^^^^^^^^^^^ `Foo` is not dyn compatible
+   |
+note: for a trait to be dyn compatible it needs to allow building a vtable
+      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
+  --> $DIR/arbitrary-self-types-dyn-incompatible.rs:4:18
+   |
+LL | trait Foo {
+   |       --- this trait is not dyn compatible...
+LL |     fn foo(self: &Rc<Self>) -> usize;
+   |                  ^^^^^^^^^ ...because method `foo`'s `self` parameter cannot be dispatched on
+   = help: only type `usize` implements `Foo`; consider using it directly instead.
+   = note: required for the cast from `Rc<usize>` to `Rc<dyn Foo>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.rs b/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.rs
index 71f198f7dc7..94b76fe9685 100644
--- a/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.rs
+++ b/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.rs
@@ -15,7 +15,7 @@ struct Dispatchable<T: ?Sized, Z> {
 }
 
 impl<T, U> DispatchFromDyn<Dispatchable<U, i32>> for Dispatchable<T, ()>
-//~^ ERROR implementing the `DispatchFromDyn` trait requires multiple coercions
+//~^ ERROR implementing `DispatchFromDyn` does not allow multiple fields to be coerced
 where
     T: Unsize<U> + ?Sized,
     U: ?Sized,
diff --git a/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.stderr b/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.stderr
index 1f13c51f679..91760b9e2ea 100644
--- a/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.stderr
+++ b/tests/ui/self/dispatch-from-dyn-zst-transmute-zst-nonzst.stderr
@@ -1,4 +1,4 @@
-error[E0378]: implementing the `DispatchFromDyn` trait requires multiple coercions
+error[E0375]: implementing `DispatchFromDyn` does not allow multiple fields to be coerced
   --> $DIR/dispatch-from-dyn-zst-transmute-zst-nonzst.rs:17:1
    |
 LL | / impl<T, U> DispatchFromDyn<Dispatchable<U, i32>> for Dispatchable<T, ()>
@@ -8,9 +8,14 @@ LL | |     T: Unsize<U> + ?Sized,
 LL | |     U: ?Sized,
    | |______________^
    |
-   = note: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced
-   = note: currently, 2 fields need coercions: `_ptr` (`Box<T>` to `Box<U>`), `z` (`()` to `i32`)
+note: the trait `DispatchFromDyn` may only be implemented when a single field is being coerced
+  --> $DIR/dispatch-from-dyn-zst-transmute-zst-nonzst.rs:13:5
+   |
+LL |     _ptr: Box<T>,
+   |     ^^^^^^^^^^^^
+LL |     z: Z,
+   |     ^^^^
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0378`.
+For more information about this error, try `rustc --explain E0375`.
diff --git a/tests/ui/self/dispatch-from-dyn-zst-transmute.rs b/tests/ui/self/dispatch-from-dyn-zst-transmute.rs
index 57c255b4d7b..967958ab486 100644
--- a/tests/ui/self/dispatch-from-dyn-zst-transmute.rs
+++ b/tests/ui/self/dispatch-from-dyn-zst-transmute.rs
@@ -15,7 +15,7 @@ struct Foo<'a, U: ?Sized> {
 }
 
 impl<'a, T, U> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T>
-//~^ ERROR implementing the `DispatchFromDyn` trait requires multiple coercions
+//~^ ERROR implementing `DispatchFromDyn` does not allow multiple fields to be coerced
 where
     T: Unsize<U> + ?Sized,
     U: ?Sized {}
diff --git a/tests/ui/self/dispatch-from-dyn-zst-transmute.stderr b/tests/ui/self/dispatch-from-dyn-zst-transmute.stderr
index 5a8ae88b5f1..cc8be45e99d 100644
--- a/tests/ui/self/dispatch-from-dyn-zst-transmute.stderr
+++ b/tests/ui/self/dispatch-from-dyn-zst-transmute.stderr
@@ -1,4 +1,4 @@
-error[E0378]: implementing the `DispatchFromDyn` trait requires multiple coercions
+error[E0375]: implementing `DispatchFromDyn` does not allow multiple fields to be coerced
   --> $DIR/dispatch-from-dyn-zst-transmute.rs:17:1
    |
 LL | / impl<'a, T, U> DispatchFromDyn<Foo<'a, U>> for Foo<'a, T>
@@ -8,9 +8,14 @@ LL | |     T: Unsize<U> + ?Sized,
 LL | |     U: ?Sized {}
    | |_____________^
    |
-   = note: the trait `DispatchFromDyn` may only be implemented for a coercion between structures with a single field being coerced
-   = note: currently, 2 fields need coercions: `token` (`IsSendToken<T>` to `IsSendToken<U>`), `ptr` (`&'a T` to `&'a U`)
+note: the trait `DispatchFromDyn` may only be implemented when a single field is being coerced
+  --> $DIR/dispatch-from-dyn-zst-transmute.rs:13:5
+   |
+LL |     token: IsSendToken<U>,
+   |     ^^^^^^^^^^^^^^^^^^^^^
+LL |     ptr: &'a U,
+   |     ^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0378`.
+For more information about this error, try `rustc --explain E0375`.
diff --git a/tests/ui/simd/intrinsic/generic-elements.rs b/tests/ui/simd/intrinsic/generic-elements.rs
index 4be6645f029..54cf35df8c7 100644
--- a/tests/ui/simd/intrinsic/generic-elements.rs
+++ b/tests/ui/simd/intrinsic/generic-elements.rs
@@ -41,7 +41,7 @@ unsafe fn simd_extract<T, E>(x: T, idx: u32) -> E;
 unsafe fn simd_shuffle<T, I, U>(x: T, y: T, idx: I) -> U;
 
 #[rustc_intrinsic]
-unsafe fn simd_shuffle_generic<T, U, const IDX: &'static [u32]>(x: T, y: T) -> U;
+unsafe fn simd_shuffle_const_generic<T, U, const IDX: &'static [u32]>(x: T, y: T) -> U;
 
 
 #[repr(simd)]
@@ -83,27 +83,27 @@ fn main() {
         //~^ ERROR expected return type of length 8, found `i32x2` with length 2
 
         const I2: &[u32] = &[0; 2];
-        simd_shuffle_generic::<i32, i32, I2>(0, 0);
+        simd_shuffle_const_generic::<i32, i32, I2>(0, 0);
         //~^ ERROR expected SIMD input type, found non-SIMD `i32`
         const I4: &[u32] = &[0; 4];
-        simd_shuffle_generic::<i32, i32, I4>(0, 0);
+        simd_shuffle_const_generic::<i32, i32, I4>(0, 0);
         //~^ ERROR expected SIMD input type, found non-SIMD `i32`
         const I8: &[u32] = &[0; 8];
-        simd_shuffle_generic::<i32, i32, I8>(0, 0);
+        simd_shuffle_const_generic::<i32, i32, I8>(0, 0);
         //~^ ERROR expected SIMD input type, found non-SIMD `i32`
 
-        simd_shuffle_generic::<_, f32x2, I2>(x, x);
+        simd_shuffle_const_generic::<_, f32x2, I2>(x, x);
         //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32`
-        simd_shuffle_generic::<_, f32x4, I4>(x, x);
+        simd_shuffle_const_generic::<_, f32x4, I4>(x, x);
         //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32`
-        simd_shuffle_generic::<_, f32x8, I8>(x, x);
+        simd_shuffle_const_generic::<_, f32x8, I8>(x, x);
         //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32`
 
-        simd_shuffle_generic::<_, i32x8, I2>(x, x);
+        simd_shuffle_const_generic::<_, i32x8, I2>(x, x);
         //~^ ERROR expected return type of length 2, found `i32x8` with length 8
-        simd_shuffle_generic::<_, i32x8, I4>(x, x);
+        simd_shuffle_const_generic::<_, i32x8, I4>(x, x);
         //~^ ERROR expected return type of length 4, found `i32x8` with length 8
-        simd_shuffle_generic::<_, i32x2, I8>(x, x);
+        simd_shuffle_const_generic::<_, i32x2, I8>(x, x);
         //~^ ERROR expected return type of length 8, found `i32x2` with length 2
     }
 }
diff --git a/tests/ui/simd/intrinsic/generic-elements.stderr b/tests/ui/simd/intrinsic/generic-elements.stderr
index 8104c3ba5a2..1b3e8d59213 100644
--- a/tests/ui/simd/intrinsic/generic-elements.stderr
+++ b/tests/ui/simd/intrinsic/generic-elements.stderr
@@ -70,59 +70,59 @@ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected ret
 LL |         simd_shuffle::<_, _, i32x2>(x, x, IDX8);
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected SIMD input type, found non-SIMD `i32`
+error[E0511]: invalid monomorphization of `simd_shuffle_const_generic` intrinsic: expected SIMD input type, found non-SIMD `i32`
   --> $DIR/generic-elements.rs:86:9
    |
-LL |         simd_shuffle_generic::<i32, i32, I2>(0, 0);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         simd_shuffle_const_generic::<i32, i32, I2>(0, 0);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected SIMD input type, found non-SIMD `i32`
+error[E0511]: invalid monomorphization of `simd_shuffle_const_generic` intrinsic: expected SIMD input type, found non-SIMD `i32`
   --> $DIR/generic-elements.rs:89:9
    |
-LL |         simd_shuffle_generic::<i32, i32, I4>(0, 0);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         simd_shuffle_const_generic::<i32, i32, I4>(0, 0);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected SIMD input type, found non-SIMD `i32`
+error[E0511]: invalid monomorphization of `simd_shuffle_const_generic` intrinsic: expected SIMD input type, found non-SIMD `i32`
   --> $DIR/generic-elements.rs:92:9
    |
-LL |         simd_shuffle_generic::<i32, i32, I8>(0, 0);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         simd_shuffle_const_generic::<i32, i32, I8>(0, 0);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32`
+error[E0511]: invalid monomorphization of `simd_shuffle_const_generic` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32`
   --> $DIR/generic-elements.rs:95:9
    |
-LL |         simd_shuffle_generic::<_, f32x2, I2>(x, x);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         simd_shuffle_const_generic::<_, f32x2, I2>(x, x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32`
+error[E0511]: invalid monomorphization of `simd_shuffle_const_generic` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32`
   --> $DIR/generic-elements.rs:97:9
    |
-LL |         simd_shuffle_generic::<_, f32x4, I4>(x, x);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         simd_shuffle_const_generic::<_, f32x4, I4>(x, x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32`
+error[E0511]: invalid monomorphization of `simd_shuffle_const_generic` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32`
   --> $DIR/generic-elements.rs:99:9
    |
-LL |         simd_shuffle_generic::<_, f32x8, I8>(x, x);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         simd_shuffle_const_generic::<_, f32x8, I8>(x, x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return type of length 2, found `i32x8` with length 8
+error[E0511]: invalid monomorphization of `simd_shuffle_const_generic` intrinsic: expected return type of length 2, found `i32x8` with length 8
   --> $DIR/generic-elements.rs:102:9
    |
-LL |         simd_shuffle_generic::<_, i32x8, I2>(x, x);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         simd_shuffle_const_generic::<_, i32x8, I2>(x, x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return type of length 4, found `i32x8` with length 8
+error[E0511]: invalid monomorphization of `simd_shuffle_const_generic` intrinsic: expected return type of length 4, found `i32x8` with length 8
   --> $DIR/generic-elements.rs:104:9
    |
-LL |         simd_shuffle_generic::<_, i32x8, I4>(x, x);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         simd_shuffle_const_generic::<_, i32x8, I4>(x, x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return type of length 8, found `i32x2` with length 2
+error[E0511]: invalid monomorphization of `simd_shuffle_const_generic` intrinsic: expected return type of length 8, found `i32x2` with length 2
   --> $DIR/generic-elements.rs:106:9
    |
-LL |         simd_shuffle_generic::<_, i32x2, I8>(x, x);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |         simd_shuffle_const_generic::<_, i32x2, I8>(x, x);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 21 previous errors
 
diff --git a/tests/ui/simd/monomorphize-shuffle-index.generic.stderr b/tests/ui/simd/monomorphize-shuffle-index.generic.stderr
index b0a8da59fac..8d4bf1e0533 100644
--- a/tests/ui/simd/monomorphize-shuffle-index.generic.stderr
+++ b/tests/ui/simd/monomorphize-shuffle-index.generic.stderr
@@ -1,10 +1,10 @@
 error: overly complex generic constant
-  --> $DIR/monomorphize-shuffle-index.rs:32:45
+  --> $DIR/monomorphize-shuffle-index.rs:32:51
    |
-LL |         return simd_shuffle_generic::<_, _, { &Self::I.0 }>(a, b);
-   |                                             ^^----------^^
-   |                                               |
-   |                                               pointer casts are not allowed in generic constants
+LL |         return simd_shuffle_const_generic::<_, _, { &Self::I.0 }>(a, b);
+   |                                                   ^^----------^^
+   |                                                     |
+   |                                                     pointer casts are not allowed in generic constants
    |
    = help: consider moving this anonymous constant into a `const` function
 
diff --git a/tests/ui/simd/monomorphize-shuffle-index.rs b/tests/ui/simd/monomorphize-shuffle-index.rs
index 01926408a2c..026193e6af6 100644
--- a/tests/ui/simd/monomorphize-shuffle-index.rs
+++ b/tests/ui/simd/monomorphize-shuffle-index.rs
@@ -11,7 +11,7 @@ unsafe fn simd_shuffle<T, I, U>(a: T, b: T, i: I) -> U;
 
 #[rustc_intrinsic]
 #[cfg(any(generic, generic_with_fn))]
-unsafe fn simd_shuffle_generic<T, U, const I: &'static [u32]>(a: T, b: T) -> U;
+unsafe fn simd_shuffle_const_generic<T, U, const I: &'static [u32]>(a: T, b: T) -> U;
 
 
 #[derive(Copy, Clone)]
@@ -29,10 +29,10 @@ trait Shuffle<const N: usize> {
         #[cfg(old)]
         return simd_shuffle(a, b, Self::I);
         #[cfg(generic)]
-        return simd_shuffle_generic::<_, _, { &Self::I.0 }>(a, b);
+        return simd_shuffle_const_generic::<_, _, { &Self::I.0 }>(a, b);
         //[generic]~^ overly complex generic constant
         #[cfg(generic_with_fn)]
-        return simd_shuffle_generic::<_, _, { Self::J }>(a, b);
+        return simd_shuffle_const_generic::<_, _, { Self::J }>(a, b);
     }
 }
 
diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.rs b/tests/ui/stability-attribute/stability-attribute-sanity.rs
index 7857a0603bd..f46e35e1a72 100644
--- a/tests/ui/stability-attribute/stability-attribute-sanity.rs
+++ b/tests/ui/stability-attribute/stability-attribute-sanity.rs
@@ -8,16 +8,16 @@ mod bogus_attribute_types_1 {
     #[stable(feature = "a", since = "4.4.4", reason)] //~ ERROR unknown meta item 'reason' [E0541]
     fn f1() { }
 
-    #[stable(feature = "a", since)] //~ ERROR incorrect meta item [E0539]
+    #[stable(feature = "a", since)] //~ ERROR expected a quoted string literal [E0539]
     fn f2() { }
 
-    #[stable(feature, since = "3.3.3")] //~ ERROR incorrect meta item [E0539]
+    #[stable(feature, since = "3.3.3")] //~ ERROR expected a quoted string literal [E0539]
     fn f3() { }
 
-    #[stable(feature = "a", since(b))] //~ ERROR incorrect meta item [E0539]
+    #[stable(feature = "a", since(b))] //~ ERROR expected a quoted string literal [E0539]
     fn f5() { }
 
-    #[stable(feature(b), since = "3.3.3")] //~ ERROR incorrect meta item [E0539]
+    #[stable(feature(b), since = "3.3.3")] //~ ERROR expected a quoted string literal [E0539]
     fn f6() { }
 }
 
diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.stderr b/tests/ui/stability-attribute/stability-attribute-sanity.stderr
index c614fc2b9f7..2e2b5b509c8 100644
--- a/tests/ui/stability-attribute/stability-attribute-sanity.stderr
+++ b/tests/ui/stability-attribute/stability-attribute-sanity.stderr
@@ -1,40 +1,28 @@
-error: multiple `deprecated` attributes
-  --> $DIR/stability-attribute-sanity.rs:62:1
-   |
-LL | #[deprecated(since = "5.5.5", note = "text")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
-   |
-note: attribute also specified here
-  --> $DIR/stability-attribute-sanity.rs:61:1
-   |
-LL | #[deprecated(since = "5.5.5", note = "text")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
 error[E0541]: unknown meta item 'reason'
   --> $DIR/stability-attribute-sanity.rs:8:46
    |
 LL |     #[stable(feature = "a", since = "4.4.4", reason)]
    |                                              ^^^^^^ expected one of `feature`, `since`
 
-error[E0539]: incorrect meta item
+error[E0539]: expected a quoted string literal
   --> $DIR/stability-attribute-sanity.rs:11:29
    |
 LL |     #[stable(feature = "a", since)]
    |                             ^^^^^
 
-error[E0539]: incorrect meta item
+error[E0539]: expected a quoted string literal
   --> $DIR/stability-attribute-sanity.rs:14:14
    |
 LL |     #[stable(feature, since = "3.3.3")]
    |              ^^^^^^^
 
-error[E0539]: incorrect meta item
+error[E0539]: expected a quoted string literal
   --> $DIR/stability-attribute-sanity.rs:17:29
    |
 LL |     #[stable(feature = "a", since(b))]
    |                             ^^^^^^^^
 
-error[E0539]: incorrect meta item
+error[E0539]: expected a quoted string literal
   --> $DIR/stability-attribute-sanity.rs:20:14
    |
 LL |     #[stable(feature(b), since = "3.3.3")]
@@ -100,6 +88,18 @@ error: 'since' must be a Rust version number, such as "1.31.0"
 LL | #[stable(feature = "e", since = "b")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error: multiple `deprecated` attributes
+  --> $DIR/stability-attribute-sanity.rs:62:1
+   |
+LL | #[deprecated(since = "5.5.5", note = "text")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+note: attribute also specified here
+  --> $DIR/stability-attribute-sanity.rs:61:1
+   |
+LL | #[deprecated(since = "5.5.5", note = "text")]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0544]: multiple stability levels
   --> $DIR/stability-attribute-sanity.rs:64:1
    |
diff --git a/tests/ui/suggestions/issue-104328.rs b/tests/ui/suggestions/issue-104328.rs
deleted file mode 100644
index 2b0fbdb8d35..00000000000
--- a/tests/ui/suggestions/issue-104328.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-#![feature(dyn_compatible_for_dispatch)]
-
-trait Foo {
-    fn f() {}
-}
-
-impl Foo for dyn Sized {}
-
-fn main() {
-    Foo::f();
-    //~^ ERROR cannot call associated function on trait without specifying the corresponding `impl` type
-}
diff --git a/tests/ui/suggestions/issue-104328.stderr b/tests/ui/suggestions/issue-104328.stderr
deleted file mode 100644
index 3c5e6f16289..00000000000
--- a/tests/ui/suggestions/issue-104328.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
-  --> $DIR/issue-104328.rs:10:5
-   |
-LL |     fn f() {}
-   |     --------- `Foo::f` defined here
-...
-LL |     Foo::f();
-   |     ^^^^^^^^ cannot call associated function of trait
-   |
-help: use the fully-qualified path to the only available implementation
-   |
-LL |     <(dyn Sized + 'static) as Foo>::f();
-   |     +++++++++++++++++++++++++    +
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0790`.
diff --git a/tests/ui/target-feature/feature-hierarchy.rs b/tests/ui/target-feature/feature-hierarchy.rs
index d62b86693c2..315ec983a19 100644
--- a/tests/ui/target-feature/feature-hierarchy.rs
+++ b/tests/ui/target-feature/feature-hierarchy.rs
@@ -21,10 +21,7 @@ impl Copy for bool {}
 #[stable(feature = "test", since = "1.0.0")]
 #[rustc_const_stable(feature = "test", since = "1.0.0")]
 #[rustc_intrinsic]
-#[rustc_intrinsic_must_be_overridden]
-const unsafe fn unreachable() -> ! {
-    loop {}
-}
+const unsafe fn unreachable() -> !;
 
 #[rustc_builtin_macro]
 macro_rules! cfg {
diff --git a/tests/ui/traits/issue-78372.stderr b/tests/ui/traits/issue-78372.stderr
index d4dfba4f039..fbc60ce5d83 100644
--- a/tests/ui/traits/issue-78372.stderr
+++ b/tests/ui/traits/issue-78372.stderr
@@ -65,7 +65,7 @@ LL |     fn foo(self: Smaht<Self, T>);
    = note: type of `self` must be `Self` or a type that dereferences to it
    = help: consider changing to `self`, `&self`, `&mut self`, `self: Box<Self>`, `self: Rc<Self>`, `self: Arc<Self>`, or `self: Pin<P>` (where P is one of the previous types except `Self`)
 
-error[E0378]: the trait `DispatchFromDyn` may only be implemented for a coercion between structures
+error[E0377]: the trait `DispatchFromDyn` may only be implemented for a coercion between structures
   --> $DIR/issue-78372.rs:3:1
    |
 LL | impl<T> DispatchFromDyn<Smaht<U, MISC>> for T {}
@@ -73,5 +73,5 @@ LL | impl<T> DispatchFromDyn<Smaht<U, MISC>> for T {}
 
 error: aborting due to 7 previous errors
 
-Some errors have detailed explanations: E0307, E0378, E0412, E0658.
+Some errors have detailed explanations: E0307, E0377, E0412, E0658.
 For more information about an error, try `rustc --explain E0307`.
diff --git a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.rs b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.rs
deleted file mode 100644
index 26292a1d218..00000000000
--- a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Check that we do not allow casts or coercions
-// to dyn-incompatible trait objects inside a Box
-
-#![feature(dyn_compatible_for_dispatch)]
-
-trait Trait: Sized {}
-
-struct S;
-
-impl Trait for S {}
-
-fn takes_box(t: Box<dyn Trait>) {}
-
-fn main() {
-    Box::new(S) as Box<dyn Trait>; //~ ERROR E0038
-    let t_box: Box<dyn Trait> = Box::new(S); //~ ERROR E0038
-    takes_box(Box::new(S)); //~ ERROR E0038
-}
diff --git a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr
deleted file mode 100644
index f3e4f2a63e9..00000000000
--- a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr
+++ /dev/null
@@ -1,54 +0,0 @@
-error[E0038]: the trait `Trait` is not dyn compatible
-  --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:16:33
-   |
-LL |     let t_box: Box<dyn Trait> = Box::new(S);
-   |                                 ^^^^^^^^^^^ `Trait` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:6:14
-   |
-LL | trait Trait: Sized {}
-   |       -----  ^^^^^ ...because it requires `Self: Sized`
-   |       |
-   |       this trait is not dyn compatible...
-   = help: only type `S` implements `Trait`; consider using it directly instead.
-   = note: required for the cast from `Box<S>` to `Box<dyn Trait>`
-
-error[E0038]: the trait `Trait` is not dyn compatible
-  --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:17:15
-   |
-LL |     takes_box(Box::new(S));
-   |               ^^^^^^^^^^^ `Trait` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:6:14
-   |
-LL | trait Trait: Sized {}
-   |       -----  ^^^^^ ...because it requires `Self: Sized`
-   |       |
-   |       this trait is not dyn compatible...
-   = help: only type `S` implements `Trait`; consider using it directly instead.
-   = note: required for the cast from `Box<S>` to `Box<(dyn Trait + 'static)>`
-
-error[E0038]: the trait `Trait` is not dyn compatible
-  --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:15:5
-   |
-LL |     Box::new(S) as Box<dyn Trait>;
-   |     ^^^^^^^^^^^ `Trait` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:6:14
-   |
-LL | trait Trait: Sized {}
-   |       -----  ^^^^^ ...because it requires `Self: Sized`
-   |       |
-   |       this trait is not dyn compatible...
-   = help: only type `S` implements `Trait`; consider using it directly instead.
-   = note: required for the cast from `Box<S>` to `Box<dyn Trait>`
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.rs b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.rs
deleted file mode 100644
index ec4bb2897f9..00000000000
--- a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Check that we do not allow casts or coercions
-// to dyn-incompatible trait objects by ref
-
-#![feature(dyn_compatible_for_dispatch)]
-
-trait Trait: Sized {}
-
-struct S;
-
-impl Trait for S {}
-
-fn takes_trait(t: &dyn Trait) {}
-
-fn main() {
-    &S as &dyn Trait; //~ ERROR E0038
-    let t: &dyn Trait = &S; //~ ERROR E0038
-    takes_trait(&S); //~ ERROR E0038
-}
diff --git a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr
deleted file mode 100644
index 716d0e78ff1..00000000000
--- a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr
+++ /dev/null
@@ -1,54 +0,0 @@
-error[E0038]: the trait `Trait` is not dyn compatible
-  --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:16:25
-   |
-LL |     let t: &dyn Trait = &S;
-   |                         ^^ `Trait` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:6:14
-   |
-LL | trait Trait: Sized {}
-   |       -----  ^^^^^ ...because it requires `Self: Sized`
-   |       |
-   |       this trait is not dyn compatible...
-   = help: only type `S` implements `Trait`; consider using it directly instead.
-   = note: required for the cast from `&S` to `&dyn Trait`
-
-error[E0038]: the trait `Trait` is not dyn compatible
-  --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:17:17
-   |
-LL |     takes_trait(&S);
-   |                 ^^ `Trait` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:6:14
-   |
-LL | trait Trait: Sized {}
-   |       -----  ^^^^^ ...because it requires `Self: Sized`
-   |       |
-   |       this trait is not dyn compatible...
-   = help: only type `S` implements `Trait`; consider using it directly instead.
-   = note: required for the cast from `&S` to `&dyn Trait`
-
-error[E0038]: the trait `Trait` is not dyn compatible
-  --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:15:5
-   |
-LL |     &S as &dyn Trait;
-   |     ^^ `Trait` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:6:14
-   |
-LL | trait Trait: Sized {}
-   |       -----  ^^^^^ ...because it requires `Self: Sized`
-   |       |
-   |       this trait is not dyn compatible...
-   = help: only type `S` implements `Trait`; consider using it directly instead.
-   = note: required for the cast from `&S` to `&dyn Trait`
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0038`.
diff --git a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs
deleted file mode 100644
index 6eba6b7abec..00000000000
--- a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-// Check that we do not allow coercions to object
-// unsafe trait objects in match arms
-
-#![feature(dyn_compatible_for_dispatch)]
-
-trait Trait: Sized {}
-
-struct S;
-
-impl Trait for S {}
-
-struct R;
-
-impl Trait for R {}
-
-fn opt() -> Option<()> {
-    Some(())
-}
-
-fn main() {
-    match opt() {
-        Some(()) => &S,
-        None => &R,  //~ ERROR E0308
-    }
-    let t: &dyn Trait = match opt() {
-        Some(()) => &S, //~ ERROR E0038
-        None => &R, //~ ERROR E0038
-    };
-}
diff --git a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr
deleted file mode 100644
index a7405ce4caa..00000000000
--- a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr
+++ /dev/null
@@ -1,60 +0,0 @@
-error[E0308]: `match` arms have incompatible types
-  --> $DIR/wf-dyn-incompat-trait-obj-match.rs:23:17
-   |
-LL | /     match opt() {
-LL | |         Some(()) => &S,
-   | |                     -- this is found to be of type `&S`
-LL | |         None => &R,
-   | |                 ^^ expected `&S`, found `&R`
-LL | |     }
-   | |_____- `match` arms have incompatible types
-   |
-   = note: expected reference `&S`
-              found reference `&R`
-
-error[E0038]: the trait `Trait` is not dyn compatible
-  --> $DIR/wf-dyn-incompat-trait-obj-match.rs:26:21
-   |
-LL |         Some(()) => &S,
-   |                     ^^ `Trait` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/wf-dyn-incompat-trait-obj-match.rs:6:14
-   |
-LL | trait Trait: Sized {}
-   |       -----  ^^^^^ ...because it requires `Self: Sized`
-   |       |
-   |       this trait is not dyn compatible...
-   = help: the following types implement `Trait`:
-             S
-             R
-           consider defining an enum where each variant holds one of these types,
-           implementing `Trait` for this new enum and using it instead
-   = note: required for the cast from `&S` to `&dyn Trait`
-
-error[E0038]: the trait `Trait` is not dyn compatible
-  --> $DIR/wf-dyn-incompat-trait-obj-match.rs:27:17
-   |
-LL |         None => &R,
-   |                 ^^ `Trait` is not dyn compatible
-   |
-note: for a trait to be dyn compatible it needs to allow building a vtable
-      for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility>
-  --> $DIR/wf-dyn-incompat-trait-obj-match.rs:6:14
-   |
-LL | trait Trait: Sized {}
-   |       -----  ^^^^^ ...because it requires `Self: Sized`
-   |       |
-   |       this trait is not dyn compatible...
-   = help: the following types implement `Trait`:
-             S
-             R
-           consider defining an enum where each variant holds one of these types,
-           implementing `Trait` for this new enum and using it instead
-   = note: required for the cast from `&R` to `&dyn Trait`
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0038, E0308.
-For more information about an error, try `rustc --explain E0038`.