about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock20
-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_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/abi/mod.rs10
-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_codegen_ssa/src/errors.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs10
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs4
-rw-r--r--compiler/rustc_const_eval/src/check_consts/mod.rs6
-rw-r--r--compiler/rustc_data_structures/src/sorted_map/index_map.rs2
-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/arg_matrix.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs39
-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_index/src/idx.rs91
-rw-r--r--compiler/rustc_index/src/lib.rs3
-rw-r--r--compiler/rustc_index/src/slice.rs33
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs2
-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/mir/mod.rs11
-rw-r--r--compiler/rustc_middle/src/mir/statement.rs57
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs112
-rw-r--r--compiler/rustc_middle/src/mir/terminator.rs40
-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.rs30
-rw-r--r--compiler/rustc_middle/src/ty/util.rs13
-rw-r--r--compiler/rustc_mir_build/src/builder/matches/match_pair.rs4
-rw-r--r--compiler/rustc_mir_transform/src/check_pointers.rs3
-rw-r--r--compiler/rustc_mir_transform/src/coverage/counters.rs2
-rw-r--r--compiler/rustc_mir_transform/src/coverage/graph.rs2
-rw-r--r--compiler/rustc_mir_transform/src/coverage/query.rs2
-rw-r--r--compiler/rustc_mir_transform/src/gvn.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/core/src/num/int_macros.rs8
-rw-r--r--library/core/src/num/uint_macros.rs8
-rw-r--r--library/core/src/ops/control_flow.rs21
-rw-r--r--library/core/src/slice/mod.rs48
-rw-r--r--library/coretests/tests/num/int_macros.rs164
-rw-r--r--library/coretests/tests/num/uint_macros.rs164
-rw-r--r--library/std/src/env.rs4
-rw-r--r--library/std/src/fs/tests.rs4
-rw-r--r--library/std/src/sys/pal/windows/fs.rs36
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/Cargo.toml1
-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/librustdoc/html/escape.rs51
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css107
-rw-r--r--src/librustdoc/html/static/js/main.js37
-rw-r--r--src/librustdoc/html/static/js/settings.js13
-rw-r--r--src/librustdoc/html/static/js/storage.js3
-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/rust-version2
-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/rust-analyzer/.github/workflows/release.yaml6
-rw-r--r--src/tools/rust-analyzer/CONTRIBUTING.md2
-rw-r--r--src/tools/rust-analyzer/Cargo.lock51
-rw-r--r--src/tools/rust-analyzer/Cargo.toml12
-rw-r--r--src/tools/rust-analyzer/README.md4
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/input.rs37
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expander.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/db.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs20
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs36
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs25
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs25
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs37
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests.rs36
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/status.rs2
-rw-r--r--src/tools/rust-analyzer/crates/limit/Cargo.toml16
-rw-r--r--src/tools/rust-analyzer/crates/limit/src/lib.rs67
-rw-r--r--src/tools/rust-analyzer/crates/load-cargo/src/lib.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/parser.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs8
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/project_json.rs5
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/sysroot.rs14
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs17
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt25
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt25
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt25
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt12
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt11
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs1
-rw-r--r--src/tools/rust-analyzer/crates/test-fixture/src/lib.rs13
-rw-r--r--src/tools/rust-analyzer/docs/book/book.toml5
-rw-r--r--src/tools/rust-analyzer/docs/book/src/SUMMARY.md8
-rw-r--r--src/tools/rust-analyzer/docs/book/src/assists_generated.md324
-rw-r--r--src/tools/rust-analyzer/docs/book/src/configuration.md6
-rw-r--r--src/tools/rust-analyzer/docs/book/src/contributing/README.md (renamed from src/tools/rust-analyzer/docs/dev/README.md)14
-rw-r--r--src/tools/rust-analyzer/docs/book/src/contributing/architecture.md (renamed from src/tools/rust-analyzer/docs/dev/architecture.md)15
-rw-r--r--src/tools/rust-analyzer/docs/book/src/contributing/debugging.md (renamed from src/tools/rust-analyzer/docs/dev/debugging.md)8
-rw-r--r--src/tools/rust-analyzer/docs/book/src/contributing/guide.md (renamed from src/tools/rust-analyzer/docs/dev/guide.md)13
-rw-r--r--src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md (renamed from src/tools/rust-analyzer/docs/dev/lsp-extensions.md)2
-rw-r--r--src/tools/rust-analyzer/docs/book/src/contributing/setup.md (renamed from src/tools/rust-analyzer/docs/dev/setup.md)0
-rw-r--r--src/tools/rust-analyzer/docs/book/src/contributing/style.md (renamed from src/tools/rust-analyzer/docs/dev/style.md)4
-rw-r--r--src/tools/rust-analyzer/docs/book/src/contributing/syntax.md (renamed from src/tools/rust-analyzer/docs/dev/syntax.md)0
-rw-r--r--src/tools/rust-analyzer/docs/book/src/editor_features.md5
-rw-r--r--src/tools/rust-analyzer/docs/book/src/other_editors.md2
-rw-r--r--src/tools/rust-analyzer/rust-version2
-rw-r--r--src/tools/rust-analyzer/xtask/src/codegen.rs8
-rw-r--r--src/tools/rust-analyzer/xtask/src/codegen/parser_inline_tests.rs133
-rw-r--r--src/tools/rust-analyzer/xtask/src/tidy.rs7
-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/codegen/issues/str-to-string-128690.rs10
-rw-r--r--tests/pretty/hir-pretty-attr.pp11
-rw-r--r--tests/pretty/hir-pretty-attr.rs7
-rw-r--r--tests/rustdoc-gui/docblock-code-block-line-number.goml68
-rw-r--r--tests/rustdoc-gui/source-code-wrapping.goml47
-rw-r--r--tests/rustdoc-gui/src/test_docs/lib.rs9
-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/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
405 files changed, 6897 insertions, 6032 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 4401489813a..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",
@@ -4571,6 +4580,7 @@ dependencies = [
  "itertools",
  "minifier",
  "pulldown-cmark 0.9.6",
+ "pulldown-cmark-escape",
  "regex",
  "rinja",
  "rustdoc-json-types",
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_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/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 756a2226753..e8076ce77ab 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -402,9 +402,13 @@ pub(crate) fn codegen_terminator_call<'tcx>(
 
         if is_call_from_compiler_builtins_to_upstream_monomorphization(fx.tcx, instance) {
             if target.is_some() {
-                let caller = with_no_trimmed_paths!(fx.tcx.def_path_str(fx.instance.def_id()));
-                let callee = with_no_trimmed_paths!(fx.tcx.def_path_str(def_id));
-                fx.tcx.dcx().emit_err(CompilerBuiltinsCannotCall { caller, callee });
+                let caller_def = fx.instance.def_id();
+                let e = CompilerBuiltinsCannotCall {
+                    span: fx.tcx.def_span(caller_def),
+                    caller: with_no_trimmed_paths!(fx.tcx.def_path_str(caller_def)),
+                    callee: with_no_trimmed_paths!(fx.tcx.def_path_str(def_id)),
+                };
+                fx.tcx.dcx().emit_err(e);
             } else {
                 fx.bcx.ins().trap(TrapCode::user(2).unwrap());
                 return;
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_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 3ddbe4aeeec..5e25de02a77 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -1180,6 +1180,8 @@ pub(crate) struct ErrorCreatingRemarkDir {
 pub struct CompilerBuiltinsCannotCall {
     pub caller: String,
     pub callee: String,
+    #[primary_span]
+    pub span: Span,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 1e52c639463..e2a9b540d30 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -165,9 +165,13 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
         if let Some(instance) = instance {
             if is_call_from_compiler_builtins_to_upstream_monomorphization(tcx, instance) {
                 if destination.is_some() {
-                    let caller = with_no_trimmed_paths!(tcx.def_path_str(fx.instance.def_id()));
-                    let callee = with_no_trimmed_paths!(tcx.def_path_str(instance.def_id()));
-                    tcx.dcx().emit_err(CompilerBuiltinsCannotCall { caller, callee });
+                    let caller_def = fx.instance.def_id();
+                    let e = CompilerBuiltinsCannotCall {
+                        span: tcx.def_span(caller_def),
+                        caller: with_no_trimmed_paths!(tcx.def_path_str(caller_def)),
+                        callee: with_no_trimmed_paths!(tcx.def_path_str(instance.def_id())),
+                    };
+                    tcx.dcx().emit_err(e);
                 } else {
                     info!(
                         "compiler_builtins call to diverging function {:?} replaced with abort",
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index ba28720afec..0758e5d0456 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -3,7 +3,7 @@ use std::iter;
 use rustc_index::IndexVec;
 use rustc_index::bit_set::DenseBitSet;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::mir::{UnwindTerminateReason, traversal};
+use rustc_middle::mir::{Local, UnwindTerminateReason, traversal};
 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, TyAndLayout};
 use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
 use rustc_middle::{bug, mir, span_bug};
@@ -240,7 +240,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
     let local_values = {
         let args = arg_local_refs(&mut start_bx, &mut fx, &memory_locals);
 
-        let mut allocate_local = |local| {
+        let mut allocate_local = |local: Local| {
             let decl = &mir.local_decls[local];
             let layout = start_bx.layout_of(fx.monomorphize(decl.ty));
             assert!(!layout.ty.has_erasable_regions());
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_data_structures/src/sorted_map/index_map.rs b/compiler/rustc_data_structures/src/sorted_map/index_map.rs
index 1654867739f..b38b09d60eb 100644
--- a/compiler/rustc_data_structures/src/sorted_map/index_map.rs
+++ b/compiler/rustc_data_structures/src/sorted_map/index_map.rs
@@ -147,7 +147,7 @@ impl<I: Idx, K: Ord, V> FromIterator<(K, V)> for SortedIndexMultiMap<I, K, V> {
     where
         J: IntoIterator<Item = (K, V)>,
     {
-        let items = IndexVec::from_iter(iter);
+        let items = IndexVec::<I, _>::from_iter(iter);
         let mut idx_sorted_by_item_key: Vec<_> = items.indices().collect();
 
         // `sort_by_key` is stable, so insertion order is preserved for duplicate items.
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/arg_matrix.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
index 358bc389bd1..f6298adf2eb 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
@@ -22,6 +22,12 @@ impl ExpectedIdx {
     }
 }
 
+impl ProvidedIdx {
+    pub(crate) fn to_expected_idx(self) -> ExpectedIdx {
+        ExpectedIdx::from_u32(self.as_u32())
+    }
+}
+
 // An issue that might be found in the compatibility matrix
 #[derive(Debug)]
 enum Issue {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 120a43576e8..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);
         }
     }
 
@@ -775,7 +776,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // First, check if we just need to wrap some arguments in a tuple.
         if let Some((mismatch_idx, terr)) =
-            compatibility_diagonal.iter().enumerate().find_map(|(i, c)| {
+            compatibility_diagonal.iter_enumerated().find_map(|(i, c)| {
                 if let Compatibility::Incompatible(Some(terr)) = c {
                     Some((i, *terr))
                 } else {
@@ -787,24 +788,25 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // Do we have as many extra provided arguments as the tuple's length?
             // If so, we might have just forgotten to wrap some args in a tuple.
             if let Some(ty::Tuple(tys)) =
-                formal_and_expected_inputs.get(mismatch_idx.into()).map(|tys| tys.1.kind())
+                formal_and_expected_inputs.get(mismatch_idx.to_expected_idx()).map(|tys| tys.1.kind())
                 // If the tuple is unit, we're not actually wrapping any arguments.
                 && !tys.is_empty()
                 && provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len()
             {
                 // Wrap up the N provided arguments starting at this position in a tuple.
-                let provided_as_tuple = Ty::new_tup_from_iter(
-                    tcx,
-                    provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx).take(tys.len()),
-                );
+                let provided_args_to_tuple = &provided_arg_tys[mismatch_idx..];
+                let (provided_args_to_tuple, provided_args_after_tuple) =
+                    provided_args_to_tuple.split_at(tys.len());
+                let provided_as_tuple =
+                    Ty::new_tup_from_iter(tcx, provided_args_to_tuple.iter().map(|&(ty, _)| ty));
 
                 let mut satisfied = true;
                 // Check if the newly wrapped tuple + rest of the arguments are compatible.
                 for ((_, expected_ty), provided_ty) in std::iter::zip(
-                    formal_and_expected_inputs.iter().skip(mismatch_idx),
-                    [provided_as_tuple].into_iter().chain(
-                        provided_arg_tys.iter().map(|(ty, _)| *ty).skip(mismatch_idx + tys.len()),
-                    ),
+                    formal_and_expected_inputs[mismatch_idx.to_expected_idx()..].iter(),
+                    [provided_as_tuple]
+                        .into_iter()
+                        .chain(provided_args_after_tuple.iter().map(|&(ty, _)| ty)),
                 ) {
                     if !self.may_coerce(provided_ty, *expected_ty) {
                         satisfied = false;
@@ -816,10 +818,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // Take some care with spans, so we don't suggest wrapping a macro's
                 // innards in parenthesis, for example.
                 if satisfied
-                    && let Some((_, lo)) =
-                        provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx))
-                    && let Some((_, hi)) =
-                        provided_arg_tys.get(ProvidedIdx::from_usize(mismatch_idx + tys.len() - 1))
+                    && let &[(_, hi @ lo)] | &[(_, lo), .., (_, hi)] = provided_args_to_tuple
                 {
                     let mut err;
                     if tys.len() == 1 {
@@ -827,9 +826,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         // so don't do anything special here.
                         err = self.err_ctxt().report_and_explain_type_error(
                             mk_trace(
-                                *lo,
-                                formal_and_expected_inputs[mismatch_idx.into()],
-                                provided_arg_tys[mismatch_idx.into()].0,
+                                lo,
+                                formal_and_expected_inputs[mismatch_idx.to_expected_idx()],
+                                provided_arg_tys[mismatch_idx].0,
                             ),
                             self.param_env,
                             terr,
@@ -868,7 +867,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         callee_ty,
                         call_expr,
                         None,
-                        Some(mismatch_idx),
+                        Some(mismatch_idx.as_usize()),
                         &matched_inputs,
                         &formal_and_expected_inputs,
                         is_method,
@@ -2615,7 +2614,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
 
                 let expected_display_type = self
-                    .resolve_vars_if_possible(formal_and_expected_inputs[idx.into()].1)
+                    .resolve_vars_if_possible(formal_and_expected_inputs[idx].1)
                     .sort_string(self.tcx);
                 let label = if idxs_matched == params_with_generics.len() - 1 {
                     format!(
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_index/src/idx.rs b/compiler/rustc_index/src/idx.rs
index b85160540d8..33f406e2113 100644
--- a/compiler/rustc_index/src/idx.rs
+++ b/compiler/rustc_index/src/idx.rs
@@ -1,5 +1,7 @@
 use std::fmt::Debug;
 use std::hash::Hash;
+use std::ops;
+use std::slice::SliceIndex;
 
 /// Represents some newtyped `usize` wrapper.
 ///
@@ -43,3 +45,92 @@ impl Idx for u32 {
         self as usize
     }
 }
+
+/// Helper trait for indexing operations with a custom index type.
+pub trait IntoSliceIdx<I, T: ?Sized> {
+    type Output: SliceIndex<T>;
+    fn into_slice_idx(self) -> Self::Output;
+}
+
+impl<I: Idx, T> IntoSliceIdx<I, [T]> for I {
+    type Output = usize;
+    #[inline]
+    fn into_slice_idx(self) -> Self::Output {
+        self.index()
+    }
+}
+
+impl<I, T> IntoSliceIdx<I, [T]> for ops::RangeFull {
+    type Output = ops::RangeFull;
+    #[inline]
+    fn into_slice_idx(self) -> Self::Output {
+        self
+    }
+}
+
+impl<I: Idx, T> IntoSliceIdx<I, [T]> for ops::Range<I> {
+    type Output = ops::Range<usize>;
+    #[inline]
+    fn into_slice_idx(self) -> Self::Output {
+        ops::Range { start: self.start.index(), end: self.end.index() }
+    }
+}
+
+impl<I: Idx, T> IntoSliceIdx<I, [T]> for ops::RangeFrom<I> {
+    type Output = ops::RangeFrom<usize>;
+    #[inline]
+    fn into_slice_idx(self) -> Self::Output {
+        ops::RangeFrom { start: self.start.index() }
+    }
+}
+
+impl<I: Idx, T> IntoSliceIdx<I, [T]> for ops::RangeTo<I> {
+    type Output = ops::RangeTo<usize>;
+    #[inline]
+    fn into_slice_idx(self) -> Self::Output {
+        ..self.end.index()
+    }
+}
+
+impl<I: Idx, T> IntoSliceIdx<I, [T]> for ops::RangeInclusive<I> {
+    type Output = ops::RangeInclusive<usize>;
+    #[inline]
+    fn into_slice_idx(self) -> Self::Output {
+        ops::RangeInclusive::new(self.start().index(), self.end().index())
+    }
+}
+
+impl<I: Idx, T> IntoSliceIdx<I, [T]> for ops::RangeToInclusive<I> {
+    type Output = ops::RangeToInclusive<usize>;
+    #[inline]
+    fn into_slice_idx(self) -> Self::Output {
+        ..=self.end.index()
+    }
+}
+
+#[cfg(feature = "nightly")]
+impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::Range<I> {
+    type Output = core::range::Range<usize>;
+    #[inline]
+    fn into_slice_idx(self) -> Self::Output {
+        core::range::Range { start: self.start.index(), end: self.end.index() }
+    }
+}
+
+#[cfg(feature = "nightly")]
+impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::RangeFrom<I> {
+    type Output = core::range::RangeFrom<usize>;
+    #[inline]
+    fn into_slice_idx(self) -> Self::Output {
+        core::range::RangeFrom { start: self.start.index() }
+    }
+}
+
+#[cfg(feature = "nightly")]
+impl<I: Idx, T> IntoSliceIdx<I, [T]> for core::range::RangeInclusive<I> {
+    type Output = core::range::RangeInclusive<usize>;
+    #[inline]
+    fn into_slice_idx(self) -> Self::Output {
+        core::range::RangeInclusive { start: self.start.index(), end: self.end.index() }
+    }
+}
diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs
index cae55230b06..3441a5f65c7 100644
--- a/compiler/rustc_index/src/lib.rs
+++ b/compiler/rustc_index/src/lib.rs
@@ -2,6 +2,7 @@
 #![cfg_attr(all(feature = "nightly", test), feature(stmt_expr_attributes))]
 #![cfg_attr(feature = "nightly", allow(internal_features))]
 #![cfg_attr(feature = "nightly", feature(extend_one, step_trait, test))]
+#![cfg_attr(feature = "nightly", feature(new_range_api))]
 #![cfg_attr(feature = "nightly", feature(new_zeroed_alloc))]
 #![warn(unreachable_pub)]
 // tidy-alphabetical-end
@@ -14,7 +15,7 @@ mod idx;
 mod slice;
 mod vec;
 
-pub use idx::Idx;
+pub use idx::{Idx, IntoSliceIdx};
 pub use rustc_index_macros::newtype_index;
 pub use slice::IndexSlice;
 #[doc(no_inline)]
diff --git a/compiler/rustc_index/src/slice.rs b/compiler/rustc_index/src/slice.rs
index 4636f294f13..f17ea9e4b59 100644
--- a/compiler/rustc_index/src/slice.rs
+++ b/compiler/rustc_index/src/slice.rs
@@ -1,8 +1,9 @@
+use std::fmt;
 use std::marker::PhantomData;
 use std::ops::{Index, IndexMut};
-use std::{fmt, slice};
+use std::slice::{self, SliceIndex};
 
-use crate::{Idx, IndexVec};
+use crate::{Idx, IndexVec, IntoSliceIdx};
 
 /// A view into contiguous `T`s, indexed by `I` rather than by `usize`.
 ///
@@ -97,13 +98,19 @@ impl<I: Idx, T> IndexSlice<I, T> {
     }
 
     #[inline]
-    pub fn get(&self, index: I) -> Option<&T> {
-        self.raw.get(index.index())
+    pub fn get<R: IntoSliceIdx<I, [T]>>(
+        &self,
+        index: R,
+    ) -> Option<&<R::Output as SliceIndex<[T]>>::Output> {
+        self.raw.get(index.into_slice_idx())
     }
 
     #[inline]
-    pub fn get_mut(&mut self, index: I) -> Option<&mut T> {
-        self.raw.get_mut(index.index())
+    pub fn get_mut<R: IntoSliceIdx<I, [T]>>(
+        &mut self,
+        index: R,
+    ) -> Option<&mut <R::Output as SliceIndex<[T]>>::Output> {
+        self.raw.get_mut(index.into_slice_idx())
     }
 
     /// Returns mutable references to two distinct elements, `a` and `b`.
@@ -184,19 +191,19 @@ impl<I: Idx, T: fmt::Debug> fmt::Debug for IndexSlice<I, T> {
     }
 }
 
-impl<I: Idx, T> Index<I> for IndexSlice<I, T> {
-    type Output = T;
+impl<I: Idx, T, R: IntoSliceIdx<I, [T]>> Index<R> for IndexSlice<I, T> {
+    type Output = <R::Output as SliceIndex<[T]>>::Output;
 
     #[inline]
-    fn index(&self, index: I) -> &T {
-        &self.raw[index.index()]
+    fn index(&self, index: R) -> &Self::Output {
+        &self.raw[index.into_slice_idx()]
     }
 }
 
-impl<I: Idx, T> IndexMut<I> for IndexSlice<I, T> {
+impl<I: Idx, T, R: IntoSliceIdx<I, [T]>> IndexMut<R> for IndexSlice<I, T> {
     #[inline]
-    fn index_mut(&mut self, index: I) -> &mut T {
-        &mut self.raw[index.index()]
+    fn index_mut(&mut self, index: R) -> &mut Self::Output {
+        &mut self.raw[index.into_slice_idx()]
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index e454a88e847..03c4614af13 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -160,7 +160,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
     /// empty region. The `expansion` phase will grow this larger.
     fn construct_var_data(&self) -> LexicalRegionResolutions<'tcx> {
         LexicalRegionResolutions {
-            values: IndexVec::from_fn_n(
+            values: IndexVec::<RegionVid, _>::from_fn_n(
                 |vid| {
                     let vid_universe = self.var_infos[vid].universe;
                     VarValue::Empty(vid_universe)
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/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index cf90df1b198..ea0bb5feb12 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -96,6 +96,17 @@ impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> {
 }
 
 impl MirPhase {
+    pub fn name(&self) -> &'static str {
+        match *self {
+            MirPhase::Built => "built",
+            MirPhase::Analysis(AnalysisPhase::Initial) => "analysis",
+            MirPhase::Analysis(AnalysisPhase::PostCleanup) => "analysis-post-cleanup",
+            MirPhase::Runtime(RuntimePhase::Initial) => "runtime",
+            MirPhase::Runtime(RuntimePhase::PostCleanup) => "runtime-post-cleanup",
+            MirPhase::Runtime(RuntimePhase::Optimized) => "runtime-optimized",
+        }
+    }
+
     /// Gets the (dialect, phase) index of the current `MirPhase`. Both numbers
     /// are 1-indexed.
     pub fn index(&self) -> (usize, usize) {
diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs
index 595a5e548b0..f05a798949b 100644
--- a/compiler/rustc_middle/src/mir/statement.rs
+++ b/compiler/rustc_middle/src/mir/statement.rs
@@ -25,6 +25,26 @@ impl Statement<'_> {
 }
 
 impl<'tcx> StatementKind<'tcx> {
+    /// Returns a simple string representation of a `StatementKind` variant, independent of any
+    /// values it might hold (e.g. `StatementKind::Assign` always returns `"Assign"`).
+    pub const fn name(&self) -> &'static str {
+        match self {
+            StatementKind::Assign(..) => "Assign",
+            StatementKind::FakeRead(..) => "FakeRead",
+            StatementKind::SetDiscriminant { .. } => "SetDiscriminant",
+            StatementKind::Deinit(..) => "Deinit",
+            StatementKind::StorageLive(..) => "StorageLive",
+            StatementKind::StorageDead(..) => "StorageDead",
+            StatementKind::Retag(..) => "Retag",
+            StatementKind::PlaceMention(..) => "PlaceMention",
+            StatementKind::AscribeUserType(..) => "AscribeUserType",
+            StatementKind::Coverage(..) => "Coverage",
+            StatementKind::Intrinsic(..) => "Intrinsic",
+            StatementKind::ConstEvalCounter => "ConstEvalCounter",
+            StatementKind::Nop => "Nop",
+            StatementKind::BackwardIncompatibleDropHint { .. } => "BackwardIncompatibleDropHint",
+        }
+    }
     pub fn as_assign_mut(&mut self) -> Option<&mut (Place<'tcx>, Rvalue<'tcx>)> {
         match self {
             StatementKind::Assign(x) => Some(x),
@@ -862,3 +882,40 @@ impl<'tcx> BinOp {
         })
     }
 }
+
+impl From<Mutability> for RawPtrKind {
+    fn from(other: Mutability) -> Self {
+        match other {
+            Mutability::Mut => RawPtrKind::Mut,
+            Mutability::Not => RawPtrKind::Const,
+        }
+    }
+}
+
+impl RawPtrKind {
+    pub fn is_fake(self) -> bool {
+        match self {
+            RawPtrKind::Mut | RawPtrKind::Const => false,
+            RawPtrKind::FakeForPtrMetadata => true,
+        }
+    }
+
+    pub fn to_mutbl_lossy(self) -> Mutability {
+        match self {
+            RawPtrKind::Mut => Mutability::Mut,
+            RawPtrKind::Const => Mutability::Not,
+
+            // We have no type corresponding to a fake borrow, so use
+            // `*const` as an approximation.
+            RawPtrKind::FakeForPtrMetadata => Mutability::Not,
+        }
+    }
+
+    pub fn ptr_str(self) -> &'static str {
+        match self {
+            RawPtrKind::Mut => "mut",
+            RawPtrKind::Const => "const",
+            RawPtrKind::FakeForPtrMetadata => "const (fake)",
+        }
+    }
+}
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index af6f0e4c551..4f86703e953 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -97,19 +97,6 @@ pub enum MirPhase {
     Runtime(RuntimePhase),
 }
 
-impl MirPhase {
-    pub fn name(&self) -> &'static str {
-        match *self {
-            MirPhase::Built => "built",
-            MirPhase::Analysis(AnalysisPhase::Initial) => "analysis",
-            MirPhase::Analysis(AnalysisPhase::PostCleanup) => "analysis-post-cleanup",
-            MirPhase::Runtime(RuntimePhase::Initial) => "runtime",
-            MirPhase::Runtime(RuntimePhase::PostCleanup) => "runtime-post-cleanup",
-            MirPhase::Runtime(RuntimePhase::Optimized) => "runtime-optimized",
-        }
-    }
-}
-
 /// See [`MirPhase::Analysis`].
 #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, PartialOrd, Ord)]
 #[derive(HashStable)]
@@ -206,43 +193,6 @@ pub enum RawPtrKind {
     FakeForPtrMetadata,
 }
 
-impl From<Mutability> for RawPtrKind {
-    fn from(other: Mutability) -> Self {
-        match other {
-            Mutability::Mut => RawPtrKind::Mut,
-            Mutability::Not => RawPtrKind::Const,
-        }
-    }
-}
-
-impl RawPtrKind {
-    pub fn is_fake(self) -> bool {
-        match self {
-            RawPtrKind::Mut | RawPtrKind::Const => false,
-            RawPtrKind::FakeForPtrMetadata => true,
-        }
-    }
-
-    pub fn to_mutbl_lossy(self) -> Mutability {
-        match self {
-            RawPtrKind::Mut => Mutability::Mut,
-            RawPtrKind::Const => Mutability::Not,
-
-            // We have no type corresponding to a fake borrow, so use
-            // `*const` as an approximation.
-            RawPtrKind::FakeForPtrMetadata => Mutability::Not,
-        }
-    }
-
-    pub fn ptr_str(self) -> &'static str {
-        match self {
-            RawPtrKind::Mut => "mut",
-            RawPtrKind::Const => "const",
-            RawPtrKind::FakeForPtrMetadata => "const (fake)",
-        }
-    }
-}
-
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, TyEncodable, TyDecodable)]
 #[derive(Hash, HashStable)]
 pub enum MutBorrowKind {
@@ -515,29 +465,6 @@ pub enum StatementKind<'tcx> {
     },
 }
 
-impl StatementKind<'_> {
-    /// Returns a simple string representation of a `StatementKind` variant, independent of any
-    /// values it might hold (e.g. `StatementKind::Assign` always returns `"Assign"`).
-    pub const fn name(&self) -> &'static str {
-        match self {
-            StatementKind::Assign(..) => "Assign",
-            StatementKind::FakeRead(..) => "FakeRead",
-            StatementKind::SetDiscriminant { .. } => "SetDiscriminant",
-            StatementKind::Deinit(..) => "Deinit",
-            StatementKind::StorageLive(..) => "StorageLive",
-            StatementKind::StorageDead(..) => "StorageDead",
-            StatementKind::Retag(..) => "Retag",
-            StatementKind::PlaceMention(..) => "PlaceMention",
-            StatementKind::AscribeUserType(..) => "AscribeUserType",
-            StatementKind::Coverage(..) => "Coverage",
-            StatementKind::Intrinsic(..) => "Intrinsic",
-            StatementKind::ConstEvalCounter => "ConstEvalCounter",
-            StatementKind::Nop => "Nop",
-            StatementKind::BackwardIncompatibleDropHint { .. } => "BackwardIncompatibleDropHint",
-        }
-    }
-}
-
 #[derive(
     Clone,
     TyEncodable,
@@ -673,12 +600,6 @@ pub enum CallSource {
     Normal,
 }
 
-impl CallSource {
-    pub fn from_hir_call(self) -> bool {
-        matches!(self, CallSource::Normal)
-    }
-}
-
 #[derive(Clone, Copy, Debug, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
 #[derive(TypeFoldable, TypeVisitable)]
 /// The macro that an inline assembly block was created by
@@ -689,15 +610,6 @@ pub enum InlineAsmMacro {
     NakedAsm,
 }
 
-impl InlineAsmMacro {
-    pub const fn diverges(self, options: InlineAsmOptions) -> bool {
-        match self {
-            InlineAsmMacro::Asm => options.contains(InlineAsmOptions::NORETURN),
-            InlineAsmMacro::NakedAsm => true,
-        }
-    }
-}
-
 ///////////////////////////////////////////////////////////////////////////
 // Terminators
 
@@ -999,30 +911,6 @@ pub enum BackwardIncompatibleDropReason {
     Edition2024,
 }
 
-impl TerminatorKind<'_> {
-    /// Returns a simple string representation of a `TerminatorKind` variant, independent of any
-    /// values it might hold (e.g. `TerminatorKind::Call` always returns `"Call"`).
-    pub const fn name(&self) -> &'static str {
-        match self {
-            TerminatorKind::Goto { .. } => "Goto",
-            TerminatorKind::SwitchInt { .. } => "SwitchInt",
-            TerminatorKind::UnwindResume => "UnwindResume",
-            TerminatorKind::UnwindTerminate(_) => "UnwindTerminate",
-            TerminatorKind::Return => "Return",
-            TerminatorKind::Unreachable => "Unreachable",
-            TerminatorKind::Drop { .. } => "Drop",
-            TerminatorKind::Call { .. } => "Call",
-            TerminatorKind::TailCall { .. } => "TailCall",
-            TerminatorKind::Assert { .. } => "Assert",
-            TerminatorKind::Yield { .. } => "Yield",
-            TerminatorKind::CoroutineDrop => "CoroutineDrop",
-            TerminatorKind::FalseEdge { .. } => "FalseEdge",
-            TerminatorKind::FalseUnwind { .. } => "FalseUnwind",
-            TerminatorKind::InlineAsm { .. } => "InlineAsm",
-        }
-    }
-}
-
 #[derive(Debug, Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
 pub struct SwitchTargets {
     /// Possible values. For each value, the location to branch to is found in
diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs
index fdfcb128778..b887370fd69 100644
--- a/compiler/rustc_middle/src/mir/terminator.rs
+++ b/compiler/rustc_middle/src/mir/terminator.rs
@@ -2,12 +2,13 @@
 
 use std::slice;
 
+use rustc_ast::InlineAsmOptions;
 use rustc_data_structures::packed::Pu128;
 use rustc_hir::LangItem;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
 use smallvec::{SmallVec, smallvec};
 
-use super::{TerminatorKind, *};
+use super::*;
 
 impl SwitchTargets {
     /// Creates switch targets from an iterator of values and target blocks.
@@ -414,6 +415,28 @@ impl<'tcx> Terminator<'tcx> {
 }
 
 impl<'tcx> TerminatorKind<'tcx> {
+    /// Returns a simple string representation of a `TerminatorKind` variant, independent of any
+    /// values it might hold (e.g. `TerminatorKind::Call` always returns `"Call"`).
+    pub const fn name(&self) -> &'static str {
+        match self {
+            TerminatorKind::Goto { .. } => "Goto",
+            TerminatorKind::SwitchInt { .. } => "SwitchInt",
+            TerminatorKind::UnwindResume => "UnwindResume",
+            TerminatorKind::UnwindTerminate(_) => "UnwindTerminate",
+            TerminatorKind::Return => "Return",
+            TerminatorKind::Unreachable => "Unreachable",
+            TerminatorKind::Drop { .. } => "Drop",
+            TerminatorKind::Call { .. } => "Call",
+            TerminatorKind::TailCall { .. } => "TailCall",
+            TerminatorKind::Assert { .. } => "Assert",
+            TerminatorKind::Yield { .. } => "Yield",
+            TerminatorKind::CoroutineDrop => "CoroutineDrop",
+            TerminatorKind::FalseEdge { .. } => "FalseEdge",
+            TerminatorKind::FalseUnwind { .. } => "FalseUnwind",
+            TerminatorKind::InlineAsm { .. } => "InlineAsm",
+        }
+    }
+
     #[inline]
     pub fn if_(cond: Operand<'tcx>, t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> {
         TerminatorKind::SwitchInt { discr: cond, targets: SwitchTargets::static_if(0, f, t) }
@@ -698,3 +721,18 @@ impl<'tcx> TerminatorKind<'tcx> {
         }
     }
 }
+
+impl CallSource {
+    pub fn from_hir_call(self) -> bool {
+        matches!(self, CallSource::Normal)
+    }
+}
+
+impl InlineAsmMacro {
+    pub const fn diverges(self, options: InlineAsmOptions) -> bool {
+        match self {
+            InlineAsmMacro::Asm => options.contains(InlineAsmOptions::NORETURN),
+            InlineAsmMacro::NakedAsm => true,
+        }
+    }
+}
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 8ed5a118093..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};
@@ -47,7 +48,7 @@ pub use rustc_session::lint::RegisteredTools;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::{ExpnId, ExpnKind, Ident, Span, Symbol, kw, sym};
 pub use rustc_type_ir::relate::VarianceDiagInfo;
-pub use rustc_type_ir::{Movability, Mutability, *};
+pub use rustc_type_ir::*;
 use tracing::{debug, instrument};
 pub use vtable::*;
 use {rustc_ast as ast, rustc_attr_parsing as attr, rustc_hir as hir};
@@ -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_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
index ee331713736..10b43390eb2 100644
--- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
@@ -1,7 +1,7 @@
 use std::sync::Arc;
 
 use rustc_middle::mir::*;
-use rustc_middle::thir::{self, *};
+use rustc_middle::thir::*;
 use rustc_middle::ty::{self, Ty, TypeVisitableExt};
 
 use crate::builder::Builder;
@@ -134,7 +134,7 @@ impl<'tcx> MatchPairTree<'tcx> {
             PatKind::Constant { value } => TestCase::Constant { value },
 
             PatKind::AscribeUserType {
-                ascription: thir::Ascription { ref annotation, variance },
+                ascription: Ascription { ref annotation, variance },
                 ref subpattern,
                 ..
             } => {
diff --git a/compiler/rustc_mir_transform/src/check_pointers.rs b/compiler/rustc_mir_transform/src/check_pointers.rs
index d693f739180..2d04b621935 100644
--- a/compiler/rustc_mir_transform/src/check_pointers.rs
+++ b/compiler/rustc_mir_transform/src/check_pointers.rs
@@ -71,8 +71,7 @@ pub(crate) fn check_pointers<'tcx, F>(
     // statements/blocks after. Iterating or visiting the MIR in order would require updating
     // our current location after every insertion. By iterating backwards, we dodge this issue:
     // The only Locations that an insertion changes have already been handled.
-    for block in (0..basic_blocks.len()).rev() {
-        let block = block.into();
+    for block in basic_blocks.indices().rev() {
         for statement_index in (0..basic_blocks[block].statements.len()).rev() {
             let location = Location { block, statement_index };
             let statement = &basic_blocks[block].statements[statement_index];
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index 039f346495b..5568d42ab8f 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -50,7 +50,7 @@ fn make_node_flow_priority_list(
     // A "reloop" node has exactly one out-edge, which jumps back to the top
     // of an enclosing loop. Reloop nodes are typically visited more times
     // than loop-exit nodes, so try to avoid giving them physical counters.
-    let is_reloop_node = IndexVec::from_fn_n(
+    let is_reloop_node = IndexVec::<BasicCoverageBlock, _>::from_fn_n(
         |node| match graph.successors[node].as_slice() {
             &[succ] => graph.dominates(succ, node),
             _ => false,
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index 09384defea8..dcc7c5b91d7 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -42,7 +42,7 @@ impl CoverageGraph {
         // `SwitchInt` to have multiple targets to the same destination `BasicBlock`, so
         // de-duplication is required. This is done without reordering the successors.
 
-        let successors = IndexVec::from_fn_n(
+        let successors = IndexVec::<BasicCoverageBlock, _>::from_fn_n(
             |bcb| {
                 let mut seen_bcbs = FxHashSet::default();
                 let terminator = mir_body[bcbs[bcb].last_bb()].terminator();
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_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 2f8a3050199..29521d42720 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -1259,7 +1259,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
 
         let layout = self.ecx.layout_of(lhs_ty).ok()?;
 
-        let as_bits = |value| {
+        let as_bits = |value: VnIndex| {
             let constant = self.evaluated[value].as_ref()?;
             if layout.backend_repr.is_scalar() {
                 let scalar = self.ecx.read_scalar(constant).discard_err()?;
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/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 74221e21687..7d99aaa1731 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -1352,11 +1352,11 @@ macro_rules! int_impl {
         ///
         /// Basic usage:
         /// ```
-        /// #![feature(unbounded_shifts)]
         #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(4), 0x10);")]
         #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(129), 0);")]
         /// ```
-        #[unstable(feature = "unbounded_shifts", issue = "129375")]
+        #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -1474,12 +1474,12 @@ macro_rules! int_impl {
         ///
         /// Basic usage:
         /// ```
-        /// #![feature(unbounded_shifts)]
         #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(4), 0x1);")]
         #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(129), 0);")]
         #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.unbounded_shr(129), -1);")]
         /// ```
-        #[unstable(feature = "unbounded_shifts", issue = "129375")]
+        #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 2682273b7f1..405c71121ca 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -1613,11 +1613,11 @@ macro_rules! uint_impl {
         ///
         /// Basic usage:
         /// ```
-        /// #![feature(unbounded_shifts)]
         #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(4), 0x10);")]
         #[doc = concat!("assert_eq!(0x1", stringify!($SelfT), ".unbounded_shl(129), 0);")]
         /// ```
-        #[unstable(feature = "unbounded_shifts", issue = "129375")]
+        #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
@@ -1734,11 +1734,11 @@ macro_rules! uint_impl {
         ///
         /// Basic usage:
         /// ```
-        /// #![feature(unbounded_shifts)]
         #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(4), 0x1);")]
         #[doc = concat!("assert_eq!(0x10", stringify!($SelfT), ".unbounded_shr(129), 0);")]
         /// ```
-        #[unstable(feature = "unbounded_shifts", issue = "129375")]
+        #[stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")]
+        #[rustc_const_stable(feature = "unbounded_shifts", since = "CURRENT_RUSTC_VERSION")]
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs
index c8fcee5c140..8993e14fcd3 100644
--- a/library/core/src/ops/control_flow.rs
+++ b/library/core/src/ops/control_flow.rs
@@ -229,6 +229,27 @@ impl<B, C> ControlFlow<B, C> {
     }
 }
 
+impl<T> ControlFlow<T, T> {
+    /// Extracts the value `T` that is wrapped by `ControlFlow<T, T>`.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(control_flow_into_value)]
+    /// use std::ops::ControlFlow;
+    ///
+    /// assert_eq!(ControlFlow::<i32, i32>::Break(1024).into_value(), 1024);
+    /// assert_eq!(ControlFlow::<i32, i32>::Continue(512).into_value(), 512);
+    /// ```
+    #[unstable(feature = "control_flow_into_value", issue = "137461")]
+    #[rustc_allow_const_fn_unstable(const_precise_live_drops)]
+    pub const fn into_value(self) -> T {
+        match self {
+            ControlFlow::Continue(x) | ControlFlow::Break(x) => x,
+        }
+    }
+}
+
 /// These are used only as part of implementing the iterator adapters.
 /// They have mediocre names and non-obvious semantics, so aren't
 /// currently on a path to potential stabilization.
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 471150cfd96..d47af93c160 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -2928,10 +2928,17 @@ impl<T> [T] {
     /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not
     /// allocate), and *O*(*n* \* log(*n*)) worst-case.
     ///
-    /// If the implementation of [`Ord`] for `T` does not implement a [total order] the resulting
-    /// order of elements in the slice is unspecified. All original elements will remain in the
-    /// slice and any possible modifications via interior mutability are observed in the input. Same
-    /// is true if the implementation of [`Ord`] for `T` panics.
+    /// If the implementation of [`Ord`] for `T` does not implement a [total order], the function
+    /// may panic; even if the function exits normally, the resulting order of elements in the slice
+    /// is unspecified. See also the note on panicking below.
+    ///
+    /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor
+    /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and
+    /// examples see the [`Ord`] documentation.
+    ///
+    ///
+    /// All original elements will remain in the slice and any possible modifications via interior
+    /// mutability are observed in the input. Same is true if the implementation of [`Ord`] for `T` panics.
     ///
     /// Sorting types that only implement [`PartialOrd`] such as [`f32`] and [`f64`] require
     /// additional precautions. For example, `f32::NAN != f32::NAN`, which doesn't fulfill the
@@ -2954,7 +2961,8 @@ impl<T> [T] {
     ///
     /// # Panics
     ///
-    /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order].
+    /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order], or if
+    /// the [`Ord`] implementation panics.
     ///
     /// # Examples
     ///
@@ -2982,15 +2990,17 @@ impl<T> [T] {
     /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not
     /// allocate), and *O*(*n* \* log(*n*)) worst-case.
     ///
-    /// If the comparison function `compare` does not implement a [total order] the resulting order
-    /// of elements in the slice is unspecified. All original elements will remain in the slice and
-    /// any possible modifications via interior mutability are observed in the input. Same is true
-    /// if `compare` panics.
+    /// If the comparison function `compare` does not implement a [total order], the function
+    /// may panic; even if the function exits normally, the resulting order of elements in the slice
+    /// is unspecified. See also the note on panicking below.
     ///
     /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor
     /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and
     /// examples see the [`Ord`] documentation.
     ///
+    /// All original elements will remain in the slice and any possible modifications via interior
+    /// mutability are observed in the input. Same is true if `compare` panics.
+    ///
     /// # Current implementation
     ///
     /// The current implementation is based on [ipnsort] by Lukas Bergdoll and Orson Peters, which
@@ -3003,7 +3013,8 @@ impl<T> [T] {
     ///
     /// # Panics
     ///
-    /// May panic if `compare` does not implement a [total order].
+    /// May panic if the `compare` does not implement a [total order], or if
+    /// the `compare` itself panics.
     ///
     /// # Examples
     ///
@@ -3034,10 +3045,16 @@ impl<T> [T] {
     /// This sort is unstable (i.e., may reorder equal elements), in-place (i.e., does not
     /// allocate), and *O*(*n* \* log(*n*)) worst-case.
     ///
-    /// If the implementation of [`Ord`] for `K` does not implement a [total order] the resulting
-    /// order of elements in the slice is unspecified. All original elements will remain in the
-    /// slice and any possible modifications via interior mutability are observed in the input. Same
-    /// is true if the implementation of [`Ord`] for `K` panics.
+    /// If the implementation of [`Ord`] for `K` does not implement a [total order], the function
+    /// may panic; even if the function exits normally, the resulting order of elements in the slice
+    /// is unspecified. See also the note on panicking below.
+    ///
+    /// For example `|a, b| (a - b).cmp(a)` is a comparison function that is neither transitive nor
+    /// reflexive nor total, `a < b < c < a` with `a = 1, b = 2, c = 3`. For more information and
+    /// examples see the [`Ord`] documentation.
+    ///
+    /// All original elements will remain in the slice and any possible modifications via interior
+    /// mutability are observed in the input. Same is true if the implementation of [`Ord`] for `K` panics.
     ///
     /// # Current implementation
     ///
@@ -3051,7 +3068,8 @@ impl<T> [T] {
     ///
     /// # Panics
     ///
-    /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order].
+    /// May panic if the implementation of [`Ord`] for `K` does not implement a [total order], or if
+    /// the [`Ord`] implementation panics.
     ///
     /// # Examples
     ///
diff --git a/library/coretests/tests/num/int_macros.rs b/library/coretests/tests/num/int_macros.rs
index 392704e7509..bbf19d2b444 100644
--- a/library/coretests/tests/num/int_macros.rs
+++ b/library/coretests/tests/num/int_macros.rs
@@ -512,5 +512,169 @@ macro_rules! int_module {
                 assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MAX), <$T>::MAX / 2 + 3);
             }
         }
+
+        // test_unbounded_sh* constants
+        const SHIFT_AMOUNT_OVERFLOW: u32 = <$T>::BITS;
+        const SHIFT_AMOUNT_OVERFLOW2: u32 = <$T>::BITS + 3;
+        const SHIFT_AMOUNT_OVERFLOW3: u32 = <$T>::BITS << 2;
+
+        const SHIFT_AMOUNT_TEST_ONE: u32 = <$T>::BITS >> 1;
+        const SHIFT_AMOUNT_TEST_TWO: u32 = <$T>::BITS >> 3;
+        const SHIFT_AMOUNT_TEST_THREE: u32 = (<$T>::BITS >> 1) - 1;
+        const SHIFT_AMOUNT_TEST_FOUR: u32 = <$T>::BITS - 1;
+
+        test_runtime_and_compiletime! {
+            fn test_unbounded_shl() {
+                // <$T>::MIN
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN << SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 1), (<$T>::MIN << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 3), (<$T>::MIN << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 5), (<$T>::MIN << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // <$T>::MAX
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX << SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 1), (<$T>::MAX << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 3), (<$T>::MAX << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 5), (<$T>::MAX << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // 1
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_ONE), (1 << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_TWO), (1 << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_THREE), (1 << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_FOUR), (1 << SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, 1), (1 << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, 3), (1 << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, 5), (1 << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // -1
+                assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_ONE), (-1 << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_TWO), (-1 << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_THREE), (-1 << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_TEST_FOUR), (-1 << SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(-1, 1), (-1 << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(-1, 3), (-1 << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(-1, 5), (-1 << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(-1, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // 8
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_ONE), (8 << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_TWO), (8 << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_THREE), (8 << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_FOUR), (8 << SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, 1), (8 << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, 3), (8 << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, 5), (8 << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // 17
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_ONE), (17 << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_TWO), (17 << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_THREE), (17 << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_FOUR), (17 << SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, 1), (17 << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, 3), (17 << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, 5), (17 << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW3), 0);
+            }
+
+            fn test_unbounded_shr() {
+                // <$T>::MIN
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN >> SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 1), (<$T>::MIN >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 3), (<$T>::MIN >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 5), (<$T>::MIN >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), -1);
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), -1);
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), -1);
+
+                // <$T>::MAX
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX >> SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 1), (<$T>::MAX >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 3), (<$T>::MAX >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 5), (<$T>::MAX >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // 1
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_ONE), (1 >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_TWO), (1 >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_THREE), (1 >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_FOUR), (1 >> SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, 1), (1 >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, 3), (1 >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, 5), (1 >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // -1
+                assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_ONE), (-1 >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_TWO), (-1 >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_THREE), (-1 >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_TEST_FOUR), (-1 >> SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(-1, 1), (-1 >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(-1, 3), (-1 >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(-1, 5), (-1 >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW), -1);
+                assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW), -1);
+                assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW2), -1);
+                assert_eq_const_safe!(<$T>::unbounded_shr(-1, SHIFT_AMOUNT_OVERFLOW3), -1);
+
+                // 8
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_ONE), (8 >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_TWO), (8 >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_THREE), (8 >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_FOUR), (8 >> SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, 1), (8 >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, 3), (8 >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, 5), (8 >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // 17
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_ONE), (17 >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_TWO), (17 >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_THREE), (17 >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_FOUR), (17 >> SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, 1), (17 >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, 3), (17 >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, 5), (17 >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW3), 0);
+            }
+        }
     };
 }
diff --git a/library/coretests/tests/num/uint_macros.rs b/library/coretests/tests/num/uint_macros.rs
index c085ba5a249..d09eb97b17e 100644
--- a/library/coretests/tests/num/uint_macros.rs
+++ b/library/coretests/tests/num/uint_macros.rs
@@ -351,5 +351,169 @@ macro_rules! uint_module {
                 assert_eq_const_safe!(<$T>::midpoint(6, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2 + 3);
             }
         }
+
+        // test_unbounded_sh* constants
+        const SHIFT_AMOUNT_OVERFLOW: u32 = <$T>::BITS;
+        const SHIFT_AMOUNT_OVERFLOW2: u32 = <$T>::BITS + 3;
+        const SHIFT_AMOUNT_OVERFLOW3: u32 = <$T>::BITS << 2;
+
+        const SHIFT_AMOUNT_TEST_ONE: u32 = <$T>::BITS >> 1;
+        const SHIFT_AMOUNT_TEST_TWO: u32 = <$T>::BITS >> 3;
+        const SHIFT_AMOUNT_TEST_THREE: u32 = (<$T>::BITS >> 1) - 1;
+        const SHIFT_AMOUNT_TEST_FOUR: u32 = <$T>::BITS - 1;
+
+        test_runtime_and_compiletime! {
+            fn test_unbounded_shl() {
+                // <$T>::MIN
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN << SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 1), (<$T>::MIN << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 3), (<$T>::MIN << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, 5), (<$T>::MIN << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // <$T>::MAX
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX << SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 1), (<$T>::MAX << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 3), (<$T>::MAX << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, 5), (<$T>::MAX << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // 1
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_ONE), (1 << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_TWO), (1 << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_THREE), (1 << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_TEST_FOUR), (1 << SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, 1), (1 << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, 3), (1 << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, 5), (1 << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(1, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // !0
+                assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_ONE), (!0 << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_TWO), (!0 << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_THREE), (!0 << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_TEST_FOUR), (!0 << SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(!0, 1), (!0 << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(!0, 3), (!0 << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(!0, 5), (!0 << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(!0, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // 8
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_ONE), (8 << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_TWO), (8 << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_THREE), (8 << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_TEST_FOUR), (8 << SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, 1), (8 << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, 3), (8 << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, 5), (8 << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(8, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // 17
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_ONE), (17 << SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_TWO), (17 << SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_THREE), (17 << SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_TEST_FOUR), (17 << SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, 1), (17 << 1));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, 3), (17 << 3));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, 5), (17 << 5));
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shl(17, SHIFT_AMOUNT_OVERFLOW3), 0);
+            }
+
+            fn test_unbounded_shr() {
+                // <$T>::MIN
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_ONE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_TWO), (<$T>::MIN >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_THREE), (<$T>::MIN >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MIN >> SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 1), (<$T>::MIN >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 3), (<$T>::MIN >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, 5), (<$T>::MIN >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MIN, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // <$T>::MAX
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_ONE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_TWO), (<$T>::MAX >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_THREE), (<$T>::MAX >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_TEST_FOUR), (<$T>::MAX >> SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 1), (<$T>::MAX >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 3), (<$T>::MAX >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, 5), (<$T>::MAX >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(<$T>::MAX, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // 1
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_ONE), (1 >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_TWO), (1 >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_THREE), (1 >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_TEST_FOUR), (1 >> SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, 1), (1 >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, 3), (1 >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, 5), (1 >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(1, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // !0
+                assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_ONE), (!0 >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_TWO), (!0 >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_THREE), (!0 >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_TEST_FOUR), (!0 >> SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(!0, 1), (!0 >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(!0, 3), (!0 >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(!0, 5), (!0 >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(!0, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // 8
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_ONE), (8 >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_TWO), (8 >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_THREE), (8 >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_TEST_FOUR), (8 >> SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, 1), (8 >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, 3), (8 >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, 5), (8 >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(8, SHIFT_AMOUNT_OVERFLOW3), 0);
+
+                // 17
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_ONE), (17 >> SHIFT_AMOUNT_TEST_ONE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_TWO), (17 >> SHIFT_AMOUNT_TEST_TWO));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_THREE), (17 >> SHIFT_AMOUNT_TEST_THREE));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_TEST_FOUR), (17 >> SHIFT_AMOUNT_TEST_FOUR));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, 1), (17 >> 1));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, 3), (17 >> 3));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, 5), (17 >> 5));
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW2), 0);
+                assert_eq_const_safe!(<$T>::unbounded_shr(17, SHIFT_AMOUNT_OVERFLOW3), 0);
+            }
+        }
     };
 }
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/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs
index 0ddce30cf8e..dce5a429cb0 100644
--- a/library/std/src/sys/pal/windows/fs.rs
+++ b/library/std/src/sys/pal/windows/fs.rs
@@ -1,4 +1,4 @@
-use super::api::{self, WinError};
+use super::api::{self, WinError, set_file_information_by_handle};
 use super::{IoResult, to_u16s};
 use crate::alloc::{alloc, handle_alloc_error};
 use crate::borrow::Cow;
@@ -319,31 +319,17 @@ impl File {
                 && creation == c::OPEN_ALWAYS
                 && api::get_last_error() == WinError::ALREADY_EXISTS
             {
-                unsafe {
-                    // This first tries `FileAllocationInfo` but falls back to
-                    // `FileEndOfFileInfo` in order to support WINE.
-                    // If WINE gains support for FileAllocationInfo, we should
-                    // remove the fallback.
-                    let alloc = c::FILE_ALLOCATION_INFO { AllocationSize: 0 };
-                    let result = c::SetFileInformationByHandle(
-                        handle.as_raw_handle(),
-                        c::FileAllocationInfo,
-                        (&raw const alloc).cast::<c_void>(),
-                        mem::size_of::<c::FILE_ALLOCATION_INFO>() as u32,
-                    );
-                    if result == 0 {
+                // This first tries `FileAllocationInfo` but falls back to
+                // `FileEndOfFileInfo` in order to support WINE.
+                // If WINE gains support for FileAllocationInfo, we should
+                // remove the fallback.
+                let alloc = c::FILE_ALLOCATION_INFO { AllocationSize: 0 };
+                set_file_information_by_handle(handle.as_raw_handle(), &alloc)
+                    .or_else(|_| {
                         let eof = c::FILE_END_OF_FILE_INFO { EndOfFile: 0 };
-                        let result = c::SetFileInformationByHandle(
-                            handle.as_raw_handle(),
-                            c::FileEndOfFileInfo,
-                            (&raw const eof).cast::<c_void>(),
-                            mem::size_of::<c::FILE_END_OF_FILE_INFO>() as u32,
-                        );
-                        if result == 0 {
-                            return Err(io::Error::last_os_error());
-                        }
-                    }
-                }
+                        set_file_information_by_handle(handle.as_raw_handle(), &eof)
+                    })
+                    .io_result()?;
             }
             Ok(File { handle: Handle::from_inner(handle) })
         } else {
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/Cargo.toml b/src/librustdoc/Cargo.toml
index c07cc4dc347..91cc4088788 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -15,6 +15,7 @@ itertools = "0.12"
 indexmap = "2"
 minifier = { version = "0.3.5", default-features = false }
 pulldown-cmark-old = { version = "0.9.6", package = "pulldown-cmark", default-features = false }
+pulldown-cmark-escape = { version = "0.11.0", features = ["simd"] }
 regex = "1"
 rustdoc-json-types = { path = "../rustdoc-json-types" }
 serde_json = "1.0"
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/librustdoc/html/escape.rs b/src/librustdoc/html/escape.rs
index 88654ed32da..ac9e2f42cc6 100644
--- a/src/librustdoc/html/escape.rs
+++ b/src/librustdoc/html/escape.rs
@@ -5,6 +5,7 @@
 
 use std::fmt;
 
+use pulldown_cmark_escape::FmtWriter;
 use unicode_segmentation::UnicodeSegmentation;
 
 /// Wrapper struct which will emit the HTML-escaped version of the contained
@@ -13,31 +14,7 @@ pub(crate) struct Escape<'a>(pub &'a str);
 
 impl fmt::Display for Escape<'_> {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // Because the internet is always right, turns out there's not that many
-        // characters to escape: http://stackoverflow.com/questions/7381974
-        let Escape(s) = *self;
-        let pile_o_bits = s;
-        let mut last = 0;
-        for (i, ch) in s.char_indices() {
-            let s = match ch {
-                '>' => "&gt;",
-                '<' => "&lt;",
-                '&' => "&amp;",
-                '\'' => "&#39;",
-                '"' => "&quot;",
-                _ => continue,
-            };
-            fmt.write_str(&pile_o_bits[last..i])?;
-            fmt.write_str(s)?;
-            // NOTE: we only expect single byte characters here - which is fine as long as we
-            // only match single byte characters
-            last = i + 1;
-        }
-
-        if last < s.len() {
-            fmt.write_str(&pile_o_bits[last..])?;
-        }
-        Ok(())
+        pulldown_cmark_escape::escape_html(FmtWriter(fmt), self.0)
     }
 }
 
@@ -51,29 +28,7 @@ pub(crate) struct EscapeBodyText<'a>(pub &'a str);
 
 impl fmt::Display for EscapeBodyText<'_> {
     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // Because the internet is always right, turns out there's not that many
-        // characters to escape: http://stackoverflow.com/questions/7381974
-        let EscapeBodyText(s) = *self;
-        let pile_o_bits = s;
-        let mut last = 0;
-        for (i, ch) in s.char_indices() {
-            let s = match ch {
-                '>' => "&gt;",
-                '<' => "&lt;",
-                '&' => "&amp;",
-                _ => continue,
-            };
-            fmt.write_str(&pile_o_bits[last..i])?;
-            fmt.write_str(s)?;
-            // NOTE: we only expect single byte characters here - which is fine as long as we
-            // only match single byte characters
-            last = i + 1;
-        }
-
-        if last < s.len() {
-            fmt.write_str(&pile_o_bits[last..])?;
-        }
-        Ok(())
+        pulldown_cmark_escape::escape_html_body_text(FmtWriter(fmt), self.0)
     }
 }
 
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 4f5f8f92264..0ea4d8f1e39 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -41,6 +41,7 @@ xmlns="http://www.w3.org/2000/svg" fill="black" height="18px">\
 	--font-family: "Source Serif 4", NanumBarunGothic, serif;
 	--font-family-code: "Source Code Pro", monospace;
 	--line-number-padding: 4px;
+	--line-number-right-margin: 20px;
 	/* scraped examples icons (34x33px) */
 	--prev-arrow-image: url('data:image/svg+xml,<svg width="16" height="16" viewBox="0 0 16 16" \
 	enable-background="new 0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path fill="none" \
@@ -848,22 +849,6 @@ ul.block, .block li, .block ul {
 	border-radius: 6px;
 }
 
-/*
-If the code example line numbers are displayed, there will be a weird radius in the middle from
-both the code example and the line numbers, so we need to remove the radius in this case.
-*/
-.rustdoc .example-wrap > .example-line-numbers,
-.rustdoc .scraped-example .src-line-numbers,
-.rustdoc .scraped-example .src-line-numbers > pre {
-	border-top-right-radius: 0;
-	border-bottom-right-radius: 0;
-}
-.rustdoc .example-wrap > .example-line-numbers + pre,
-.rustdoc .scraped-example .rust {
-	border-top-left-radius: 0;
-	border-bottom-left-radius: 0;
-}
-
 .rustdoc .scraped-example {
 	position: relative;
 }
@@ -908,45 +893,31 @@ both the code example and the line numbers, so we need to remove the radius in t
 	overflow: auto;
 }
 
-.rustdoc .example-wrap pre.example-line-numbers,
-.rustdoc .example-wrap .src-line-numbers {
-	min-width: fit-content; /* prevent collapsing into nothing in truncated scraped examples */
-	flex-grow: 0;
-	text-align: right;
-	-moz-user-select: none;
-	-webkit-user-select: none;
-	-ms-user-select: none;
-	user-select: none;
-	padding: 14px 8px;
-	padding-right: 2px;
-	color: var(--src-line-numbers-span-color);
-}
-
-.example-wrap.digits-1 [data-nosnippet] {
+.example-wrap.digits-1:not(.hide-lines) [data-nosnippet] {
 	width: calc(1ch + var(--line-number-padding) * 2);
 }
-.example-wrap.digits-2 [data-nosnippet] {
+.example-wrap.digits-2:not(.hide-lines) [data-nosnippet] {
 	width: calc(2ch + var(--line-number-padding) * 2);
 }
-.example-wrap.digits-3 [data-nosnippet] {
+.example-wrap.digits-3:not(.hide-lines) [data-nosnippet] {
 	width: calc(3ch + var(--line-number-padding) * 2);
 }
-.example-wrap.digits-4 [data-nosnippet] {
+.example-wrap.digits-4:not(.hide-lines) [data-nosnippet] {
 	width: calc(4ch + var(--line-number-padding) * 2);
 }
-.example-wrap.digits-5 [data-nosnippet] {
+.example-wrap.digits-5:not(.hide-lines) [data-nosnippet] {
 	width: calc(5ch + var(--line-number-padding) * 2);
 }
-.example-wrap.digits-6 [data-nosnippet] {
+.example-wrap.digits-6:not(.hide-lines) [data-nosnippet] {
 	width: calc(6ch + var(--line-number-padding) * 2);
 }
-.example-wrap.digits-7 [data-nosnippet] {
+.example-wrap.digits-7:not(.hide-lines) [data-nosnippet] {
 	width: calc(7ch + var(--line-number-padding) * 2);
 }
-.example-wrap.digits-8 [data-nosnippet] {
+.example-wrap.digits-8:not(.hide-lines) [data-nosnippet] {
 	width: calc(8ch + var(--line-number-padding) * 2);
 }
-.example-wrap.digits-9 [data-nosnippet] {
+.example-wrap.digits-9:not(.hide-lines) [data-nosnippet] {
 	width: calc(9ch + var(--line-number-padding) * 2);
 }
 
@@ -954,12 +925,12 @@ both the code example and the line numbers, so we need to remove the radius in t
 	color: var(--src-line-numbers-span-color);
 	text-align: right;
 	display: inline-block;
-	margin-right: 20px;
+	margin-right: var(--line-number-right-margin);
 	-moz-user-select: none;
 	-webkit-user-select: none;
 	-ms-user-select: none;
 	user-select: none;
-	padding: 0 4px;
+	padding: 0 var(--line-number-padding);
 }
 .example-wrap [data-nosnippet]:target {
 	border-right: none;
@@ -967,6 +938,60 @@ both the code example and the line numbers, so we need to remove the radius in t
 .example-wrap .line-highlighted[data-nosnippet] {
 	background-color: var(--src-line-number-highlighted-background-color);
 }
+:root.word-wrap-source-code .example-wrap [data-nosnippet] {
+	position: absolute;
+	left: 0;
+}
+.word-wrap-source-code .example-wrap pre > code {
+	position: relative;
+	word-break: break-all;
+}
+:root.word-wrap-source-code .example-wrap pre > code {
+	display: block;
+	white-space: pre-wrap;
+}
+:root.word-wrap-source-code .example-wrap pre > code * {
+	word-break: break-all;
+}
+:root.word-wrap-source-code .example-wrap.digits-1 pre > code {
+	padding-left: calc(
+		1ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
+}
+:root.word-wrap-source-code .example-wrap.digits-2 pre > code {
+	padding-left: calc(
+		2ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
+}
+:root.word-wrap-source-code .example-wrap.digits-3 pre > code {
+	padding-left: calc(
+		3ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
+}
+:root.word-wrap-source-code .example-wrap.digits-4 pre > code {
+	padding-left: calc(
+		4ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
+}
+:root.word-wrap-source-code .example-wrap.digits-5 pre > code {
+	padding-left: calc(
+		5ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
+}
+:root.word-wrap-source-code .example-wrap.digits-6 pre > code {
+	padding-left: calc(
+		6ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
+}
+:root.word-wrap-source-code .example-wrap.digits-7 pre > code {
+	padding-left: calc(
+		7ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
+}
+:root.word-wrap-source-code .example-wrap.digits-8 pre > code {
+	padding-left: calc(
+		8ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
+}
+:root.word-wrap-source-code .example-wrap.digits-9 pre > code {
+	padding-left: calc(
+		9ch + var(--line-number-padding) * 2 + var(--line-number-right-margin));
+}
+.example-wrap.hide-lines [data-nosnippet] {
+	display: none;
+}
 
 .search-loading {
 	text-align: center;
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index e46cc1897e9..edfcc1291b9 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -1112,35 +1112,32 @@ function preLoadCss(cssUrl) {
 
     // @ts-expect-error
     window.rustdoc_add_line_numbers_to_examples = () => {
-        if (document.querySelector(".rustdoc.src")) {
-            // We are in the source code page, nothing to be done here!
-            return;
+        // @ts-expect-error
+        function generateLine(nb) {
+            return `<span data-nosnippet>${nb}</span>`;
         }
+
         onEachLazy(document.querySelectorAll(
-            ":not(.scraped-example) > .example-wrap > pre:not(.example-line-numbers)",
-        ), x => {
-            const parent = x.parentNode;
-            const line_numbers = parent.querySelectorAll(".example-line-numbers");
-            if (line_numbers.length > 0) {
+            ".rustdoc:not(.src) :not(.scraped-example) > .example-wrap > pre > code",
+        ), code => {
+            if (hasClass(code.parentElement.parentElement, "hide-lines")) {
+                removeClass(code.parentElement.parentElement, "hide-lines");
                 return;
             }
-            const count = x.textContent.split("\n").length;
-            const elems = [];
-            for (let i = 0; i < count; ++i) {
-                elems.push(i + 1);
-            }
-            const node = document.createElement("pre");
-            addClass(node, "example-line-numbers");
-            node.innerHTML = elems.join("\n");
-            parent.insertBefore(node, x);
+            const lines = code.innerHTML.split("\n");
+            const digits = (lines.length + "").length;
+            // @ts-expect-error
+            code.innerHTML = lines.map((line, index) => generateLine(index + 1) + line).join("\n");
+            addClass(code.parentElement.parentElement, `digits-${digits}`);
         });
     };
 
     // @ts-expect-error
     window.rustdoc_remove_line_numbers_from_examples = () => {
-        onEachLazy(document.querySelectorAll(".example-wrap > .example-line-numbers"), x => {
-            x.parentNode.removeChild(x);
-        });
+        onEachLazy(
+            document.querySelectorAll(".rustdoc:not(.src) :not(.scraped-example) > .example-wrap"),
+            x => addClass(x, "hide-lines"),
+        );
     };
 
     if (getSettingValue("line-numbers") === "true") {
diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js
index bf33e0f17e5..5f1bbd27328 100644
--- a/src/librustdoc/html/static/js/settings.js
+++ b/src/librustdoc/html/static/js/settings.js
@@ -59,6 +59,14 @@
                 } else {
                     removeClass(document.documentElement, "sans-serif");
                 }
+                break;
+            case "word-wrap-source-code":
+                if (value === true) {
+                    addClass(document.documentElement, "word-wrap-source-code");
+                } else {
+                    removeClass(document.documentElement, "word-wrap-source-code");
+                }
+                break;
         }
     }
 
@@ -246,6 +254,11 @@
                 "js_name": "sans-serif-fonts",
                 "default": false,
             },
+            {
+                "name": "Word wrap source code",
+                "js_name": "word-wrap-source-code",
+                "default": false,
+            },
         ];
 
         // Then we build the DOM.
diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js
index 3042373fb09..425b915b5f9 100644
--- a/src/librustdoc/html/static/js/storage.js
+++ b/src/librustdoc/html/static/js/storage.js
@@ -286,6 +286,9 @@ if (getSettingValue("hide-modnav") === "true") {
 if (getSettingValue("sans-serif-fonts") === "true") {
     addClass(document.documentElement, "sans-serif");
 }
+if (getSettingValue("word-wrap-source-code") === "true") {
+    addClass(document.documentElement, "word-wrap-source-code");
+}
 function updateSidebarWidth() {
     const desktopSidebarWidth = getSettingValue("desktop-sidebar-width");
     if (desktopSidebarWidth && desktopSidebarWidth !== "null") {
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/rust-version b/src/tools/miri/rust-version
index 6cd39fabeee..b3e207f53b8 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-e0be1a02626abef2878cb7f4aaef7ae409477112
+f5729cfed3c45e061e8a443677fc1d5ef9277df7
diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs
index 339d7161374..de5da6ec898 100644
--- a/src/tools/miri/src/intrinsics/simd.rs
+++ b/src/tools/miri/src/intrinsics/simd.rs
@@ -635,7 +635,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     this.write_immediate(*val, &dest)?;
                 }
             }
-            "shuffle_generic" => {
+            "shuffle_const_generic" => {
                 let [left, right] = check_intrinsic_arg_count(args)?;
                 let (left, left_len) = this.project_to_simd(left)?;
                 let (right, right_len) = this.project_to_simd(right)?;
@@ -659,7 +659,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/rust-analyzer/.github/workflows/release.yaml b/src/tools/rust-analyzer/.github/workflows/release.yaml
index 3f1c8b2a9c1..fe090267dc9 100644
--- a/src/tools/rust-analyzer/.github/workflows/release.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/release.yaml
@@ -34,14 +34,14 @@ jobs:
           - os: windows-latest
             target: aarch64-pc-windows-msvc
             code-target: win32-arm64
-          - os: ubuntu-20.04
+          - os: ubuntu-latest
             target: x86_64-unknown-linux-gnu
             code-target: linux-x64
             container: rockylinux:8
-          - os: ubuntu-20.04
+          - os: ubuntu-latest
             target: aarch64-unknown-linux-gnu
             code-target: linux-arm64
-          - os: ubuntu-20.04
+          - os: ubuntu-latest
             target: arm-unknown-linux-gnueabihf
             code-target: linux-armhf
           - os: macos-13
diff --git a/src/tools/rust-analyzer/CONTRIBUTING.md b/src/tools/rust-analyzer/CONTRIBUTING.md
index da65b034be3..6f270fc63ba 100644
--- a/src/tools/rust-analyzer/CONTRIBUTING.md
+++ b/src/tools/rust-analyzer/CONTRIBUTING.md
@@ -4,7 +4,7 @@ Thank you for your interest in contributing to rust-analyzer! There are many way
 and we appreciate all of them.
 
 To get a quick overview of the crates and structure of the project take a look at the
-[./docs/dev](./docs/dev) folder.
+[Contributing](https://rust-analyzer.github.io/book/contributing) section of the manual.
 
 If you have any questions please ask them in the [rust-analyzer zulip stream](
 https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer) or if unsure where
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 6d7f6042dec..01e6a39f7c9 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -559,9 +559,9 @@ dependencies = [
  "intern",
  "itertools",
  "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "limit",
  "mbe",
  "ra-ap-rustc_abi",
+ "ra-ap-rustc_hashes",
  "ra-ap-rustc_parse_format",
  "rustc-hash 2.0.0",
  "rustc_apfloat",
@@ -591,7 +591,6 @@ dependencies = [
  "intern",
  "itertools",
  "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "limit",
  "mbe",
  "parser",
  "rustc-hash 2.0.0",
@@ -626,11 +625,11 @@ dependencies = [
  "intern",
  "itertools",
  "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "limit",
  "nohash-hasher",
  "oorandom",
  "project-model",
  "ra-ap-rustc_abi",
+ "ra-ap-rustc_hashes",
  "ra-ap-rustc_index",
  "ra-ap-rustc_pattern_analysis",
  "rustc-hash 2.0.0",
@@ -744,7 +743,6 @@ dependencies = [
  "hir",
  "indexmap",
  "itertools",
- "limit",
  "line-index 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "memchr",
  "nohash-hasher",
@@ -944,10 +942,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "limit"
-version = "0.0.0"
-
-[[package]]
 name = "line-index"
 version = "0.1.2"
 dependencies = [
@@ -1279,7 +1273,6 @@ dependencies = [
  "drop_bomb",
  "edition",
  "expect-test",
- "limit",
  "ra-ap-rustc_lexer",
  "stdx",
  "tracing",
@@ -1514,20 +1507,30 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_abi"
-version = "0.95.0"
+version = "0.97.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b40c4e339b71a8f075a829b1acaf32f870a11b466d9b8623d50b0ce33e65af95"
+checksum = "3829c3355d1681ffeaf1450ec71edcdace6820fe2e86469d8fc1ad45e2c96460"
 dependencies = [
  "bitflags 2.7.0",
+ "ra-ap-rustc_hashes",
  "ra-ap-rustc_index",
  "tracing",
 ]
 
 [[package]]
+name = "ra-ap-rustc_hashes"
+version = "0.97.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bd4d6d4c434bec08e02370a4f64a4985312097215a62e82d0f757f3a98e502e"
+dependencies = [
+ "rustc-stable-hash",
+]
+
+[[package]]
 name = "ra-ap-rustc_index"
-version = "0.95.0"
+version = "0.97.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "872072e2ba11d11147ebe9fde1608fe7f7d9b5c51dac524af28ee07c6dade468"
+checksum = "bad6fc4bd7522e31096e2de5b0351144fe0684b608791ee26c842bf2da1b19ae"
 dependencies = [
  "ra-ap-rustc_index_macros",
  "smallvec",
@@ -1535,9 +1538,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_index_macros"
-version = "0.95.0"
+version = "0.97.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffcd77debcaf2ad690a57c2d041c11eb33fe66869754b2c5f35c52954b46af0c"
+checksum = "cfb234e1f84b92be45276c3025bee18789e9bc95bec8789bec961e78edb01c52"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1546,9 +1549,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_lexer"
-version = "0.95.0"
+version = "0.97.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49265cdf8823f8d246e476c79c60bd6e5b551c81ae76e1c8d6a5e0dc73df0bca"
+checksum = "7a3a40bd11dc43d1cb110e730b80620cf8102f4cca8920a02b65954da0ed931f"
 dependencies = [
  "memchr",
  "unicode-properties",
@@ -1557,9 +1560,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_parse_format"
-version = "0.95.0"
+version = "0.97.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b3da239fdc971176de0db45cb631d71475b52033a3d0027d91964da7be89eee6"
+checksum = "5feb877478994cb4c0c0c7a5116a352eefc0634aefc8636feb00a893fa5b7135"
 dependencies = [
  "ra-ap-rustc_index",
  "ra-ap-rustc_lexer",
@@ -1567,9 +1570,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_pattern_analysis"
-version = "0.95.0"
+version = "0.97.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56057d08fdfa0d95494e461bbdd5d4b3fdb349cca6be05ad7759bc964be1b8d4"
+checksum = "a76774d35934d464c4115908cde16f76a4f7e540fe1eea6b79336c556e37bdd3"
 dependencies = [
  "ra-ap-rustc_index",
  "rustc-hash 2.0.0",
@@ -1745,6 +1748,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152"
 
 [[package]]
+name = "rustc-stable-hash"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2febf9acc5ee5e99d1ad0afcdbccc02d87aa3f857a1f01f825b80eacf8edfcd1"
+
+[[package]]
 name = "rustc_apfloat"
 version = "0.2.1+llvm-462a31f5a5ab"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 924ffb8dd21..1ff36a68e8f 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -64,7 +64,6 @@ ide-db = { path = "./crates/ide-db", version = "0.0.0" }
 ide-diagnostics = { path = "./crates/ide-diagnostics", version = "0.0.0" }
 ide-ssr = { path = "./crates/ide-ssr", version = "0.0.0" }
 intern = { path = "./crates/intern", version = "0.0.0" }
-limit = { path = "./crates/limit", version = "0.0.0" }
 load-cargo = { path = "./crates/load-cargo", version = "0.0.0" }
 mbe = { path = "./crates/mbe", version = "0.0.0" }
 parser = { path = "./crates/parser", version = "0.0.0" }
@@ -87,11 +86,12 @@ vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
 vfs = { path = "./crates/vfs", version = "0.0.0" }
 edition = { path = "./crates/edition", version = "0.0.0" }
 
-ra-ap-rustc_lexer = { version = "0.95", default-features = false }
-ra-ap-rustc_parse_format = { version = "0.95", default-features = false }
-ra-ap-rustc_index = { version = "0.95", default-features = false }
-ra-ap-rustc_abi = { version = "0.95", default-features = false }
-ra-ap-rustc_pattern_analysis = { version = "0.95", default-features = false }
+ra-ap-rustc_hashes = { version = "0.97", default-features = false }
+ra-ap-rustc_lexer = { version = "0.97", default-features = false }
+ra-ap-rustc_parse_format = { version = "0.97", default-features = false }
+ra-ap-rustc_index = { version = "0.97", default-features = false }
+ra-ap-rustc_abi = { version = "0.97", default-features = false }
+ra-ap-rustc_pattern_analysis = { version = "0.97", default-features = false }
 
 # local crates that aren't published to crates.io. These should not have versions.
 
diff --git a/src/tools/rust-analyzer/README.md b/src/tools/rust-analyzer/README.md
index 56883723c93..4360dea4a11 100644
--- a/src/tools/rust-analyzer/README.md
+++ b/src/tools/rust-analyzer/README.md
@@ -14,8 +14,8 @@ https://rust-analyzer.github.io/book/installation.html
 ## Documentation
 
 If you want to **contribute** to rust-analyzer check out the [CONTRIBUTING.md](./CONTRIBUTING.md) or
-if you are just curious about how things work under the hood, check the [./docs/dev](./docs/dev)
-folder.
+if you are just curious about how things work under the hood, see the
+[Contributing](https://rust-analyzer.github.io/book/contributing) section of the manual.
 
 If you want to **use** rust-analyzer's language server with your editor of
 choice, check [the manual](https://rust-analyzer.github.io/book/).
diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs
index c2cea071905..bd08387b582 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/input.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs
@@ -296,6 +296,9 @@ pub struct CrateData {
     pub dependencies: Vec<Dependency>,
     pub origin: CrateOrigin,
     pub is_proc_macro: bool,
+    /// The working directory to run proc-macros in. This is the workspace root of the cargo workspace
+    /// for workspace members, the crate manifest dir otherwise.
+    pub proc_macro_cwd: Option<AbsPathBuf>,
 }
 
 #[derive(Default, Clone, PartialEq, Eq)]
@@ -360,8 +363,9 @@ impl CrateGraph {
         cfg_options: Arc<CfgOptions>,
         potential_cfg_options: Option<Arc<CfgOptions>>,
         mut env: Env,
-        is_proc_macro: bool,
         origin: CrateOrigin,
+        is_proc_macro: bool,
+        proc_macro_cwd: Option<AbsPathBuf>,
     ) -> CrateId {
         env.entries.shrink_to_fit();
         let data = CrateData {
@@ -375,6 +379,7 @@ impl CrateGraph {
             dependencies: Vec::new(),
             origin,
             is_proc_macro,
+            proc_macro_cwd,
         };
         self.arena.alloc(data)
     }
@@ -698,8 +703,9 @@ mod tests {
             Default::default(),
             Default::default(),
             Env::default(),
-            false,
             CrateOrigin::Local { repo: None, name: None },
+            false,
+            None,
         );
         let crate2 = graph.add_crate_root(
             FileId::from_raw(2u32),
@@ -709,8 +715,9 @@ mod tests {
             Default::default(),
             Default::default(),
             Env::default(),
-            false,
             CrateOrigin::Local { repo: None, name: None },
+            false,
+            None,
         );
         let crate3 = graph.add_crate_root(
             FileId::from_raw(3u32),
@@ -720,8 +727,9 @@ mod tests {
             Default::default(),
             Default::default(),
             Env::default(),
-            false,
             CrateOrigin::Local { repo: None, name: None },
+            false,
+            None,
         );
         assert!(graph
             .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2,))
@@ -745,8 +753,9 @@ mod tests {
             Default::default(),
             Default::default(),
             Env::default(),
-            false,
             CrateOrigin::Local { repo: None, name: None },
+            false,
+            None,
         );
         let crate2 = graph.add_crate_root(
             FileId::from_raw(2u32),
@@ -756,8 +765,9 @@ mod tests {
             Default::default(),
             Default::default(),
             Env::default(),
-            false,
             CrateOrigin::Local { repo: None, name: None },
+            false,
+            None,
         );
         assert!(graph
             .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2,))
@@ -778,8 +788,9 @@ mod tests {
             Default::default(),
             Default::default(),
             Env::default(),
-            false,
             CrateOrigin::Local { repo: None, name: None },
+            false,
+            None,
         );
         let crate2 = graph.add_crate_root(
             FileId::from_raw(2u32),
@@ -789,8 +800,9 @@ mod tests {
             Default::default(),
             Default::default(),
             Env::default(),
-            false,
             CrateOrigin::Local { repo: None, name: None },
+            false,
+            None,
         );
         let crate3 = graph.add_crate_root(
             FileId::from_raw(3u32),
@@ -800,8 +812,9 @@ mod tests {
             Default::default(),
             Default::default(),
             Env::default(),
-            false,
             CrateOrigin::Local { repo: None, name: None },
+            false,
+            None,
         );
         assert!(graph
             .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2,))
@@ -822,8 +835,9 @@ mod tests {
             Default::default(),
             Default::default(),
             Env::default(),
-            false,
             CrateOrigin::Local { repo: None, name: None },
+            false,
+            None,
         );
         let crate2 = graph.add_crate_root(
             FileId::from_raw(2u32),
@@ -833,8 +847,9 @@ mod tests {
             Default::default(),
             Default::default(),
             Env::default(),
-            false,
             CrateOrigin::Local { repo: None, name: None },
+            false,
+            None,
         );
         assert!(graph
             .add_dep(
diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
index c7e4168f6bc..eed8c886839 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
@@ -10,7 +10,7 @@ use rustc_hash::FxHashMap;
 use span::EditionedFileId;
 use syntax::{ast, Parse, SourceFile, SyntaxError};
 use triomphe::Arc;
-use vfs::{AbsPathBuf, FileId};
+use vfs::FileId;
 
 pub use crate::{
     change::FileChange,
@@ -85,8 +85,6 @@ pub trait SourceDatabase: FileLoader + std::fmt::Debug {
 /// Crate related data shared by the whole workspace.
 #[derive(Debug, PartialEq, Eq, Hash, Clone)]
 pub struct CrateWorkspaceData {
-    /// The working directory to run proc-macros in. This is usually the workspace root of cargo workspaces.
-    pub proc_macro_cwd: Option<AbsPathBuf>,
     // FIXME: Consider removing this, making HirDatabase::target_data_layout an input query
     pub data_layout: TargetLayoutLoadResult,
     /// Toolchain version used to compile the crate.
diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
index 375f18d9fe1..9a448ec14ea 100644
--- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
@@ -31,6 +31,7 @@ triomphe.workspace = true
 rustc_apfloat = "0.2.0"
 text-size.workspace = true
 
+ra-ap-rustc_hashes.workspace = true
 ra-ap-rustc_parse_format.workspace = true
 ra-ap-rustc_abi.workspace = true
 
@@ -43,7 +44,6 @@ hir-expand.workspace = true
 mbe.workspace = true
 cfg.workspace = true
 tt.workspace = true
-limit.workspace = true
 span.workspace = true
 
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
index 5d1834a8642..c94622016d3 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
@@ -173,7 +173,13 @@ fn parse_repr_tt(tt: &TopSubtree) -> Option<ReprOptions> {
         }
     }
 
-    Some(ReprOptions { int, align: max_align, pack: min_pack, flags, field_shuffle_seed: Hash64::ZERO })
+    Some(ReprOptions {
+        int,
+        align: max_align,
+        pack: min_pack,
+        flags,
+        field_shuffle_seed: Hash64::ZERO,
+    })
 }
 
 impl StructData {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
index 108258d5a11..a1b3123c991 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs
@@ -9,7 +9,6 @@ use hir_expand::{
     attrs::RawAttrs, mod_path::ModPath, span_map::SpanMap, ExpandError, ExpandErrorKind,
     ExpandResult, HirFileId, InFile, Lookup, MacroCallId,
 };
-use limit::Limit;
 use span::{Edition, SyntaxContextId};
 use syntax::{ast, Parse};
 use triomphe::Arc;
@@ -28,18 +27,18 @@ pub struct Expander {
     pub(crate) module: ModuleId,
     /// `recursion_depth == usize::MAX` indicates that the recursion limit has been reached.
     recursion_depth: u32,
-    recursion_limit: Limit,
+    recursion_limit: usize,
 }
 
 impl Expander {
     pub fn new(db: &dyn DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander {
         let recursion_limit = module.def_map(db).recursion_limit() as usize;
-        let recursion_limit = Limit::new(if cfg!(test) {
+        let recursion_limit = if cfg!(test) {
             // Without this, `body::tests::your_stack_belongs_to_me` stack-overflows in debug
             std::cmp::min(32, recursion_limit)
         } else {
             recursion_limit
-        });
+        };
         Expander {
             current_file_id,
             module,
@@ -194,7 +193,7 @@ impl Expander {
         let Some(call_id) = value else {
             return ExpandResult { value: None, err };
         };
-        if self.recursion_limit.check(self.recursion_depth as usize + 1).is_err() {
+        if self.recursion_depth as usize > self.recursion_limit {
             self.recursion_depth = u32::MAX;
             cov_mark::hit!(your_stack_belongs_to_me);
             return ExpandResult::only_err(ExpandError::new(
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index 254c1379917..16f3fd56eb9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -19,7 +19,6 @@ use hir_expand::{
 use intern::{sym, Interned};
 use itertools::{izip, Itertools};
 use la_arena::Idx;
-use limit::Limit;
 use rustc_hash::{FxHashMap, FxHashSet};
 use span::{Edition, EditionedFileId, FileAstId, SyntaxContextId};
 use syntax::ast;
@@ -55,8 +54,8 @@ use crate::{
     UnresolvedMacro, UseId, UseLoc,
 };
 
-static GLOB_RECURSION_LIMIT: Limit = Limit::new(100);
-static FIXED_POINT_LIMIT: Limit = Limit::new(8192);
+const GLOB_RECURSION_LIMIT: usize = 100;
+const FIXED_POINT_LIMIT: usize = 8192;
 
 pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeId) -> DefMap {
     let crate_graph = db.crate_graph();
@@ -393,7 +392,7 @@ impl DefCollector<'_> {
                 }
 
                 i += 1;
-                if FIXED_POINT_LIMIT.check(i).is_err() {
+                if i > FIXED_POINT_LIMIT {
                     tracing::error!("name resolution is stuck");
                     break 'resolve_attr;
                 }
@@ -993,7 +992,7 @@ impl DefCollector<'_> {
         import: Option<ImportOrExternCrate>,
         depth: usize,
     ) {
-        if GLOB_RECURSION_LIMIT.check(depth).is_err() {
+        if depth > GLOB_RECURSION_LIMIT {
             // prevent stack overflows (but this shouldn't be possible)
             panic!("infinite recursion in glob imports!");
         }
@@ -1470,8 +1469,7 @@ impl DefCollector<'_> {
         depth: usize,
         container: ItemContainerId,
     ) {
-        let recursion_limit = Limit::new(self.def_map.recursion_limit() as usize);
-        if recursion_limit.check(depth).is_err() {
+        if depth > self.def_map.recursion_limit() as usize {
             cov_mark::hit!(macro_expansion_overflow);
             tracing::warn!("macro expansion is too deep");
             return;
@@ -1499,7 +1497,6 @@ impl DefCollector<'_> {
 
     fn finish(mut self) -> DefMap {
         // Emit diagnostics for all remaining unexpanded macros.
-
         let _p = tracing::info_span!("DefCollector::finish").entered();
 
         for directive in &self.unresolved_macros {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs
index d7e4ca41cd5..afee42ecec0 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs
@@ -2,12 +2,11 @@
 use arrayvec::ArrayVec;
 use base_db::AnchoredPath;
 use hir_expand::{name::Name, HirFileIdExt};
-use limit::Limit;
 use span::EditionedFileId;
 
 use crate::{db::DefDatabase, HirFileId};
 
-static MOD_DEPTH_LIMIT: Limit = Limit::new(32);
+const MOD_DEPTH_LIMIT: usize = 32;
 
 #[derive(Clone, Debug)]
 pub(super) struct ModDir {
@@ -50,7 +49,7 @@ impl ModDir {
 
     fn child(&self, dir_path: DirPath, root_non_dir_owner: bool) -> Option<ModDir> {
         let depth = self.depth + 1;
-        if MOD_DEPTH_LIMIT.check(depth as usize).is_err() {
+        if depth as usize > MOD_DEPTH_LIMIT {
             tracing::error!("MOD_DEPTH_LIMIT exceeded");
             cov_mark::hit!(circular_mods);
             return None;
diff --git a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml
index 03a9d54d2e6..b193a34a01d 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml
@@ -31,7 +31,6 @@ cfg.workspace = true
 syntax.workspace = true
 tt.workspace = true
 mbe.workspace = true
-limit.workspace = true
 span.workspace = true
 parser.workspace = true
 syntax-bridge.workspace = true
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
index 310ddaaf9e9..55242ab3e57 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
@@ -833,7 +833,7 @@ fn env_expand(
         if key.as_str() == "OUT_DIR" {
             err = Some(ExpandError::other(
                 span,
-                r#"`OUT_DIR` not set, enable "build scripts" to fix"#,
+                r#"`OUT_DIR` not set, build scripts may have failed to run"#,
             ));
         }
 
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
index b7804f888ae..8ca8bf1ba4a 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
@@ -2,7 +2,6 @@
 
 use base_db::{ra_salsa, CrateId, SourceDatabase};
 use either::Either;
-use limit::Limit;
 use mbe::MatchedArmIndex;
 use rustc_hash::FxHashSet;
 use span::{AstIdMap, Edition, EditionedFileId, Span, SyntaxContextData, SyntaxContextId};
@@ -35,7 +34,7 @@ type MacroArgResult = (Arc<tt::TopSubtree>, SyntaxFixupUndoInfo, Span);
 /// an error will be emitted.
 ///
 /// Actual max for `analysis-stats .` at some point: 30672.
-static TOKEN_LIMIT: Limit = Limit::new(2_097_152);
+const TOKEN_LIMIT: usize = 2_097_152;
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub enum TokenExpander {
@@ -740,20 +739,19 @@ pub(crate) fn token_tree_to_syntax_node(
 fn check_tt_count(tt: &tt::TopSubtree) -> Result<(), ExpandResult<()>> {
     let tt = tt.top_subtree();
     let count = tt.count();
-    if TOKEN_LIMIT.check(count).is_err() {
+    if count <= TOKEN_LIMIT {
+        Ok(())
+    } else {
         Err(ExpandResult {
             value: (),
             err: Some(ExpandError::other(
                 tt.delimiter.open,
                 format!(
                     "macro invocation exceeds token limit: produced {} tokens, limit is {}",
-                    count,
-                    TOKEN_LIMIT.inner(),
+                    count, TOKEN_LIMIT,
                 ),
             )),
         })
-    } else {
-        Ok(())
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
index 07808fea85b..3dc3dcd760c 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
@@ -238,6 +238,9 @@ impl CustomProcMacroExpander {
                 let krate_graph = db.crate_graph();
                 // Proc macros have access to the environment variables of the invoking crate.
                 let env = &krate_graph[calling_crate].env;
+                let current_dir =
+                    krate_graph[calling_crate].proc_macro_cwd.as_deref().map(ToString::to_string);
+
                 match proc_macro.expander.expand(
                     tt,
                     attr_arg,
@@ -245,10 +248,7 @@ impl CustomProcMacroExpander {
                     def_site,
                     call_site,
                     mixed_site,
-                    db.crate_workspace_data()[&calling_crate]
-                        .proc_macro_cwd
-                        .as_ref()
-                        .map(ToString::to_string),
+                    current_dir,
                 ) {
                     Ok(t) => ExpandResult::ok(t),
                     Err(err) => match err {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
index 989f0955e1e..4d36de0b383 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
@@ -36,6 +36,7 @@ indexmap.workspace = true
 rustc_apfloat = "0.2.0"
 
 ra-ap-rustc_abi.workspace = true
+ra-ap-rustc_hashes.workspace = true
 ra-ap-rustc_index.workspace = true
 ra-ap-rustc_pattern_analysis.workspace = true
 
@@ -47,7 +48,6 @@ hir-def.workspace = true
 hir-expand.workspace = true
 base-db.workspace = true
 syntax.workspace = true
-limit.workspace = true
 span.workspace = true
 
 [dev-dependencies]
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
index e0e366f4501..171ba001c4a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
@@ -9,7 +9,6 @@ use chalk_ir::cast::Cast;
 use hir_def::lang_item::LangItem;
 use hir_expand::name::Name;
 use intern::sym;
-use limit::Limit;
 use triomphe::Arc;
 
 use crate::{
@@ -17,7 +16,7 @@ use crate::{
     TraitEnvironment, Ty, TyBuilder, TyKind,
 };
 
-static AUTODEREF_RECURSION_LIMIT: Limit = Limit::new(20);
+const AUTODEREF_RECURSION_LIMIT: usize = 20;
 
 #[derive(Debug)]
 pub(crate) enum AutoderefKind {
@@ -140,7 +139,7 @@ impl<T: TrackAutoderefSteps> Iterator for Autoderef<'_, '_, T> {
             return Some((self.ty.clone(), 0));
         }
 
-        if AUTODEREF_RECURSION_LIMIT.check(self.steps.len() + 1).is_err() {
+        if self.steps.len() > AUTODEREF_RECURSION_LIMIT {
             return None;
         }
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
index 6d4753ea389..c8ff6cba3dd 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
@@ -768,21 +768,23 @@ pub(crate) fn adt_datum_query(
         phantom_data,
     };
 
-    let variant_id_to_fields = |id: VariantId| {
+    // this slows down rust-analyzer by quite a bit unfortunately, so enabling this is currently not worth it
+    let _variant_id_to_fields = |id: VariantId| {
         let variant_data = &id.variant_data(db.upcast());
-        let fields = if variant_data.fields().is_empty() || bound_vars_subst.is_empty(Interner) {
+        let fields = if variant_data.fields().is_empty() {
             vec![]
         } else {
-            // HACK: provide full struct type info slows down rust-analyzer by quite a bit unfortunately,
-            // so we trick chalk into thinking that our struct impl Unsize
-            if let Some(ty) = bound_vars_subst.at(Interner, 0).ty(Interner) {
-                vec![ty.clone()]
-            } else {
-                vec![]
-            }
+            let field_types = db.field_types(id);
+            variant_data
+                .fields()
+                .iter()
+                .map(|(idx, _)| field_types[idx].clone().substitute(Interner, &bound_vars_subst))
+                .filter(|it| !it.contains_unknown())
+                .collect()
         };
         rust_ir::AdtVariantDatum { fields }
     };
+    let variant_id_to_fields = |_: VariantId| rust_ir::AdtVariantDatum { fields: vec![] };
 
     let (kind, variants) = match adt_id {
         hir_def::AdtId::StructId(id) => {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
index a72bcad50a0..e2ab336d2e4 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -14,8 +14,8 @@ use hir_def::{
 };
 use la_arena::{Idx, RawIdx};
 use rustc_abi::AddressSpace;
-use rustc_index::{IndexSlice, IndexVec};
 use rustc_hashes::Hash64;
+use rustc_index::{IndexSlice, IndexVec};
 
 use triomphe::Arc;
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs
index 22c5bb9923f..a165932ddcc 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower/path.rs
@@ -10,7 +10,7 @@ use hir_def::{
     generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
     path::{GenericArg, GenericArgs, Path, PathSegment, PathSegments},
     resolver::{ResolveValueResult, TypeNs, ValueNs},
-    type_ref::{TypeBound, TypeRef},
+    type_ref::{TypeBound, TypeRef, TypesMap},
     GenericDefId, GenericParamId, ItemContainerId, Lookup, TraitId,
 };
 use smallvec::SmallVec;
@@ -838,15 +838,21 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
                         (_, ImplTraitLoweringMode::Param | ImplTraitLoweringMode::Variable) => {
                             // Find the generic index for the target of our `bound`
                             let target_param_idx =
-                                self.ctx.resolver.where_predicates_in_scope().find_map(|(p, _)| {
-                                    match p {
+                                self.ctx.resolver.where_predicates_in_scope().find_map(
+                                    |(p, (_, types_map))| match p {
                                         WherePredicate::TypeBound {
                                             target: WherePredicateTypeTarget::TypeOrConstParam(idx),
                                             bound: b,
-                                        } if b == bound => Some(idx),
+                                        } if std::ptr::eq::<TypesMap>(
+                                            self.ctx.types_map,
+                                            types_map,
+                                        ) && bound == b =>
+                                        {
+                                            Some(idx)
+                                        }
                                         _ => None,
-                                    }
-                                });
+                                    },
+                                );
                             let ty = if let Some(target_param_idx) = target_param_idx {
                                 let mut counter = 0;
                                 let generics = self.ctx.generics().expect("generics in scope");
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
index 9625ae5f88e..2b5486fc5fa 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
@@ -3,7 +3,7 @@ use span::{Edition, EditionedFileId};
 use syntax::{TextRange, TextSize};
 use test_fixture::WithFixture;
 
-use crate::{db::HirDatabase, test_db::TestDB, Interner, Substitution};
+use crate::{db::HirDatabase, mir::MirLowerError, test_db::TestDB, Interner, Substitution};
 
 use super::{interpret_mir, MirEvalError};
 
@@ -84,6 +84,16 @@ fn check_panic(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected_panic:
     assert_eq!(e.is_panic().unwrap_or_else(|| panic!("unexpected error: {e:?}")), expected_panic);
 }
 
+fn check_error_with(
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+    expect_err: impl FnOnce(MirEvalError) -> bool,
+) {
+    let (db, file_ids) = TestDB::with_many_files(ra_fixture);
+    let file_id = *file_ids.last().unwrap();
+    let e = eval_main(&db, file_id).unwrap_err();
+    assert!(expect_err(e));
+}
+
 #[test]
 fn function_with_extern_c_abi() {
     check_pass(
@@ -945,3 +955,27 @@ fn main() {
 "#,
     );
 }
+
+#[test]
+fn regression_19177() {
+    check_error_with(
+        r#"
+//- minicore: copy
+trait Foo {}
+trait Bar {}
+trait Baz {}
+trait Qux {
+    type Assoc;
+}
+
+fn main<'a, T: Foo + Bar + Baz>(
+    x: &T,
+    y: (),
+    z: &'a dyn Qux<Assoc = T>,
+    w: impl Foo + Bar,
+) {
+}
+"#,
+        |e| matches!(e, MirEvalError::MirLowerError(_, MirLowerError::GenericArgNotProvided(..))),
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
index ef94814d587..7e7c1f835c7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
@@ -535,7 +535,7 @@ fn test() {
 
 #[test]
 fn coerce_unsize_generic() {
-    check_no_mismatches(
+    check(
         r#"
 //- minicore: coerce_unsized
 struct Foo<T> { t: T };
@@ -543,7 +543,9 @@ struct Bar<T>(Foo<T>);
 
 fn test() {
     let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] };
+                         //^^^^^^^^^^^^^^^^^^^^^ expected &'? Foo<[usize]>, got &'? Foo<[i32; 3]>
     let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] });
+                         //^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &'? Bar<[usize]>, got &'? Bar<[i32; 3]>
 }
 "#,
     );
@@ -955,24 +957,3 @@ fn f() {
     "#,
     );
 }
-
-#[test]
-fn coerce_nested_unsized_struct() {
-    check_types(
-        r#"
-//- minicore: fn, coerce_unsized, dispatch_from_dyn, sized
-use core::marker::Unsize;
-
-struct Foo<T: ?Sized>(T);
-
-fn need(_: &Foo<dyn Fn(i32) -> i32>) {
-}
-
-fn test() {
-    let callback = |x| x;
-                  //^ i32
-    need(&Foo(callback));
-}
-"#,
-    )
-}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index f0eb41b1ce7..dda7bfb2baf 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -4694,21 +4694,21 @@ fn f<T: Send, U>() {
     Struct::<T>::IS_SEND;
   //^^^^^^^^^^^^^^^^^^^^Yes
     Struct::<U>::IS_SEND;
-  //^^^^^^^^^^^^^^^^^^^^{unknown}
+  //^^^^^^^^^^^^^^^^^^^^Yes
     Struct::<*const T>::IS_SEND;
-  //^^^^^^^^^^^^^^^^^^^^^^^^^^^{unknown}
+  //^^^^^^^^^^^^^^^^^^^^^^^^^^^Yes
     Enum::<T>::IS_SEND;
   //^^^^^^^^^^^^^^^^^^Yes
     Enum::<U>::IS_SEND;
-  //^^^^^^^^^^^^^^^^^^{unknown}
+  //^^^^^^^^^^^^^^^^^^Yes
     Enum::<*const T>::IS_SEND;
-  //^^^^^^^^^^^^^^^^^^^^^^^^^{unknown}
+  //^^^^^^^^^^^^^^^^^^^^^^^^^Yes
     Union::<T>::IS_SEND;
   //^^^^^^^^^^^^^^^^^^^Yes
     Union::<U>::IS_SEND;
-  //^^^^^^^^^^^^^^^^^^^{unknown}
+  //^^^^^^^^^^^^^^^^^^^Yes
     Union::<*const T>::IS_SEND;
-  //^^^^^^^^^^^^^^^^^^^^^^^^^^{unknown}
+  //^^^^^^^^^^^^^^^^^^^^^^^^^^Yes
     PhantomData::<T>::IS_SEND;
   //^^^^^^^^^^^^^^^^^^^^^^^^^Yes
     PhantomData::<U>::IS_SEND;
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
index fb533077d96..05105c8c92c 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
@@ -20,6 +20,7 @@ pub struct AssistConfig {
     pub assist_emit_must_use: bool,
     pub term_search_fuel: u64,
     pub term_search_borrowck: bool,
+    pub code_action_grouping: bool,
 }
 
 impl AssistConfig {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
index 081e36b4ff6..220259451e8 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
@@ -48,6 +48,10 @@ use crate::{
 // }
 // ```
 pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+    if !ctx.config.code_action_grouping {
+        return None;
+    }
+
     let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
     let strukt_name = strukt.name()?;
     let current_module = ctx.sema.scope(strukt.syntax())?.module();
@@ -213,7 +217,9 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
 
 #[cfg(test)]
 mod tests {
-    use crate::tests::{check_assist, check_assist_not_applicable};
+    use crate::tests::{
+        check_assist, check_assist_not_applicable, check_assist_not_applicable_no_grouping,
+    };
 
     use super::*;
 
@@ -717,4 +723,21 @@ impl Person {
 "#,
         );
     }
+
+    #[test]
+    fn delegate_method_skipped_when_no_grouping() {
+        check_assist_not_applicable_no_grouping(
+            generate_delegate_methods,
+            r#"
+struct Age(u8);
+impl Age {
+    fn age(&self) -> u8 {
+        self.0
+    }
+}
+struct Person {
+    ag$0e: Age,
+}"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
index 66bf9b01868..55b860d0ff5 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
@@ -88,6 +88,10 @@ use syntax::{
 // }
 // ```
 pub(crate) fn generate_delegate_trait(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+    if !ctx.config.code_action_grouping {
+        return None;
+    }
+
     let strukt = Struct::new(ctx.find_node_at_offset::<ast::Struct>()?)?;
 
     let field: Field = match ctx.find_node_at_offset::<ast::RecordField>() {
@@ -788,7 +792,9 @@ fn qualified_path(qual_path_ty: ast::Path, path_expr_seg: ast::Path) -> ast::Pat
 mod test {
 
     use super::*;
-    use crate::tests::{check_assist, check_assist_not_applicable};
+    use crate::tests::{
+        check_assist, check_assist_not_applicable, check_assist_not_applicable_no_grouping,
+    };
 
     #[test]
     fn test_tuple_struct_basic() {
@@ -1836,4 +1842,33 @@ impl<D, T: C<A>> C<D> for B<T> {
 "#,
         )
     }
+
+    #[test]
+    fn delegate_trait_skipped_when_no_grouping() {
+        check_assist_not_applicable_no_grouping(
+            generate_delegate_trait,
+            r#"
+trait SomeTrait {
+    type T;
+    fn fn_(arg: u32) -> u32;
+    fn method_(&mut self) -> bool;
+}
+struct A;
+impl SomeTrait for A {
+    type T = u32;
+
+    fn fn_(arg: u32) -> u32 {
+        42
+    }
+
+    fn method_(&mut self) -> bool {
+        false
+    }
+}
+struct B {
+    a$0 : A,
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
index 48d2af6d3ff..11aeb21c77e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
@@ -34,6 +34,26 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
     assist_emit_must_use: false,
     term_search_fuel: 400,
     term_search_borrowck: true,
+    code_action_grouping: true,
+};
+
+pub(crate) const TEST_CONFIG_NO_GROUPING: AssistConfig = AssistConfig {
+    snippet_cap: SnippetCap::new(true),
+    allowed: None,
+    insert_use: InsertUseConfig {
+        granularity: ImportGranularity::Crate,
+        prefix_kind: hir::PrefixKind::Plain,
+        enforce_granularity: true,
+        group: true,
+        skip_glob_imports: true,
+    },
+    prefer_no_std: false,
+    prefer_prelude: true,
+    prefer_absolute: false,
+    assist_emit_must_use: false,
+    term_search_fuel: 400,
+    term_search_borrowck: true,
+    code_action_grouping: false,
 };
 
 pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig {
@@ -52,6 +72,7 @@ pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig {
     assist_emit_must_use: false,
     term_search_fuel: 400,
     term_search_borrowck: true,
+    code_action_grouping: true,
 };
 
 pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig {
@@ -70,6 +91,7 @@ pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig {
     assist_emit_must_use: false,
     term_search_fuel: 400,
     term_search_borrowck: true,
+    code_action_grouping: true,
 };
 
 pub(crate) fn with_single_file(text: &str) -> (RootDatabase, EditionedFileId) {
@@ -173,6 +195,20 @@ pub(crate) fn check_assist_not_applicable_for_import_one(
     );
 }
 
+#[track_caller]
+pub(crate) fn check_assist_not_applicable_no_grouping(
+    assist: Handler,
+    #[rust_analyzer::rust_fixture] ra_fixture: &str,
+) {
+    check_with_config(
+        TEST_CONFIG_NO_GROUPING,
+        assist,
+        ra_fixture,
+        ExpectedResult::NotApplicable,
+        None,
+    );
+}
+
 /// Check assist in unresolved state. Useful to check assists for lazy computation.
 #[track_caller]
 pub(crate) fn check_assist_unresolved(
diff --git a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
index 17f0e69bde4..c8a8a2d1698 100644
--- a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
@@ -30,7 +30,6 @@ bitflags.workspace = true
 
 # local deps
 base-db.workspace = true
-limit.workspace = true
 parser.workspace = true
 profile.workspace = true
 stdx.workspace = true
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
index ad86d855b55..77fc59b4ecc 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
@@ -357,7 +357,7 @@ fn path_applicable_imports(
                 let mod_path = mod_path(item)?;
                 Some(LocatedImport::new(mod_path, item, item))
             })
-            .take(DEFAULT_QUERY_SEARCH_LIMIT.inner())
+            .take(DEFAULT_QUERY_SEARCH_LIMIT)
             .collect()
         }
         // we have some unresolved qualifier that we search an import for
@@ -383,7 +383,7 @@ fn path_applicable_imports(
                 qualifier_rest,
             )
         })
-        .take(DEFAULT_QUERY_SEARCH_LIMIT.inner())
+        .take(DEFAULT_QUERY_SEARCH_LIMIT)
         .collect(),
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs b/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs
index a2062f36d3f..4d9c051354a 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs
@@ -6,7 +6,6 @@ use std::ops::ControlFlow;
 
 use either::Either;
 use hir::{import_map, Crate, ItemInNs, Module, Semantics};
-use limit::Limit;
 
 use crate::{
     imports::import_assets::NameToImport,
@@ -15,7 +14,7 @@ use crate::{
 };
 
 /// A value to use, when uncertain which limit to pick.
-pub static DEFAULT_QUERY_SEARCH_LIMIT: Limit = Limit::new(100);
+pub const DEFAULT_QUERY_SEARCH_LIMIT: usize = 100;
 
 pub use import_map::AssocSearchMode;
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
index 99894fefef3..2f132985895 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
@@ -133,7 +133,7 @@ macro_rules! env { () => {} }
 macro_rules! concat { () => {} }
 
   include!(concat!(env!("OUT_DIR"), "/out.rs"));
-                      //^^^^^^^^^ error: `OUT_DIR` not set, enable "build scripts" to fix
+                      //^^^^^^^^^ error: `OUT_DIR` not set, build scripts may have failed to run
 "#,
         );
     }
@@ -186,7 +186,7 @@ fn main() {
        //^^^^^^^ error: expected string literal
 
     env!("OUT_DIR");
-       //^^^^^^^^^ error: `OUT_DIR` not set, enable "build scripts" to fix
+       //^^^^^^^^^ error: `OUT_DIR` not set, build scripts may have failed to run
 
     compile_error!("compile_error works");
   //^^^^^^^^^^^^^ error: compile_error works
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index e942f5a6aac..27a1a510b4f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -252,14 +252,14 @@ impl Analysis {
             Arc::new(cfg_options),
             None,
             Env::default(),
-            false,
             CrateOrigin::Local { repo: None, name: None },
+            false,
+            None,
         );
         change.change_file(file_id, Some(text));
         let ws_data = crate_graph
             .iter()
             .zip(iter::repeat(Arc::new(CrateWorkspaceData {
-                proc_macro_cwd: None,
                 data_layout: Err("fixture has no layout".into()),
                 toolchain: None,
             })))
diff --git a/src/tools/rust-analyzer/crates/ide/src/status.rs b/src/tools/rust-analyzer/crates/ide/src/status.rs
index b0022cfac76..f8ecaa8fdf2 100644
--- a/src/tools/rust-analyzer/crates/ide/src/status.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/status.rs
@@ -68,6 +68,7 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
                 dependencies,
                 origin,
                 is_proc_macro,
+                proc_macro_cwd,
             } = &crate_graph[crate_id];
             format_to!(
                 buf,
@@ -85,6 +86,7 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
             format_to!(buf, "    Env: {:?}\n", env);
             format_to!(buf, "    Origin: {:?}\n", origin);
             format_to!(buf, "    Is a proc macro crate: {}\n", is_proc_macro);
+            format_to!(buf, "    Proc macro cwd: {:?}\n", proc_macro_cwd);
             let deps = dependencies
                 .iter()
                 .map(|dep| format!("{}={}", dep.name, dep.crate_id.into_raw()))
diff --git a/src/tools/rust-analyzer/crates/limit/Cargo.toml b/src/tools/rust-analyzer/crates/limit/Cargo.toml
deleted file mode 100644
index 30666f5219a..00000000000
--- a/src/tools/rust-analyzer/crates/limit/Cargo.toml
+++ /dev/null
@@ -1,16 +0,0 @@
-[package]
-name = "limit"
-version = "0.0.0"
-repository.workspace = true
-description = "A struct to enforce limits for rust-analyzer."
-
-authors.workspace = true
-edition.workspace = true
-license.workspace = true
-rust-version.workspace = true
-
-[features]
-tracking = []
-
-[lints]
-workspace = true
diff --git a/src/tools/rust-analyzer/crates/limit/src/lib.rs b/src/tools/rust-analyzer/crates/limit/src/lib.rs
deleted file mode 100644
index c1caeed2f87..00000000000
--- a/src/tools/rust-analyzer/crates/limit/src/lib.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-//! limit defines a struct to enforce limits.
-
-#[cfg(feature = "tracking")]
-use std::sync::atomic::AtomicUsize;
-
-/// Represents a struct used to enforce a numerical limit.
-#[derive(Debug)]
-pub struct Limit {
-    upper_bound: usize,
-    #[cfg(feature = "tracking")]
-    max: AtomicUsize,
-}
-
-impl Limit {
-    /// Creates a new limit.
-    #[inline]
-    pub const fn new(upper_bound: usize) -> Self {
-        Self {
-            upper_bound,
-            #[cfg(feature = "tracking")]
-            max: AtomicUsize::new(0),
-        }
-    }
-
-    /// Creates a new limit.
-    #[inline]
-    #[cfg(feature = "tracking")]
-    pub const fn new_tracking(upper_bound: usize) -> Self {
-        Self {
-            upper_bound,
-            #[cfg(feature = "tracking")]
-            max: AtomicUsize::new(1),
-        }
-    }
-
-    /// Gets the underlying numeric limit.
-    #[inline]
-    pub const fn inner(&self) -> usize {
-        self.upper_bound
-    }
-
-    /// Checks whether the given value is below the limit.
-    /// Returns `Ok` when `other` is below `self`, and `Err` otherwise.
-    #[inline]
-    pub fn check(&self, other: usize) -> Result<(), ()> {
-        if other > self.upper_bound {
-            Err(())
-        } else {
-            #[cfg(feature = "tracking")]
-            loop {
-                use std::sync::atomic::Ordering;
-                let old_max = self.max.load(Ordering::Relaxed);
-                if other <= old_max || old_max == 0 {
-                    break;
-                }
-                _ = self.max.compare_exchange_weak(
-                    old_max,
-                    other,
-                    Ordering::Relaxed,
-                    Ordering::Relaxed,
-                );
-            }
-
-            Ok(())
-        }
-    }
-}
diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
index 67ee9d11199..76f1a7f48b6 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -456,7 +456,6 @@ fn load_crate_graph(
     let ws_data = crate_graph
         .iter()
         .zip(iter::repeat(From::from(CrateWorkspaceData {
-            proc_macro_cwd: None,
             data_layout: target_layout.clone(),
             toolchain: toolchain.clone(),
         })))
diff --git a/src/tools/rust-analyzer/crates/parser/Cargo.toml b/src/tools/rust-analyzer/crates/parser/Cargo.toml
index 3629d275c0c..48436ec71f7 100644
--- a/src/tools/rust-analyzer/crates/parser/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/parser/Cargo.toml
@@ -15,7 +15,6 @@ doctest = false
 [dependencies]
 drop_bomb = "0.1.5"
 ra-ap-rustc_lexer.workspace = true
-limit.workspace = true
 tracing = { workspace = true, optional = true }
 
 edition.workspace = true
diff --git a/src/tools/rust-analyzer/crates/parser/src/parser.rs b/src/tools/rust-analyzer/crates/parser/src/parser.rs
index 2f6ba525747..b0586862764 100644
--- a/src/tools/rust-analyzer/crates/parser/src/parser.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/parser.rs
@@ -3,7 +3,6 @@
 use std::cell::Cell;
 
 use drop_bomb::DropBomb;
-use limit::Limit;
 
 use crate::{
     event::Event,
@@ -30,7 +29,7 @@ pub(crate) struct Parser<'t> {
     edition: Edition,
 }
 
-static PARSER_STEP_LIMIT: Limit = Limit::new(15_000_000);
+const PARSER_STEP_LIMIT: usize = 15_000_000;
 
 impl<'t> Parser<'t> {
     pub(super) fn new(inp: &'t Input, edition: Edition) -> Parser<'t> {
@@ -54,7 +53,7 @@ impl<'t> Parser<'t> {
         assert!(n <= 3);
 
         let steps = self.steps.get();
-        assert!(PARSER_STEP_LIMIT.check(steps as usize).is_ok(), "the parser seems stuck");
+        assert!((steps as usize) < PARSER_STEP_LIMIT, "the parser seems stuck");
         self.steps.set(steps + 1);
 
         self.inp.kind(self.pos + n)
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
index c8ea8c547a9..1a747731587 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
+++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
@@ -721,16 +721,16 @@ mod err {
     #[test]
     fn bad_asm_expr() { run_and_expect_errors("test_data/parser/inline/err/bad_asm_expr.rs"); }
     #[test]
+    fn comma_after_default_values_syntax() {
+        run_and_expect_errors("test_data/parser/inline/err/comma_after_default_values_syntax.rs");
+    }
+    #[test]
     fn comma_after_functional_update_syntax() {
         run_and_expect_errors(
             "test_data/parser/inline/err/comma_after_functional_update_syntax.rs",
         );
     }
     #[test]
-    fn comma_after_default_values_syntax() {
-        run_and_expect_errors("test_data/parser/inline/err/comma_after_default_values_syntax.rs");
-    }
-    #[test]
     fn crate_visibility_empty_recover() {
         run_and_expect_errors("test_data/parser/inline/err/crate_visibility_empty_recover.rs");
     }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
index feee40a1fc9..2f9612e3a47 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
@@ -164,6 +164,7 @@ impl ProjectJson {
                         is_proc_macro: crate_data.is_proc_macro,
                         repository: crate_data.repository,
                         build,
+                        proc_macro_cwd: crate_data.proc_macro_cwd.map(absolutize_on_base),
                     }
                 })
                 .collect(),
@@ -240,6 +241,8 @@ pub struct Crate {
     pub(crate) include: Vec<AbsPathBuf>,
     pub(crate) exclude: Vec<AbsPathBuf>,
     pub(crate) is_proc_macro: bool,
+    /// The working directory to run proc-macros in. This is usually the workspace root of cargo workspaces.
+    pub(crate) proc_macro_cwd: Option<AbsPathBuf>,
     pub(crate) repository: Option<String>,
     pub build: Option<Build>,
 }
@@ -362,6 +365,8 @@ struct CrateData {
     repository: Option<String>,
     #[serde(default)]
     build: Option<BuildData>,
+    #[serde(default)]
+    proc_macro_cwd: Option<Utf8PathBuf>,
 }
 
 mod cfg_ {
diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
index 544ba43ba66..fb752fe47b3 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
@@ -312,8 +312,8 @@ impl Sysroot {
                     RustLibSrcWorkspace::Empty => true,
                 };
                 if !has_core {
-                    let var_note = if env::var_os("rust_lib_src_PATH").is_some() {
-                        " (env var `rust_lib_src_PATH` is set and may be incorrect, try unsetting it)"
+                    let var_note = if env::var_os("RUST_SRC_PATH").is_some() {
+                        " (env var `RUST_SRC_PATH` is set and may be incorrect, try unsetting it)"
                     } else {
                         ", try running `rustup component add rust-src` to possibly fix this"
                     };
@@ -422,18 +422,16 @@ fn discover_sysroot_dir(
 }
 
 fn discover_rust_lib_src_dir(sysroot_path: &AbsPathBuf) -> Option<AbsPathBuf> {
-    if let Ok(path) = env::var("rust_lib_src_PATH") {
+    if let Ok(path) = env::var("RUST_SRC_PATH") {
         if let Ok(path) = AbsPathBuf::try_from(path.as_str()) {
             let core = path.join("core");
             if fs::metadata(&core).is_ok() {
-                tracing::debug!("Discovered sysroot by rust_lib_src_PATH: {path}");
+                tracing::debug!("Discovered sysroot by RUST_SRC_PATH: {path}");
                 return Some(path);
             }
-            tracing::debug!(
-                "rust_lib_src_PATH is set, but is invalid (no core: {core:?}), ignoring"
-            );
+            tracing::debug!("RUST_SRC_PATH is set, but is invalid (no core: {core:?}), ignoring");
         } else {
-            tracing::debug!("rust_lib_src_PATH is set, but is invalid, ignoring");
+            tracing::debug!("RUST_SRC_PATH is set, but is invalid, ignoring");
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index f5d46daa80f..16b5bb11afa 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -958,6 +958,7 @@ fn project_json_to_crate_graph(
                     is_proc_macro,
                     repository,
                     is_workspace_member,
+                    proc_macro_cwd,
                     ..
                 },
                 file_id,
@@ -1005,7 +1006,6 @@ fn project_json_to_crate_graph(
                     Arc::new(cfg_options),
                     None,
                     env,
-                    *is_proc_macro,
                     if let Some(name) = display_name.clone() {
                         CrateOrigin::Local {
                             repo: repository.clone(),
@@ -1014,6 +1014,8 @@ fn project_json_to_crate_graph(
                     } else {
                         CrateOrigin::Local { repo: None, name: None }
                     },
+                    *is_proc_macro,
+                    proc_macro_cwd.clone(),
                 );
                 debug!(
                     ?crate_graph_crate_id,
@@ -1283,11 +1285,12 @@ fn detached_file_to_crate_graph(
         cfg_options.clone(),
         None,
         Env::default(),
-        false,
         CrateOrigin::Local {
             repo: None,
             name: display_name.map(|n| n.canonical_name().to_owned()),
         },
+        false,
+        None,
     );
 
     public_deps.add_to_crate_graph(&mut crate_graph, detached_file_crate);
@@ -1448,8 +1451,13 @@ fn add_target_crate_root(
         Arc::new(cfg_options),
         potential_cfg_options.map(Arc::new),
         env,
-        matches!(kind, TargetKind::Lib { is_proc_macro: true }),
         origin,
+        matches!(kind, TargetKind::Lib { is_proc_macro: true }),
+        Some(if pkg.is_member {
+            cargo.workspace_root().to_path_buf()
+        } else {
+            pkg.manifest.parent().to_path_buf()
+        }),
     );
     if let TargetKind::Lib { is_proc_macro: true } = kind {
         let proc_macro = match build_data {
@@ -1587,8 +1595,9 @@ fn sysroot_to_crate_graph(
                         cfg_options.clone(),
                         None,
                         Env::default(),
-                        false,
                         CrateOrigin::Lang(LangCrateOrigin::from(&*stitched[krate].name)),
+                        false,
+                        None,
                     );
                     Some((krate, crate_id))
                 })
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
index 880e90c52a5..fae0b6fcca4 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
@@ -61,6 +61,11 @@
             ),
         },
         is_proc_macro: false,
+        proc_macro_cwd: Some(
+            AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
+        ),
     },
     1: CrateData {
         root_file_id: FileId(
@@ -132,6 +137,11 @@
             ),
         },
         is_proc_macro: false,
+        proc_macro_cwd: Some(
+            AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
+        ),
     },
     2: CrateData {
         root_file_id: FileId(
@@ -203,6 +213,11 @@
             ),
         },
         is_proc_macro: false,
+        proc_macro_cwd: Some(
+            AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
+        ),
     },
     3: CrateData {
         root_file_id: FileId(
@@ -274,6 +289,11 @@
             ),
         },
         is_proc_macro: false,
+        proc_macro_cwd: Some(
+            AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
+        ),
     },
     4: CrateData {
         root_file_id: FileId(
@@ -341,5 +361,10 @@
             name: "libc",
         },
         is_proc_macro: false,
+        proc_macro_cwd: Some(
+            AbsPathBuf(
+                "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
+            ),
+        ),
     },
 }
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
index 880e90c52a5..fae0b6fcca4 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
@@ -61,6 +61,11 @@
             ),
         },
         is_proc_macro: false,
+        proc_macro_cwd: Some(
+            AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
+        ),
     },
     1: CrateData {
         root_file_id: FileId(
@@ -132,6 +137,11 @@
             ),
         },
         is_proc_macro: false,
+        proc_macro_cwd: Some(
+            AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
+        ),
     },
     2: CrateData {
         root_file_id: FileId(
@@ -203,6 +213,11 @@
             ),
         },
         is_proc_macro: false,
+        proc_macro_cwd: Some(
+            AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
+        ),
     },
     3: CrateData {
         root_file_id: FileId(
@@ -274,6 +289,11 @@
             ),
         },
         is_proc_macro: false,
+        proc_macro_cwd: Some(
+            AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
+        ),
     },
     4: CrateData {
         root_file_id: FileId(
@@ -341,5 +361,10 @@
             name: "libc",
         },
         is_proc_macro: false,
+        proc_macro_cwd: Some(
+            AbsPathBuf(
+                "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
+            ),
+        ),
     },
 }
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
index 7746acd225e..566174882dd 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
@@ -60,6 +60,11 @@
             ),
         },
         is_proc_macro: false,
+        proc_macro_cwd: Some(
+            AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
+        ),
     },
     1: CrateData {
         root_file_id: FileId(
@@ -130,6 +135,11 @@
             ),
         },
         is_proc_macro: false,
+        proc_macro_cwd: Some(
+            AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
+        ),
     },
     2: CrateData {
         root_file_id: FileId(
@@ -200,6 +210,11 @@
             ),
         },
         is_proc_macro: false,
+        proc_macro_cwd: Some(
+            AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
+        ),
     },
     3: CrateData {
         root_file_id: FileId(
@@ -270,6 +285,11 @@
             ),
         },
         is_proc_macro: false,
+        proc_macro_cwd: Some(
+            AbsPathBuf(
+                "$ROOT$hello-world",
+            ),
+        ),
     },
     4: CrateData {
         root_file_id: FileId(
@@ -337,5 +357,10 @@
             name: "libc",
         },
         is_proc_macro: false,
+        proc_macro_cwd: Some(
+            AbsPathBuf(
+                "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
+            ),
+        ),
     },
 }
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt
index 587d3c17827..9b4be19c41c 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_cfg_groups.txt
@@ -38,6 +38,7 @@
             Alloc,
         ),
         is_proc_macro: false,
+        proc_macro_cwd: None,
     },
     1: CrateData {
         root_file_id: FileId(
@@ -69,6 +70,7 @@
             Core,
         ),
         is_proc_macro: false,
+        proc_macro_cwd: None,
     },
     2: CrateData {
         root_file_id: FileId(
@@ -100,6 +102,7 @@
             Other,
         ),
         is_proc_macro: false,
+        proc_macro_cwd: None,
     },
     3: CrateData {
         root_file_id: FileId(
@@ -131,6 +134,7 @@
             Other,
         ),
         is_proc_macro: false,
+        proc_macro_cwd: None,
     },
     4: CrateData {
         root_file_id: FileId(
@@ -179,6 +183,7 @@
             ProcMacro,
         ),
         is_proc_macro: false,
+        proc_macro_cwd: None,
     },
     5: CrateData {
         root_file_id: FileId(
@@ -210,6 +215,7 @@
             Other,
         ),
         is_proc_macro: false,
+        proc_macro_cwd: None,
     },
     6: CrateData {
         root_file_id: FileId(
@@ -306,6 +312,7 @@
             Std,
         ),
         is_proc_macro: false,
+        proc_macro_cwd: None,
     },
     7: CrateData {
         root_file_id: FileId(
@@ -337,6 +344,7 @@
             Other,
         ),
         is_proc_macro: false,
+        proc_macro_cwd: None,
     },
     8: CrateData {
         root_file_id: FileId(
@@ -368,6 +376,7 @@
             Test,
         ),
         is_proc_macro: false,
+        proc_macro_cwd: None,
     },
     9: CrateData {
         root_file_id: FileId(
@@ -399,6 +408,7 @@
             Other,
         ),
         is_proc_macro: false,
+        proc_macro_cwd: None,
     },
     10: CrateData {
         root_file_id: FileId(
@@ -477,6 +487,7 @@
             ),
         },
         is_proc_macro: false,
+        proc_macro_cwd: None,
     },
     11: CrateData {
         root_file_id: FileId(
@@ -555,5 +566,6 @@
             ),
         },
         is_proc_macro: false,
+        proc_macro_cwd: None,
     },
 }
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
index 00805c79bcc..4c8e66e8e96 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
@@ -38,6 +38,7 @@
             Alloc,
         ),
         is_proc_macro: false,
+        proc_macro_cwd: None,
     },
     1: CrateData {
         root_file_id: FileId(
@@ -69,6 +70,7 @@
             Core,
         ),
         is_proc_macro: false,
+        proc_macro_cwd: None,
     },
     2: CrateData {
         root_file_id: FileId(
@@ -100,6 +102,7 @@
             Other,
         ),
         is_proc_macro: false,
+        proc_macro_cwd: None,
     },
     3: CrateData {
         root_file_id: FileId(
@@ -131,6 +134,7 @@
             Other,
         ),
         is_proc_macro: false,
+        proc_macro_cwd: None,
     },
     4: CrateData {
         root_file_id: FileId(
@@ -179,6 +183,7 @@
             ProcMacro,
         ),
         is_proc_macro: false,
+        proc_macro_cwd: None,
     },
     5: CrateData {
         root_file_id: FileId(
@@ -210,6 +215,7 @@
             Other,
         ),
         is_proc_macro: false,
+        proc_macro_cwd: None,
     },
     6: CrateData {
         root_file_id: FileId(
@@ -306,6 +312,7 @@
             Std,
         ),
         is_proc_macro: false,
+        proc_macro_cwd: None,
     },
     7: CrateData {
         root_file_id: FileId(
@@ -337,6 +344,7 @@
             Other,
         ),
         is_proc_macro: false,
+        proc_macro_cwd: None,
     },
     8: CrateData {
         root_file_id: FileId(
@@ -368,6 +376,7 @@
             Test,
         ),
         is_proc_macro: false,
+        proc_macro_cwd: None,
     },
     9: CrateData {
         root_file_id: FileId(
@@ -399,6 +408,7 @@
             Other,
         ),
         is_proc_macro: false,
+        proc_macro_cwd: None,
     },
     10: CrateData {
         root_file_id: FileId(
@@ -474,5 +484,6 @@
             ),
         },
         is_proc_macro: false,
+        proc_macro_cwd: None,
     },
 }
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index d7e9a5c586c..1dce0bea1a9 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -1476,6 +1476,7 @@ impl Config {
             prefer_absolute: self.imports_prefixExternPrelude(source_root).to_owned(),
             term_search_fuel: self.assist_termSearch_fuel(source_root).to_owned() as u64,
             term_search_borrowck: self.assist_termSearch_borrowcheck(source_root).to_owned(),
+            code_action_grouping: self.code_action_group(),
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index ba72ea35df6..56dcad0eb18 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -885,7 +885,6 @@ pub fn ws_to_crate_graph(
         ws_data.extend(mapping.values().copied().zip(iter::repeat(Arc::new(CrateWorkspaceData {
             toolchain: toolchain.clone(),
             data_layout: target_layout.clone(),
-            proc_macro_cwd: Some(ws.workspace_root().to_owned()),
         }))));
         proc_macro_paths.push(crate_proc_macros);
     }
diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
index 613f27c7958..37dfb87721c 100644
--- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
@@ -211,8 +211,9 @@ impl ChangeFixture {
                     From::from(meta.cfg.clone()),
                     Some(From::from(meta.cfg)),
                     meta.env,
-                    false,
                     origin,
+                    false,
+                    None,
                 );
                 let prev = crates.insert(crate_name.clone(), crate_id);
                 assert!(prev.is_none(), "multiple crates with same name: {crate_name}");
@@ -249,8 +250,9 @@ impl ChangeFixture {
                 From::from(default_cfg.clone()),
                 Some(From::from(default_cfg)),
                 default_env,
-                false,
                 CrateOrigin::Local { repo: None, name: None },
+                false,
+                None,
             );
         } else {
             for (from, to, prelude) in crate_deps {
@@ -286,8 +288,9 @@ impl ChangeFixture {
                     String::from("__ra_is_test_fixture"),
                     String::from("__ra_is_test_fixture"),
                 )]),
-                false,
                 CrateOrigin::Lang(LangCrateOrigin::Core),
+                false,
+                None,
             );
 
             for krate in all_crates {
@@ -333,8 +336,9 @@ impl ChangeFixture {
                     String::from("__ra_is_test_fixture"),
                     String::from("__ra_is_test_fixture"),
                 )]),
-                true,
                 CrateOrigin::Local { repo: None, name: None },
+                true,
+                None,
             );
             proc_macros.insert(proc_macros_crate, Ok(proc_macro));
 
@@ -362,7 +366,6 @@ impl ChangeFixture {
             crate_graph
                 .iter()
                 .zip(iter::repeat(From::from(CrateWorkspaceData {
-                    proc_macro_cwd: None,
                     data_layout: target_data_layout,
                     toolchain,
                 })))
diff --git a/src/tools/rust-analyzer/docs/book/book.toml b/src/tools/rust-analyzer/docs/book/book.toml
index 5ca4badde87..a6f6a6ed784 100644
--- a/src/tools/rust-analyzer/docs/book/book.toml
+++ b/src/tools/rust-analyzer/docs/book/book.toml
@@ -34,3 +34,8 @@ use-boolean-and = true
 [output.html.fold]
 enable = true
 level = 3
+
+[preprocessor.toc]
+command = "mdbook-toc"
+renderer = ["html"]
+max-level = 3
diff --git a/src/tools/rust-analyzer/docs/book/src/SUMMARY.md b/src/tools/rust-analyzer/docs/book/src/SUMMARY.md
index 9dc4f1f2d2a..1f211a97d78 100644
--- a/src/tools/rust-analyzer/docs/book/src/SUMMARY.md
+++ b/src/tools/rust-analyzer/docs/book/src/SUMMARY.md
@@ -14,3 +14,11 @@
   - [Assists (Code Actions)](assists.md)
   - [Diagnostics](diagnostics.md)
 - [Editor Features](editor_features.md)
+- [Contributing](contributing/README.md)
+  - [Architecture](contributing/architecture.md)
+  - [Debugging](contributing/debugging.md)
+  - [Guide](contributing/guide.md)
+  - [LSP Extensions](contributing/lsp-extensions.md)
+  - [Setup](contributing/setup.md)
+  - [Style](contributing/style.md)
+  - [Syntax](contributing/syntax.md)
diff --git a/src/tools/rust-analyzer/docs/book/src/assists_generated.md b/src/tools/rust-analyzer/docs/book/src/assists_generated.md
index 3617badeef5..9d68a873ffe 100644
--- a/src/tools/rust-analyzer/docs/book/src/assists_generated.md
+++ b/src/tools/rust-analyzer/docs/book/src/assists_generated.md
@@ -1,7 +1,7 @@
 //! Generated by `cargo xtask codegen assists-doc-tests`, do not edit by hand.
 
 ### `add_braces`
-**Source:**  [add_braces.rs](crates/ide-assists/src/handlers/add_braces.rs#8) 
+**Source:**  [add_braces.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/add_braces.rs#L8) 
 
 Adds braces to lambda and match arm expressions.
 
@@ -29,7 +29,7 @@ fn foo(n: i32) -> i32 {
 
 
 ### `add_explicit_type`
-**Source:**  [add_explicit_type.rs](crates/ide-assists/src/handlers/add_explicit_type.rs#7) 
+**Source:**  [add_explicit_type.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/add_explicit_type.rs#L7) 
 
 Specify type for a let binding.
 
@@ -49,7 +49,7 @@ fn main() {
 
 
 ### `add_hash`
-**Source:**  [raw_string.rs](crates/ide-assists/src/handlers/raw_string.rs#89) 
+**Source:**  [raw_string.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/raw_string.rs#L89) 
 
 Adds a hash to a raw string literal.
 
@@ -69,7 +69,7 @@ fn main() {
 
 
 ### `add_impl_default_members`
-**Source:**  [add_missing_impl_members.rs](crates/ide-assists/src/handlers/add_missing_impl_members.rs#58) 
+**Source:**  [add_missing_impl_members.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/add_missing_impl_members.rs#L58) 
 
 Adds scaffold for overriding default impl members.
 
@@ -105,7 +105,7 @@ impl Trait for () {
 
 
 ### `add_impl_missing_members`
-**Source:**  [add_missing_impl_members.rs](crates/ide-assists/src/handlers/add_missing_impl_members.rs#16) 
+**Source:**  [add_missing_impl_members.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/add_missing_impl_members.rs#L16) 
 
 Adds scaffold for required impl members.
 
@@ -141,7 +141,7 @@ impl Trait<u32> for () {
 
 
 ### `add_label_to_loop`
-**Source:**  [add_label_to_loop.rs](crates/ide-assists/src/handlers/add_label_to_loop.rs#9) 
+**Source:**  [add_label_to_loop.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/add_label_to_loop.rs#L9) 
 
 Adds a label to a loop.
 
@@ -167,7 +167,7 @@ fn main() {
 
 
 ### `add_lifetime_to_type`
-**Source:**  [add_lifetime_to_type.rs](crates/ide-assists/src/handlers/add_lifetime_to_type.rs#5) 
+**Source:**  [add_lifetime_to_type.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/add_lifetime_to_type.rs#L5) 
 
 Adds a new lifetime to a struct, enum or union.
 
@@ -189,7 +189,7 @@ struct Point<'a> {
 
 
 ### `add_missing_match_arms`
-**Source:**  [add_missing_match_arms.rs](crates/ide-assists/src/handlers/add_missing_match_arms.rs#14) 
+**Source:**  [add_missing_match_arms.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/add_missing_match_arms.rs#L16) 
 
 Adds missing clauses to a `match` expression.
 
@@ -218,7 +218,7 @@ fn handle(action: Action) {
 
 
 ### `add_return_type`
-**Source:**  [add_return_type.rs](crates/ide-assists/src/handlers/add_return_type.rs#6) 
+**Source:**  [add_return_type.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/add_return_type.rs#L6) 
 
 Adds the return type to a function or closure inferred from its tail expression if it doesn't have a return
 type specified. This assists is useable in a functions or closures tail expression or return type position.
@@ -235,7 +235,7 @@ fn foo() -> i32 { 42i32 }
 
 
 ### `add_turbo_fish`
-**Source:**  [add_turbo_fish.rs](crates/ide-assists/src/handlers/add_turbo_fish.rs#14) 
+**Source:**  [add_turbo_fish.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/add_turbo_fish.rs#L14) 
 
 Adds `::<_>` to a call of a generic method or function.
 
@@ -257,7 +257,7 @@ fn main() {
 
 
 ### `apply_demorgan`
-**Source:**  [apply_demorgan.rs](crates/ide-assists/src/handlers/apply_demorgan.rs#16) 
+**Source:**  [apply_demorgan.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/apply_demorgan.rs#L16) 
 
 Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws).
 This transforms expressions of the form `!l || !r` into `!(l && r)`.
@@ -280,7 +280,7 @@ fn main() {
 
 
 ### `apply_demorgan_iterator`
-**Source:**  [apply_demorgan.rs](crates/ide-assists/src/handlers/apply_demorgan.rs#132) 
+**Source:**  [apply_demorgan.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/apply_demorgan.rs#L132) 
 
 Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws) to
 `Iterator::all` and `Iterator::any`.
@@ -311,7 +311,7 @@ fn main() {
 
 
 ### `auto_import`
-**Source:**  [auto_import.rs](crates/ide-assists/src/handlers/auto_import.rs#73) 
+**Source:**  [auto_import.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/auto_import.rs#L73) 
 
 If the name is unresolved, provides all possible imports for it.
 
@@ -333,7 +333,7 @@ fn main() {
 
 
 ### `bind_unused_param`
-**Source:**  [bind_unused_param.rs](crates/ide-assists/src/handlers/bind_unused_param.rs#12) 
+**Source:**  [bind_unused_param.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/bind_unused_param.rs#L12) 
 
 Binds unused function parameter to an underscore.
 
@@ -351,7 +351,7 @@ fn some_function(x: i32) {
 
 
 ### `bool_to_enum`
-**Source:**  [bool_to_enum.rs](crates/ide-assists/src/handlers/bool_to_enum.rs#29) 
+**Source:**  [bool_to_enum.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/bool_to_enum.rs#L29) 
 
 This converts boolean local variables, fields, constants, and statics into a new
 enum with two variants `Bool::True` and `Bool::False`, as well as replacing
@@ -385,7 +385,7 @@ fn main() {
 
 
 ### `change_visibility`
-**Source:**  [change_visibility.rs](crates/ide-assists/src/handlers/change_visibility.rs#13) 
+**Source:**  [change_visibility.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/change_visibility.rs#L13) 
 
 Adds or changes existing visibility specifier.
 
@@ -401,7 +401,7 @@ pub(crate) fn frobnicate() {}
 
 
 ### `comment_to_doc`
-**Source:**  [convert_comment_from_or_to_doc.rs](crates/ide-assists/src/handlers/convert_comment_from_or_to_doc.rs#9) 
+**Source:**  [convert_comment_from_or_to_doc.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_comment_from_or_to_doc.rs#L9) 
 
 Converts comments to documentation.
 
@@ -419,7 +419,7 @@ Converts comments to documentation.
 
 
 ### `convert_bool_then_to_if`
-**Source:**  [convert_bool_then.rs](crates/ide-assists/src/handlers/convert_bool_then.rs#131) 
+**Source:**  [convert_bool_then.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_bool_then.rs#L131) 
 
 Converts a `bool::then` method call to an equivalent if expression.
 
@@ -443,7 +443,7 @@ fn main() {
 
 
 ### `convert_closure_to_fn`
-**Source:**  [convert_closure_to_fn.rs](crates/ide-assists/src/handlers/convert_closure_to_fn.rs#25) 
+**Source:**  [convert_closure_to_fn.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_closure_to_fn.rs#L25) 
 
 This converts a closure to a freestanding function, changing all captures to parameters.
 
@@ -469,7 +469,7 @@ fn main() {
 
 
 ### `convert_for_loop_with_for_each`
-**Source:**  [convert_iter_for_each_to_for.rs](crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs#76) 
+**Source:**  [convert_iter_for_each_to_for.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs#L76) 
 
 Converts a for loop into a for_each loop on the Iterator.
 
@@ -495,7 +495,7 @@ fn main() {
 
 
 ### `convert_from_to_tryfrom`
-**Source:**  [convert_from_to_tryfrom.rs](crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs#10) 
+**Source:**  [convert_from_to_tryfrom.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs#L10) 
 
 Converts a From impl to a TryFrom impl, wrapping returns in `Ok`.
 
@@ -527,7 +527,7 @@ impl TryFrom<usize> for Thing {
 
 
 ### `convert_if_to_bool_then`
-**Source:**  [convert_bool_then.rs](crates/ide-assists/src/handlers/convert_bool_then.rs#20) 
+**Source:**  [convert_bool_then.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_bool_then.rs#L20) 
 
 Converts an if expression into a corresponding `bool::then` call.
 
@@ -551,7 +551,7 @@ fn main() {
 
 
 ### `convert_integer_literal`
-**Source:**  [convert_integer_literal.rs](crates/ide-assists/src/handlers/convert_integer_literal.rs#5) 
+**Source:**  [convert_integer_literal.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_integer_literal.rs#L5) 
 
 Converts the base of integer literals to other bases.
 
@@ -567,7 +567,7 @@ const _: i32 = 0b1010;
 
 
 ### `convert_into_to_from`
-**Source:**  [convert_into_to_from.rs](crates/ide-assists/src/handlers/convert_into_to_from.rs#8) 
+**Source:**  [convert_into_to_from.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_into_to_from.rs#L8) 
 
 Converts an Into impl to an equivalent From impl.
 
@@ -597,7 +597,7 @@ impl From<usize> for Thing {
 
 
 ### `convert_iter_for_each_to_for`
-**Source:**  [convert_iter_for_each_to_for.rs](crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs#11) 
+**Source:**  [convert_iter_for_each_to_for.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_iter_for_each_to_for.rs#L11) 
 
 Converts an Iterator::for_each function into a for loop.
 
@@ -623,7 +623,7 @@ fn main() {
 
 
 ### `convert_let_else_to_match`
-**Source:**  [convert_let_else_to_match.rs](crates/ide-assists/src/handlers/convert_let_else_to_match.rs#9) 
+**Source:**  [convert_let_else_to_match.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_let_else_to_match.rs#L9) 
 
 Converts let-else statement to let statement and match expression.
 
@@ -646,7 +646,7 @@ fn main() {
 
 
 ### `convert_match_to_let_else`
-**Source:**  [convert_match_to_let_else.rs](crates/ide-assists/src/handlers/convert_match_to_let_else.rs#12) 
+**Source:**  [convert_match_to_let_else.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_match_to_let_else.rs#L12) 
 
 Converts let statement with match initializer to let-else statement.
 
@@ -669,7 +669,7 @@ fn foo(opt: Option<()>) {
 
 
 ### `convert_named_struct_to_tuple_struct`
-**Source:**  [convert_named_struct_to_tuple_struct.rs](crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs#11) 
+**Source:**  [convert_named_struct_to_tuple_struct.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs#L11) 
 
 Converts struct with named fields to tuple struct, and analogously for enum variants with named
 fields.
@@ -714,7 +714,7 @@ impl Point {
 
 
 ### `convert_nested_function_to_closure`
-**Source:**  [convert_nested_function_to_closure.rs](crates/ide-assists/src/handlers/convert_nested_function_to_closure.rs#7) 
+**Source:**  [convert_nested_function_to_closure.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_nested_function_to_closure.rs#L7) 
 
 Converts a function that is defined within the body of another function into a closure.
 
@@ -742,7 +742,7 @@ fn main() {
 
 
 ### `convert_to_guarded_return`
-**Source:**  [convert_to_guarded_return.rs](crates/ide-assists/src/handlers/convert_to_guarded_return.rs#24) 
+**Source:**  [convert_to_guarded_return.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_to_guarded_return.rs#L24) 
 
 Replace a large conditional with a guarded return.
 
@@ -769,7 +769,7 @@ fn main() {
 
 
 ### `convert_tuple_return_type_to_struct`
-**Source:**  [convert_tuple_return_type_to_struct.rs](crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs#20) 
+**Source:**  [convert_tuple_return_type_to_struct.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs#L20) 
 
 This converts the return type of a function from a tuple type
 into a tuple struct and updates the body accordingly.
@@ -800,7 +800,7 @@ fn foo() -> FooResult {
 
 
 ### `convert_tuple_struct_to_named_struct`
-**Source:**  [convert_tuple_struct_to_named_struct.rs](crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs#10) 
+**Source:**  [convert_tuple_struct_to_named_struct.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs#L10) 
 
 Converts tuple struct to struct with named fields, and analogously for tuple enum variants.
 
@@ -844,7 +844,7 @@ impl Point {
 
 
 ### `convert_two_arm_bool_match_to_matches_macro`
-**Source:**  [convert_two_arm_bool_match_to_matches_macro.rs](crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs#8) 
+**Source:**  [convert_two_arm_bool_match_to_matches_macro.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_two_arm_bool_match_to_matches_macro.rs#L8) 
 
 Convert 2-arm match that evaluates to a boolean into the equivalent matches! invocation.
 
@@ -867,7 +867,7 @@ fn main() {
 
 
 ### `convert_while_to_loop`
-**Source:**  [convert_while_to_loop.rs](crates/ide-assists/src/handlers/convert_while_to_loop.rs#20) 
+**Source:**  [convert_while_to_loop.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_while_to_loop.rs#L20) 
 
 Replace a while with a loop.
 
@@ -894,7 +894,7 @@ fn main() {
 
 
 ### `destructure_struct_binding`
-**Source:**  [destructure_struct_binding.rs](crates/ide-assists/src/handlers/destructure_struct_binding.rs#18) 
+**Source:**  [destructure_struct_binding.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/destructure_struct_binding.rs#L18) 
 
 Destructures a struct binding in place.
 
@@ -926,7 +926,7 @@ fn main() {
 
 
 ### `destructure_tuple_binding`
-**Source:**  [destructure_tuple_binding.rs](crates/ide-assists/src/handlers/destructure_tuple_binding.rs#19) 
+**Source:**  [destructure_tuple_binding.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/destructure_tuple_binding.rs#L19) 
 
 Destructures a tuple binding in place.
 
@@ -948,7 +948,7 @@ fn main() {
 
 
 ### `desugar_async_into_impl_future`
-**Source:**  [toggle_async_sugar.rs](crates/ide-assists/src/handlers/toggle_async_sugar.rs#103) 
+**Source:**  [toggle_async_sugar.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/toggle_async_sugar.rs#L103) 
 
 Rewrites asynchronous function from `async fn` into `-> impl Future`.
 This action does not touch the function body and therefore `0`
@@ -970,7 +970,7 @@ pub fn foo() -> impl core::future::Future<Output = usize> {
 
 
 ### `desugar_doc_comment`
-**Source:**  [desugar_doc_comment.rs](crates/ide-assists/src/handlers/desugar_doc_comment.rs#14) 
+**Source:**  [desugar_doc_comment.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/desugar_doc_comment.rs#L14) 
 
 Desugars doc-comments to the attribute form.
 
@@ -988,7 +988,7 @@ comment"]
 
 
 ### `expand_glob_import`
-**Source:**  [expand_glob_import.rs](crates/ide-assists/src/handlers/expand_glob_import.rs#18) 
+**Source:**  [expand_glob_import.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/expand_glob_import.rs#L19) 
 
 Expands glob imports.
 
@@ -1017,8 +1017,34 @@ fn qux(bar: Bar, baz: Baz) {}
 ```
 
 
+### `expand_glob_reexport`
+**Source:**  [expand_glob_import.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/expand_glob_import.rs#L81) 
+
+Expands non-private glob imports.
+
+#### Before
+```rust
+mod foo {
+    pub struct Bar;
+    pub struct Baz;
+}
+
+pub use foo::*┃;
+```
+
+#### After
+```rust
+mod foo {
+    pub struct Bar;
+    pub struct Baz;
+}
+
+pub use foo::{Bar, Baz};
+```
+
+
 ### `explicit_enum_discriminant`
-**Source:**  [explicit_enum_discriminant.rs](crates/ide-assists/src/handlers/explicit_enum_discriminant.rs#11) 
+**Source:**  [explicit_enum_discriminant.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/explicit_enum_discriminant.rs#L11) 
 
 Adds explicit discriminant to all enum variants.
 
@@ -1044,7 +1070,7 @@ enum TheEnum {
 
 
 ### `extract_constant`
-**Source:**  [extract_variable.rs](crates/ide-assists/src/handlers/extract_variable.rs#35) 
+**Source:**  [extract_variable.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/extract_variable.rs#L35) 
 
 Extracts subexpression into a constant.
 
@@ -1065,7 +1091,7 @@ fn main() {
 
 
 ### `extract_expressions_from_format_string`
-**Source:**  [extract_expressions_from_format_string.rs](crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs#14) 
+**Source:**  [extract_expressions_from_format_string.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/extract_expressions_from_format_string.rs#L14) 
 
 Move an expression out of a format string.
 
@@ -1085,7 +1111,7 @@ fn main() {
 
 
 ### `extract_function`
-**Source:**  [extract_function.rs](crates/ide-assists/src/handlers/extract_function.rs#39) 
+**Source:**  [extract_function.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/extract_function.rs#L39) 
 
 Extracts selected statements and comments into new function.
 
@@ -1117,7 +1143,7 @@ fn ┃fun_name(n: i32) {
 
 
 ### `extract_module`
-**Source:**  [extract_module.rs](crates/ide-assists/src/handlers/extract_module.rs#29) 
+**Source:**  [extract_module.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/extract_module.rs#L29) 
 
 Extracts a selected region as separate module. All the references, visibility and imports are
 resolved.
@@ -1148,7 +1174,7 @@ fn bar(name: i32) -> i32 {
 
 
 ### `extract_static`
-**Source:**  [extract_variable.rs](crates/ide-assists/src/handlers/extract_variable.rs#52) 
+**Source:**  [extract_variable.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/extract_variable.rs#L52) 
 
 Extracts subexpression into a static.
 
@@ -1169,7 +1195,7 @@ fn main() {
 
 
 ### `extract_struct_from_enum_variant`
-**Source:**  [extract_struct_from_enum_variant.rs](crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs#26) 
+**Source:**  [extract_struct_from_enum_variant.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs#L26) 
 
 Extracts a struct from enum variant.
 
@@ -1187,7 +1213,7 @@ enum A { One(One) }
 
 
 ### `extract_type_alias`
-**Source:**  [extract_type_alias.rs](crates/ide-assists/src/handlers/extract_type_alias.rs#10) 
+**Source:**  [extract_type_alias.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/extract_type_alias.rs#L10) 
 
 Extracts the selected type as a type alias.
 
@@ -1209,7 +1235,7 @@ struct S {
 
 
 ### `extract_variable`
-**Source:**  [extract_variable.rs](crates/ide-assists/src/handlers/extract_variable.rs#18) 
+**Source:**  [extract_variable.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/extract_variable.rs#L18) 
 
 Extracts subexpression into a variable.
 
@@ -1230,7 +1256,7 @@ fn main() {
 
 
 ### `fill_record_pattern_fields`
-**Source:**  [fill_record_pattern_fields.rs](crates/ide-assists/src/handlers/fill_record_pattern_fields.rs#8) 
+**Source:**  [fill_record_pattern_fields.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/fill_record_pattern_fields.rs#L8) 
 
 Fills fields by replacing rest pattern in record patterns.
 
@@ -1254,7 +1280,7 @@ fn foo(bar: Bar) {
 
 
 ### `fix_visibility`
-**Source:**  [fix_visibility.rs](crates/ide-assists/src/handlers/fix_visibility.rs#14) 
+**Source:**  [fix_visibility.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/fix_visibility.rs#L14) 
 
 Makes inaccessible item public.
 
@@ -1280,7 +1306,7 @@ fn main() {
 
 
 ### `flip_binexpr`
-**Source:**  [flip_binexpr.rs](crates/ide-assists/src/handlers/flip_binexpr.rs#8) 
+**Source:**  [flip_binexpr.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/flip_binexpr.rs#L8) 
 
 Flips operands of a binary expression.
 
@@ -1300,7 +1326,7 @@ fn main() {
 
 
 ### `flip_comma`
-**Source:**  [flip_comma.rs](crates/ide-assists/src/handlers/flip_comma.rs#10) 
+**Source:**  [flip_comma.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/flip_comma.rs#L10) 
 
 Flips two comma-separated items.
 
@@ -1320,7 +1346,7 @@ fn main() {
 
 
 ### `flip_trait_bound`
-**Source:**  [flip_trait_bound.rs](crates/ide-assists/src/handlers/flip_trait_bound.rs#9) 
+**Source:**  [flip_trait_bound.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/flip_trait_bound.rs#L9) 
 
 Flips two trait bounds.
 
@@ -1336,7 +1362,7 @@ fn foo<T: Copy + Clone>() { }
 
 
 ### `generate_constant`
-**Source:**  [generate_constant.rs](crates/ide-assists/src/handlers/generate_constant.rs#14) 
+**Source:**  [generate_constant.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_constant.rs#L14) 
 
 Generate a named constant.
 
@@ -1361,7 +1387,7 @@ fn main() {
 
 
 ### `generate_default_from_enum_variant`
-**Source:**  [generate_default_from_enum_variant.rs](crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs#6) 
+**Source:**  [generate_default_from_enum_variant.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_default_from_enum_variant.rs#L6) 
 
 Adds a Default impl for an enum using a variant.
 
@@ -1391,7 +1417,7 @@ impl Default for Version {
 
 
 ### `generate_default_from_new`
-**Source:**  [generate_default_from_new.rs](crates/ide-assists/src/handlers/generate_default_from_new.rs#13) 
+**Source:**  [generate_default_from_new.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_default_from_new.rs#L13) 
 
 Generates default implementation from new method.
 
@@ -1425,7 +1451,7 @@ impl Default for Example {
 
 
 ### `generate_delegate_methods`
-**Source:**  [generate_delegate_methods.rs](crates/ide-assists/src/handlers/generate_delegate_methods.rs#15) 
+**Source:**  [generate_delegate_methods.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_delegate_methods.rs#L15) 
 
 Generate delegate methods.
 
@@ -1465,7 +1491,7 @@ impl Person {
 
 
 ### `generate_delegate_trait`
-**Source:**  [generate_delegate_trait.rs](crates/ide-assists/src/handlers/generate_delegate_trait.rs#29) 
+**Source:**  [generate_delegate_trait.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_delegate_trait.rs#L29) 
 
 Generate delegate trait implementation for `StructField`s.
 
@@ -1531,7 +1557,7 @@ impl SomeTrait for B {
 
 
 ### `generate_deref`
-**Source:**  [generate_deref.rs](crates/ide-assists/src/handlers/generate_deref.rs#16) 
+**Source:**  [generate_deref.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_deref.rs#L16) 
 
 Generate `Deref` impl using the given struct field.
 
@@ -1561,7 +1587,7 @@ impl core::ops::Deref for B {
 
 
 ### `generate_derive`
-**Source:**  [generate_derive.rs](crates/ide-assists/src/handlers/generate_derive.rs#8) 
+**Source:**  [generate_derive.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_derive.rs#L8) 
 
 Adds a new `#[derive()]` clause to a struct or enum.
 
@@ -1584,7 +1610,7 @@ struct Point {
 
 
 ### `generate_doc_example`
-**Source:**  [generate_documentation_template.rs](crates/ide-assists/src/handlers/generate_documentation_template.rs#76) 
+**Source:**  [generate_documentation_template.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_documentation_template.rs#L76) 
 
 Generates a rustdoc example when editing an item's documentation.
 
@@ -1610,7 +1636,7 @@ pub fn add(a: i32, b: i32) -> i32 { a + b }
 
 
 ### `generate_documentation_template`
-**Source:**  [generate_documentation_template.rs](crates/ide-assists/src/handlers/generate_documentation_template.rs#13) 
+**Source:**  [generate_documentation_template.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_documentation_template.rs#L13) 
 
 Adds a documentation template above a function definition / declaration.
 
@@ -1645,7 +1671,7 @@ impl S {
 
 
 ### `generate_enum_as_method`
-**Source:**  [generate_enum_projection_method.rs](crates/ide-assists/src/handlers/generate_enum_projection_method.rs#59) 
+**Source:**  [generate_enum_projection_method.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_enum_projection_method.rs#L59) 
 
 Generate an `as_` method for this enum variant.
 
@@ -1677,7 +1703,7 @@ impl Value {
 
 
 ### `generate_enum_is_method`
-**Source:**  [generate_enum_is_method.rs](crates/ide-assists/src/handlers/generate_enum_is_method.rs#11) 
+**Source:**  [generate_enum_is_method.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_enum_is_method.rs#L11) 
 
 Generate an `is_` method for this enum variant.
 
@@ -1711,7 +1737,7 @@ impl Version {
 
 
 ### `generate_enum_try_into_method`
-**Source:**  [generate_enum_projection_method.rs](crates/ide-assists/src/handlers/generate_enum_projection_method.rs#12) 
+**Source:**  [generate_enum_projection_method.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_enum_projection_method.rs#L12) 
 
 Generate a `try_into_` method for this enum variant.
 
@@ -1743,7 +1769,7 @@ impl Value {
 
 
 ### `generate_enum_variant`
-**Source:**  [generate_enum_variant.rs](crates/ide-assists/src/handlers/generate_enum_variant.rs#10) 
+**Source:**  [generate_enum_variant.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_enum_variant.rs#L10) 
 
 Adds a variant to an enum.
 
@@ -1772,7 +1798,7 @@ fn main() {
 
 
 ### `generate_fn_type_alias_named`
-**Source:**  [generate_fn_type_alias.rs](crates/ide-assists/src/handlers/generate_fn_type_alias.rs#10) 
+**Source:**  [generate_fn_type_alias.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_fn_type_alias.rs#L10) 
 
 Generate a type alias for the function with named parameters.
 
@@ -1790,7 +1816,7 @@ unsafe fn foo(n: i32) -> i32 { 42i32 }
 
 
 ### `generate_fn_type_alias_unnamed`
-**Source:**  [generate_fn_type_alias.rs](crates/ide-assists/src/handlers/generate_fn_type_alias.rs#24) 
+**Source:**  [generate_fn_type_alias.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_fn_type_alias.rs#L24) 
 
 Generate a type alias for the function with unnamed parameters.
 
@@ -1808,7 +1834,7 @@ unsafe fn foo(n: i32) -> i32 { 42i32 }
 
 
 ### `generate_from_impl_for_enum`
-**Source:**  [generate_from_impl_for_enum.rs](crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs#8) 
+**Source:**  [generate_from_impl_for_enum.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_from_impl_for_enum.rs#L8) 
 
 Adds a From impl for this enum variant with one tuple field.
 
@@ -1830,7 +1856,7 @@ impl From<u32> for A {
 
 
 ### `generate_function`
-**Source:**  [generate_function.rs](crates/ide-assists/src/handlers/generate_function.rs#28) 
+**Source:**  [generate_function.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_function.rs#L28) 
 
 Adds a stub function with a signature matching the function under the cursor.
 
@@ -1860,7 +1886,7 @@ fn bar(arg: &str, baz: Baz) ${0:-> _} {
 
 
 ### `generate_getter`
-**Source:**  [generate_getter_or_setter.rs](crates/ide-assists/src/handlers/generate_getter_or_setter.rs#73) 
+**Source:**  [generate_getter_or_setter.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_getter_or_setter.rs#L73) 
 
 Generate a getter method.
 
@@ -1886,7 +1912,7 @@ impl Person {
 
 
 ### `generate_getter_mut`
-**Source:**  [generate_getter_or_setter.rs](crates/ide-assists/src/handlers/generate_getter_or_setter.rs#127) 
+**Source:**  [generate_getter_or_setter.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_getter_or_setter.rs#L127) 
 
 Generate a mut getter method.
 
@@ -1912,7 +1938,7 @@ impl Person {
 
 
 ### `generate_impl`
-**Source:**  [generate_impl.rs](crates/ide-assists/src/handlers/generate_impl.rs#20) 
+**Source:**  [generate_impl.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_impl.rs#L20) 
 
 Adds a new inherent impl for a type.
 
@@ -1934,7 +1960,7 @@ impl<T: Clone> Ctx<T> {┃}
 
 
 ### `generate_is_empty_from_len`
-**Source:**  [generate_is_empty_from_len.rs](crates/ide-assists/src/handlers/generate_is_empty_from_len.rs#12) 
+**Source:**  [generate_is_empty_from_len.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs#L12) 
 
 Generates is_empty implementation from the len method.
 
@@ -1969,7 +1995,7 @@ impl MyStruct {
 
 
 ### `generate_mut_trait_impl`
-**Source:**  [generate_mut_trait_impl.rs](crates/ide-assists/src/handlers/generate_mut_trait_impl.rs#12) 
+**Source:**  [generate_mut_trait_impl.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs#L12) 
 
 Adds a IndexMut impl from the `Index` trait.
 
@@ -2007,7 +2033,7 @@ impl<T> core::ops::Index<Axis> for [T; 3] {
 
 
 ### `generate_new`
-**Source:**  [generate_new.rs](crates/ide-assists/src/handlers/generate_new.rs#14) 
+**Source:**  [generate_new.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_new.rs#L14) 
 
 Adds a `fn new` for a type.
 
@@ -2033,7 +2059,7 @@ impl<T: Clone> Ctx<T> {
 
 
 ### `generate_setter`
-**Source:**  [generate_getter_or_setter.rs](crates/ide-assists/src/handlers/generate_getter_or_setter.rs#13) 
+**Source:**  [generate_getter_or_setter.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_getter_or_setter.rs#L13) 
 
 Generate a setter method.
 
@@ -2059,7 +2085,7 @@ impl Person {
 
 
 ### `generate_trait_from_impl`
-**Source:**  [generate_trait_from_impl.rs](crates/ide-assists/src/handlers/generate_trait_from_impl.rs#18) 
+**Source:**  [generate_trait_from_impl.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_trait_from_impl.rs#L18) 
 
 Generate trait for an already defined inherent impl and convert impl to a trait impl.
 
@@ -2118,7 +2144,7 @@ impl<const N: usize> ${0:NewTrait}<N> for Foo<N> {
 
 
 ### `generate_trait_impl`
-**Source:**  [generate_impl.rs](crates/ide-assists/src/handlers/generate_impl.rs#66) 
+**Source:**  [generate_impl.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/generate_impl.rs#L66) 
 
 Adds a new trait impl for a type.
 
@@ -2140,7 +2166,7 @@ impl<T: Clone> ${0:_} for Ctx<T> {}
 
 
 ### `inline_call`
-**Source:**  [inline_call.rs](crates/ide-assists/src/handlers/inline_call.rs#170) 
+**Source:**  [inline_call.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/inline_call.rs#L170) 
 
 Inlines a function or method body creating a `let` statement per parameter unless the parameter
 can be inlined. The parameter will be inlined either if it the supplied argument is a simple local
@@ -2165,7 +2191,7 @@ fn foo(name: Option<&str>) {
 
 
 ### `inline_const_as_literal`
-**Source:**  [inline_const_as_literal.rs](crates/ide-assists/src/handlers/inline_const_as_literal.rs#6) 
+**Source:**  [inline_const_as_literal.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/inline_const_as_literal.rs#L6) 
 
 Evaluate and inline const variable as literal.
 
@@ -2189,7 +2215,7 @@ fn something() -> &'static str {
 
 
 ### `inline_into_callers`
-**Source:**  [inline_call.rs](crates/ide-assists/src/handlers/inline_call.rs#32) 
+**Source:**  [inline_call.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/inline_call.rs#L32) 
 
 Inline a function or method body into all of its callers where possible, creating a `let` statement per parameter
 unless the parameter can be inlined. The parameter will be inlined either if it the supplied argument is a simple local
@@ -2232,7 +2258,7 @@ fn bar() {
 
 
 ### `inline_local_variable`
-**Source:**  [inline_local_variable.rs](crates/ide-assists/src/handlers/inline_local_variable.rs#17) 
+**Source:**  [inline_local_variable.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/inline_local_variable.rs#L17) 
 
 Inlines a local variable.
 
@@ -2253,7 +2279,7 @@ fn main() {
 
 
 ### `inline_macro`
-**Source:**  [inline_macro.rs](crates/ide-assists/src/handlers/inline_macro.rs#7) 
+**Source:**  [inline_macro.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/inline_macro.rs#L7) 
 
 Takes a macro and inlines it one step.
 
@@ -2289,7 +2315,7 @@ fn main() {
 
 
 ### `inline_type_alias`
-**Source:**  [inline_type_alias.rs](crates/ide-assists/src/handlers/inline_type_alias.rs#106) 
+**Source:**  [inline_type_alias.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/inline_type_alias.rs#L106) 
 
 Replace a type alias with its concrete type.
 
@@ -2313,7 +2339,7 @@ fn main() {
 
 
 ### `inline_type_alias_uses`
-**Source:**  [inline_type_alias.rs](crates/ide-assists/src/handlers/inline_type_alias.rs#24) 
+**Source:**  [inline_type_alias.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/inline_type_alias.rs#L24) 
 
 Inline a type alias into all of its uses where possible.
 
@@ -2341,7 +2367,7 @@ fn foo() {
 
 
 ### `into_to_qualified_from`
-**Source:**  [into_to_qualified_from.rs](crates/ide-assists/src/handlers/into_to_qualified_from.rs#10) 
+**Source:**  [into_to_qualified_from.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/into_to_qualified_from.rs#L10) 
 
 Convert an `into` method call to a fully qualified `from` call.
 
@@ -2378,7 +2404,7 @@ fn main() -> () {
 
 
 ### `introduce_named_generic`
-**Source:**  [introduce_named_generic.rs](crates/ide-assists/src/handlers/introduce_named_generic.rs#7) 
+**Source:**  [introduce_named_generic.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/introduce_named_generic.rs#L7) 
 
 Replaces `impl Trait` function argument with the named generic.
 
@@ -2394,7 +2420,7 @@ fn foo<┃B: Bar>(bar: B) {}
 
 
 ### `introduce_named_lifetime`
-**Source:**  [introduce_named_lifetime.rs](crates/ide-assists/src/handlers/introduce_named_lifetime.rs#13) 
+**Source:**  [introduce_named_lifetime.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/introduce_named_lifetime.rs#L13) 
 
 Change an anonymous lifetime to a named lifetime.
 
@@ -2422,7 +2448,7 @@ impl<'a> Cursor<'a> {
 
 
 ### `invert_if`
-**Source:**  [invert_if.rs](crates/ide-assists/src/handlers/invert_if.rs#13) 
+**Source:**  [invert_if.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/invert_if.rs#L13) 
 
 This transforms if expressions of the form `if !x {A} else {B}` into `if x {B} else {A}`
 This also works with `!=`. This assist can only be applied with the cursor on `if`.
@@ -2443,7 +2469,7 @@ fn main() {
 
 
 ### `line_to_block`
-**Source:**  [convert_comment_block.rs](crates/ide-assists/src/handlers/convert_comment_block.rs#9) 
+**Source:**  [convert_comment_block.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/convert_comment_block.rs#L9) 
 
 Converts comments between block and single-line form.
 
@@ -2463,7 +2489,7 @@ Converts comments between block and single-line form.
 
 
 ### `make_raw_string`
-**Source:**  [raw_string.rs](crates/ide-assists/src/handlers/raw_string.rs#7) 
+**Source:**  [raw_string.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/raw_string.rs#L7) 
 
 Adds `r#` to a plain string literal.
 
@@ -2483,7 +2509,7 @@ fn main() {
 
 
 ### `make_usual_string`
-**Source:**  [raw_string.rs](crates/ide-assists/src/handlers/raw_string.rs#47) 
+**Source:**  [raw_string.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/raw_string.rs#L47) 
 
 Turns a raw string into a plain string.
 
@@ -2503,7 +2529,7 @@ fn main() {
 
 
 ### `merge_imports`
-**Source:**  [merge_imports.rs](crates/ide-assists/src/handlers/merge_imports.rs#21) 
+**Source:**  [merge_imports.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/merge_imports.rs#L21) 
 
 Merges neighbor imports with a common prefix.
 
@@ -2520,7 +2546,7 @@ use std::{fmt::Formatter, io};
 
 
 ### `merge_match_arms`
-**Source:**  [merge_match_arms.rs](crates/ide-assists/src/handlers/merge_match_arms.rs#12) 
+**Source:**  [merge_match_arms.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/merge_match_arms.rs#L12) 
 
 Merges the current match arm with the following if their bodies are identical.
 
@@ -2549,7 +2575,7 @@ fn handle(action: Action) {
 
 
 ### `merge_nested_if`
-**Source:**  [merge_nested_if.rs](crates/ide-assists/src/handlers/merge_nested_if.rs#11) 
+**Source:**  [merge_nested_if.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/merge_nested_if.rs#L11) 
 
 This transforms if expressions of the form `if x { if y {A} }` into `if x && y {A}`
 This assist can only be applied with the cursor on `if`.
@@ -2570,7 +2596,7 @@ fn main() {
 
 
 ### `move_arm_cond_to_match_guard`
-**Source:**  [move_guard.rs](crates/ide-assists/src/handlers/move_guard.rs#69) 
+**Source:**  [move_guard.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/move_guard.rs#L69) 
 
 Moves if expression from match arm body into a guard.
 
@@ -2600,7 +2626,7 @@ fn handle(action: Action) {
 
 
 ### `move_bounds_to_where_clause`
-**Source:**  [move_bounds.rs](crates/ide-assists/src/handlers/move_bounds.rs#12) 
+**Source:**  [move_bounds.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/move_bounds.rs#L12) 
 
 Moves inline type bounds to a where clause.
 
@@ -2620,7 +2646,7 @@ fn apply<T, U, F>(f: F, x: T) -> U where F: FnOnce(T) -> U {
 
 
 ### `move_const_to_impl`
-**Source:**  [move_const_to_impl.rs](crates/ide-assists/src/handlers/move_const_to_impl.rs#14) 
+**Source:**  [move_const_to_impl.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/move_const_to_impl.rs#L14) 
 
 Move a local constant item in a method to impl's associated constant. All the references will be
 qualified with `Self::`.
@@ -2653,7 +2679,7 @@ impl S {
 
 
 ### `move_from_mod_rs`
-**Source:**  [move_from_mod_rs.rs](crates/ide-assists/src/handlers/move_from_mod_rs.rs#12) 
+**Source:**  [move_from_mod_rs.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/move_from_mod_rs.rs#L12) 
 
 Moves xxx/mod.rs to xxx.rs.
 
@@ -2672,7 +2698,7 @@ fn t() {}
 
 
 ### `move_guard_to_arm_body`
-**Source:**  [move_guard.rs](crates/ide-assists/src/handlers/move_guard.rs#8) 
+**Source:**  [move_guard.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/move_guard.rs#L8) 
 
 Moves match guard into match arm body.
 
@@ -2704,7 +2730,7 @@ fn handle(action: Action) {
 
 
 ### `move_module_to_file`
-**Source:**  [move_module_to_file.rs](crates/ide-assists/src/handlers/move_module_to_file.rs#15) 
+**Source:**  [move_module_to_file.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/move_module_to_file.rs#L15) 
 
 Moves inline module's contents to a separate file.
 
@@ -2722,7 +2748,7 @@ mod foo;
 
 
 ### `move_to_mod_rs`
-**Source:**  [move_to_mod_rs.rs](crates/ide-assists/src/handlers/move_to_mod_rs.rs#12) 
+**Source:**  [move_to_mod_rs.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/move_to_mod_rs.rs#L12) 
 
 Moves xxx.rs to xxx/mod.rs.
 
@@ -2741,7 +2767,7 @@ fn t() {}
 
 
 ### `normalize_import`
-**Source:**  [normalize_import.rs](crates/ide-assists/src/handlers/normalize_import.rs#9) 
+**Source:**  [normalize_import.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/normalize_import.rs#L9) 
 
 Normalizes an import.
 
@@ -2757,7 +2783,7 @@ use std::{fmt::Formatter, io};
 
 
 ### `promote_local_to_const`
-**Source:**  [promote_local_to_const.rs](crates/ide-assists/src/handlers/promote_local_to_const.rs#17) 
+**Source:**  [promote_local_to_const.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/promote_local_to_const.rs#L17) 
 
 Promotes a local variable to a const item changing its name to a `SCREAMING_SNAKE_CASE` variant
 if the local uses no non-const expressions.
@@ -2790,7 +2816,7 @@ fn main() {
 
 
 ### `pull_assignment_up`
-**Source:**  [pull_assignment_up.rs](crates/ide-assists/src/handlers/pull_assignment_up.rs#11) 
+**Source:**  [pull_assignment_up.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/pull_assignment_up.rs#L11) 
 
 Extracts variable assignment to outside an if or match statement.
 
@@ -2822,7 +2848,7 @@ fn main() {
 
 
 ### `qualify_method_call`
-**Source:**  [qualify_method_call.rs](crates/ide-assists/src/handlers/qualify_method_call.rs#10) 
+**Source:**  [qualify_method_call.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/qualify_method_call.rs#L10) 
 
 Replaces the method call with a qualified function call.
 
@@ -2852,7 +2878,7 @@ fn main() {
 
 
 ### `qualify_path`
-**Source:**  [qualify_path.rs](crates/ide-assists/src/handlers/qualify_path.rs#24) 
+**Source:**  [qualify_path.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/qualify_path.rs#L24) 
 
 If the name is unresolved, provides all possible qualified paths for it.
 
@@ -2872,7 +2898,7 @@ fn main() {
 
 
 ### `reformat_number_literal`
-**Source:**  [number_representation.rs](crates/ide-assists/src/handlers/number_representation.rs#7) 
+**Source:**  [number_representation.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/number_representation.rs#L7) 
 
 Adds or removes separators from integer literal.
 
@@ -2888,7 +2914,7 @@ const _: i32 = 1_012_345;
 
 
 ### `remove_dbg`
-**Source:**  [remove_dbg.rs](crates/ide-assists/src/handlers/remove_dbg.rs#9) 
+**Source:**  [remove_dbg.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/remove_dbg.rs#L9) 
 
 Removes `dbg!()` macro call.
 
@@ -2908,7 +2934,7 @@ fn main() {
 
 
 ### `remove_hash`
-**Source:**  [raw_string.rs](crates/ide-assists/src/handlers/raw_string.rs#117) 
+**Source:**  [raw_string.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/raw_string.rs#L117) 
 
 Removes a hash from a raw string literal.
 
@@ -2928,7 +2954,7 @@ fn main() {
 
 
 ### `remove_mut`
-**Source:**  [remove_mut.rs](crates/ide-assists/src/handlers/remove_mut.rs#5) 
+**Source:**  [remove_mut.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/remove_mut.rs#L5) 
 
 Removes the `mut` keyword.
 
@@ -2948,7 +2974,7 @@ impl Walrus {
 
 
 ### `remove_parentheses`
-**Source:**  [remove_parentheses.rs](crates/ide-assists/src/handlers/remove_parentheses.rs#5) 
+**Source:**  [remove_parentheses.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/remove_parentheses.rs#L5) 
 
 Removes redundant parentheses.
 
@@ -2968,7 +2994,7 @@ fn main() {
 
 
 ### `remove_unused_imports`
-**Source:**  [remove_unused_imports.rs](crates/ide-assists/src/handlers/remove_unused_imports.rs#17) 
+**Source:**  [remove_unused_imports.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/remove_unused_imports.rs#L17) 
 
 Removes any use statements in the current selection that are unused.
 
@@ -2989,7 +3015,7 @@ mod foo {
 
 
 ### `remove_unused_param`
-**Source:**  [remove_unused_param.rs](crates/ide-assists/src/handlers/remove_unused_param.rs#15) 
+**Source:**  [remove_unused_param.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/remove_unused_param.rs#L15) 
 
 Removes unused function parameter.
 
@@ -3013,7 +3039,7 @@ fn main() {
 
 
 ### `reorder_fields`
-**Source:**  [reorder_fields.rs](crates/ide-assists/src/handlers/reorder_fields.rs#8) 
+**Source:**  [reorder_fields.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/reorder_fields.rs#L8) 
 
 Reorder the fields of record literals and record patterns in the same order as in
 the definition.
@@ -3032,7 +3058,7 @@ const test: Foo = Foo {foo: 1, bar: 0}
 
 
 ### `reorder_impl_items`
-**Source:**  [reorder_impl_items.rs](crates/ide-assists/src/handlers/reorder_impl_items.rs#11) 
+**Source:**  [reorder_impl_items.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/reorder_impl_items.rs#L11) 
 
 Reorder the items of an `impl Trait`. The items will be ordered
 in the same order as in the trait definition.
@@ -3071,7 +3097,7 @@ impl Foo for Bar {
 
 
 ### `replace_arith_with_checked`
-**Source:**  [replace_arith_op.rs](crates/ide-assists/src/handlers/replace_arith_op.rs#9) 
+**Source:**  [replace_arith_op.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/replace_arith_op.rs#L9) 
 
 Replaces arithmetic on integers with the `checked_*` equivalent.
 
@@ -3091,7 +3117,7 @@ fn main() {
 
 
 ### `replace_arith_with_saturating`
-**Source:**  [replace_arith_op.rs](crates/ide-assists/src/handlers/replace_arith_op.rs#28) 
+**Source:**  [replace_arith_op.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/replace_arith_op.rs#L28) 
 
 Replaces arithmetic on integers with the `saturating_*` equivalent.
 
@@ -3111,7 +3137,7 @@ fn main() {
 
 
 ### `replace_arith_with_wrapping`
-**Source:**  [replace_arith_op.rs](crates/ide-assists/src/handlers/replace_arith_op.rs#50) 
+**Source:**  [replace_arith_op.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/replace_arith_op.rs#L50) 
 
 Replaces arithmetic on integers with the `wrapping_*` equivalent.
 
@@ -3131,7 +3157,7 @@ fn main() {
 
 
 ### `replace_char_with_string`
-**Source:**  [replace_string_with_char.rs](crates/ide-assists/src/handlers/replace_string_with_char.rs#51) 
+**Source:**  [replace_string_with_char.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/replace_string_with_char.rs#L51) 
 
 Replace a char literal with a string literal.
 
@@ -3151,7 +3177,7 @@ fn main() {
 
 
 ### `replace_derive_with_manual_impl`
-**Source:**  [replace_derive_with_manual_impl.rs](crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs#20) 
+**Source:**  [replace_derive_with_manual_impl.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs#L20) 
 
 Converts a `derive` impl into a manual one.
 
@@ -3175,7 +3201,7 @@ impl Debug for S {
 
 
 ### `replace_if_let_with_match`
-**Source:**  [replace_if_let_with_match.rs](crates/ide-assists/src/handlers/replace_if_let_with_match.rs#20) 
+**Source:**  [replace_if_let_with_match.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/replace_if_let_with_match.rs#L20) 
 
 Replaces a `if let` expression with a `match` expression.
 
@@ -3206,7 +3232,7 @@ fn handle(action: Action) {
 
 
 ### `replace_is_some_with_if_let_some`
-**Source:**  [replace_is_method_with_if_let_method.rs](crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs#9) 
+**Source:**  [replace_is_method_with_if_let_method.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/replace_is_method_with_if_let_method.rs#L9) 
 
 Replace `if x.is_some()` with `if let Some(_tmp) = x` or `if x.is_ok()` with `if let Ok(_tmp) = x`.
 
@@ -3228,7 +3254,7 @@ fn main() {
 
 
 ### `replace_let_with_if_let`
-**Source:**  [replace_let_with_if_let.rs](crates/ide-assists/src/handlers/replace_let_with_if_let.rs#9) 
+**Source:**  [replace_let_with_if_let.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/replace_let_with_if_let.rs#L9) 
 
 Replaces `let` with an `if let`.
 
@@ -3255,7 +3281,7 @@ fn compute() -> Option<i32> { None }
 
 
 ### `replace_match_with_if_let`
-**Source:**  [replace_if_let_with_match.rs](crates/ide-assists/src/handlers/replace_if_let_with_match.rs#188) 
+**Source:**  [replace_if_let_with_match.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/replace_if_let_with_match.rs#L188) 
 
 Replaces a binary `match` with a wildcard pattern and no guards with an `if let` expression.
 
@@ -3286,7 +3312,7 @@ fn handle(action: Action) {
 
 
 ### `replace_named_generic_with_impl`
-**Source:**  [replace_named_generic_with_impl.rs](crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs#18) 
+**Source:**  [replace_named_generic_with_impl.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/replace_named_generic_with_impl.rs#L18) 
 
 Replaces named generic with an `impl Trait` in function argument.
 
@@ -3302,7 +3328,7 @@ fn new(location: impl AsRef<Path>) -> Self {}
 
 
 ### `replace_qualified_name_with_use`
-**Source:**  [replace_qualified_name_with_use.rs](crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs#13) 
+**Source:**  [replace_qualified_name_with_use.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs#L13) 
 
 Adds a use statement for a given fully-qualified name.
 
@@ -3320,7 +3346,7 @@ fn process(map: HashMap<String, String>) {}
 
 
 ### `replace_string_with_char`
-**Source:**  [replace_string_with_char.rs](crates/ide-assists/src/handlers/replace_string_with_char.rs#11) 
+**Source:**  [replace_string_with_char.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/replace_string_with_char.rs#L11) 
 
 Replace string literal with char literal.
 
@@ -3340,7 +3366,7 @@ fn main() {
 
 
 ### `replace_try_expr_with_match`
-**Source:**  [replace_try_expr_with_match.rs](crates/ide-assists/src/handlers/replace_try_expr_with_match.rs#18) 
+**Source:**  [replace_try_expr_with_match.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs#L18) 
 
 Replaces a `try` expression with a `match` expression.
 
@@ -3363,7 +3389,7 @@ fn handle() {
 
 
 ### `replace_turbofish_with_explicit_type`
-**Source:**  [replace_turbofish_with_explicit_type.rs](crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs#12) 
+**Source:**  [replace_turbofish_with_explicit_type.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/replace_turbofish_with_explicit_type.rs#L12) 
 
 Converts `::<_>` to an explicit type assignment.
 
@@ -3385,7 +3411,7 @@ fn main() {
 
 
 ### `replace_with_eager_method`
-**Source:**  [replace_method_eager_lazy.rs](crates/ide-assists/src/handlers/replace_method_eager_lazy.rs#89) 
+**Source:**  [replace_method_eager_lazy.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs#L89) 
 
 Replace `unwrap_or_else` with `unwrap_or` and `ok_or_else` with `ok_or`.
 
@@ -3407,7 +3433,7 @@ fn foo() {
 
 
 ### `replace_with_lazy_method`
-**Source:**  [replace_method_eager_lazy.rs](crates/ide-assists/src/handlers/replace_method_eager_lazy.rs#9) 
+**Source:**  [replace_method_eager_lazy.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/replace_method_eager_lazy.rs#L9) 
 
 Replace `unwrap_or` with `unwrap_or_else` and `ok_or` with `ok_or_else`.
 
@@ -3429,7 +3455,7 @@ fn foo() {
 
 
 ### `sort_items`
-**Source:**  [sort_items.rs](crates/ide-assists/src/handlers/sort_items.rs#12) 
+**Source:**  [sort_items.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/sort_items.rs#L12) 
 
 Sorts item members alphabetically: fields, enum variants and methods.
 
@@ -3520,7 +3546,7 @@ enum Animal {
 
 
 ### `split_import`
-**Source:**  [split_import.rs](crates/ide-assists/src/handlers/split_import.rs#5) 
+**Source:**  [split_import.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/split_import.rs#L5) 
 
 Wraps the tail of import into braces.
 
@@ -3536,7 +3562,7 @@ use std::{collections::HashMap};
 
 
 ### `sugar_impl_future_into_async`
-**Source:**  [toggle_async_sugar.rs](crates/ide-assists/src/handlers/toggle_async_sugar.rs#13) 
+**Source:**  [toggle_async_sugar.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/toggle_async_sugar.rs#L13) 
 
 Rewrites asynchronous function from `-> impl Future` into `async fn`.
 This action does not touch the function body and therefore `async { 0 }`
@@ -3558,7 +3584,7 @@ pub async fn foo() -> usize {
 
 
 ### `toggle_ignore`
-**Source:**  [toggle_ignore.rs](crates/ide-assists/src/handlers/toggle_ignore.rs#8) 
+**Source:**  [toggle_ignore.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/toggle_ignore.rs#L8) 
 
 Adds `#[ignore]` attribute to the test.
 
@@ -3581,7 +3607,7 @@ fn arithmetics {
 
 
 ### `toggle_macro_delimiter`
-**Source:**  [toggle_macro_delimiter.rs](crates/ide-assists/src/handlers/toggle_macro_delimiter.rs#9) 
+**Source:**  [toggle_macro_delimiter.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/toggle_macro_delimiter.rs#L9) 
 
 Change macro delimiters in the order of `( -> { -> [ -> (`.
 
@@ -3605,7 +3631,7 @@ sth!{ }
 
 
 ### `unmerge_match_arm`
-**Source:**  [unmerge_match_arm.rs](crates/ide-assists/src/handlers/unmerge_match_arm.rs#10) 
+**Source:**  [unmerge_match_arm.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/unmerge_match_arm.rs#L10) 
 
 Splits the current match with a `|` pattern into two arms with identical bodies.
 
@@ -3634,7 +3660,7 @@ fn handle(action: Action) {
 
 
 ### `unmerge_use`
-**Source:**  [unmerge_use.rs](crates/ide-assists/src/handlers/unmerge_use.rs#12) 
+**Source:**  [unmerge_use.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/unmerge_use.rs#L12) 
 
 Extracts single use item from use list.
 
@@ -3651,7 +3677,7 @@ use std::fmt::Display;
 
 
 ### `unnecessary_async`
-**Source:**  [unnecessary_async.rs](crates/ide-assists/src/handlers/unnecessary_async.rs#17) 
+**Source:**  [unnecessary_async.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/unnecessary_async.rs#L17) 
 
 Removes the `async` mark from functions which have no `.await` in their body.
 Looks for calls to the functions and removes the `.await` on the call site.
@@ -3670,7 +3696,7 @@ pub async fn bar() { foo() }
 
 
 ### `unqualify_method_call`
-**Source:**  [unqualify_method_call.rs](crates/ide-assists/src/handlers/unqualify_method_call.rs#9) 
+**Source:**  [unqualify_method_call.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/unqualify_method_call.rs#L9) 
 
 Transforms universal function call syntax into a method call.
 
@@ -3692,7 +3718,7 @@ fn main() {
 
 
 ### `unwrap_block`
-**Source:**  [unwrap_block.rs](crates/ide-assists/src/handlers/unwrap_block.rs#12) 
+**Source:**  [unwrap_block.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/unwrap_block.rs#L12) 
 
 This assist removes if...else, for, while and loop control statements to just keep the body.
 
@@ -3714,7 +3740,7 @@ fn foo() {
 
 
 ### `unwrap_option_return_type`
-**Source:**  [unwrap_return_type.rs](crates/ide-assists/src/handlers/unwrap_return_type.rs#13) 
+**Source:**  [unwrap_return_type.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/unwrap_return_type.rs#L13) 
 
 Unwrap the function's return type.
 
@@ -3730,7 +3756,7 @@ fn foo() -> i32 { 42i32 }
 
 
 ### `unwrap_result_return_type`
-**Source:**  [unwrap_return_type.rs](crates/ide-assists/src/handlers/unwrap_return_type.rs#26) 
+**Source:**  [unwrap_return_type.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/unwrap_return_type.rs#L26) 
 
 Unwrap the function's return type.
 
@@ -3746,7 +3772,7 @@ fn foo() -> i32 { 42i32 }
 
 
 ### `unwrap_tuple`
-**Source:**  [unwrap_tuple.rs](crates/ide-assists/src/handlers/unwrap_tuple.rs#8) 
+**Source:**  [unwrap_tuple.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/unwrap_tuple.rs#L8) 
 
 Unwrap the tuple to different variables.
 
@@ -3767,7 +3793,7 @@ fn main() {
 
 
 ### `wrap_return_type_in_option`
-**Source:**  [wrap_return_type.rs](crates/ide-assists/src/handlers/wrap_return_type.rs#16) 
+**Source:**  [wrap_return_type.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/wrap_return_type.rs#L16) 
 
 Wrap the function's return type into Option.
 
@@ -3783,7 +3809,7 @@ fn foo() -> Option<i32> { Some(42i32) }
 
 
 ### `wrap_return_type_in_result`
-**Source:**  [wrap_return_type.rs](crates/ide-assists/src/handlers/wrap_return_type.rs#29) 
+**Source:**  [wrap_return_type.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/wrap_return_type.rs#L29) 
 
 Wrap the function's return type into Result.
 
@@ -3799,7 +3825,7 @@ fn foo() -> Result<i32, ${0:_}> { Ok(42i32) }
 
 
 ### `wrap_unwrap_cfg_attr`
-**Source:**  [wrap_unwrap_cfg_attr.rs](crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs#12) 
+**Source:**  [wrap_unwrap_cfg_attr.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/ide-assists/src/handlers/wrap_unwrap_cfg_attr.rs#L12) 
 
 Wraps an attribute to a cfg_attr attribute or unwraps a cfg_attr attribute to the inner attributes.
 
diff --git a/src/tools/rust-analyzer/docs/book/src/configuration.md b/src/tools/rust-analyzer/docs/book/src/configuration.md
index 221a571c17c..fd94a4221a9 100644
--- a/src/tools/rust-analyzer/docs/book/src/configuration.md
+++ b/src/tools/rust-analyzer/docs/book/src/configuration.md
@@ -3,13 +3,13 @@
 **Source:**
 [config.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/rust-analyzer/src/config.rs)
 
-The [Installation](#_installation) section contains details on
+The [Installation](./installation.md) section contains details on
 configuration for some of the editors. In general `rust-analyzer` is
 configured via LSP messages, which means that it’s up to the editor to
 decide on the exact format and location of configuration files.
 
-Some clients, such as [VS Code](#vs-code) or [COC plugin in
-Vim](#coc-rust-analyzer) provide `rust-analyzer` specific configuration
+Some clients, such as [VS Code](./vs_code.md) or [COC plugin in
+Vim](./other_editors.md#coc-rust-analyzer) provide `rust-analyzer` specific configuration
 UIs. Others may require you to know a bit more about the interaction
 with `rust-analyzer`.
 
diff --git a/src/tools/rust-analyzer/docs/dev/README.md b/src/tools/rust-analyzer/docs/book/src/contributing/README.md
index c990212d585..cbbf6acf3e5 100644
--- a/src/tools/rust-analyzer/docs/dev/README.md
+++ b/src/tools/rust-analyzer/docs/book/src/contributing/README.md
@@ -9,7 +9,7 @@ $ cargo test
 
 should be enough to get you started!
 
-To learn more about how rust-analyzer works, see [./architecture.md](./architecture.md).
+To learn more about how rust-analyzer works, see [Architecture](architecture.md).
 It also explains the high-level layout of the source code.
 Do skim through that document.
 
@@ -24,7 +24,9 @@ rust-analyzer is a part of the [RLS-2.0 working
 group](https://github.com/rust-lang/compiler-team/tree/6a769c13656c0a6959ebc09e7b1f7c09b86fb9c0/working-groups/rls-2.0).
 Discussion happens in this Zulip stream:
 
-https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer
+<https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer>
+
+<!-- toc -->
 
 # Issue Labels
 
@@ -54,7 +56,7 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer
 
 # Code Style & Review Process
 
-Do see [./style.md](./style.md).
+See the [Style Guide](style.md).
 
 # Cookbook
 
@@ -88,11 +90,13 @@ As a sanity check after I'm done, I use `cargo xtask install --server` and **Rel
 If the problem concerns only the VS Code extension, I use **Run Installed Extension** launch configuration from `launch.json`.
 Notably, this uses the usual `rust-analyzer` binary from `PATH`.
 For this, it is important to have the following in your `settings.json` file:
+
 ```json
 {
     "rust-analyzer.server.path": "rust-analyzer"
 }
 ```
+
 After I am done with the fix, I use `cargo xtask install --client` to try the new extension for real.
 
 If I need to fix something in the `rust-analyzer` crate, I feel sad because it's on the boundary between the two processes, and working there is slow.
@@ -117,6 +121,7 @@ cd editors/code
 npm ci
 npm run lint
 ```
+
 ## How to ...
 
 * ... add an assist? [#7535](https://github.com/rust-lang/rust-analyzer/pull/7535)
@@ -142,14 +147,15 @@ Note that `stdout` is used for the actual protocol, so `println!` will break thi
 To log all communication between the server and the client, there are two choices:
 
 * You can log on the server side, by running something like
+
   ```
   env RA_LOG=lsp_server=debug code .
   ```
+
 * You can log on the client side, by the `rust-analyzer: Toggle LSP Logs` command or enabling `"rust-analyzer.trace.server": "verbose"` workspace setting.
   These logs are shown in a separate tab in the output and could be used with LSP inspector.
   Kudos to [@DJMcNab](https://github.com/DJMcNab) for setting this awesome infra up!
 
-
 There are also several VS Code commands which might be of interest:
 
 * `rust-analyzer: Status` shows some memory-usage statistics.
diff --git a/src/tools/rust-analyzer/docs/dev/architecture.md b/src/tools/rust-analyzer/docs/book/src/contributing/architecture.md
index 9c9e05a429b..1cc13b3b964 100644
--- a/src/tools/rust-analyzer/docs/dev/architecture.md
+++ b/src/tools/rust-analyzer/docs/book/src/contributing/architecture.md
@@ -8,19 +8,20 @@ It goes deeper than what is covered in this document, but will take some time to
 
 See also these implementation-related blog posts:
 
-* https://rust-analyzer.github.io/blog/2019/11/13/find-usages.html
-* https://rust-analyzer.github.io/blog/2020/07/20/three-architectures-for-responsive-ide.html
-* https://rust-analyzer.github.io/blog/2020/09/16/challeging-LR-parsing.html
-* https://rust-analyzer.github.io/blog/2020/09/28/how-to-make-a-light-bulb.html
-* https://rust-analyzer.github.io/blog/2020/10/24/introducing-ungrammar.html
+* <https://rust-analyzer.github.io/blog/2019/11/13/find-usages.html>
+* <https://rust-analyzer.github.io/blog/2020/07/20/three-architectures-for-responsive-ide.html>
+* <https://rust-analyzer.github.io/blog/2020/09/16/challeging-LR-parsing.html>
+* <https://rust-analyzer.github.io/blog/2020/09/28/how-to-make-a-light-bulb.html>
+* <https://rust-analyzer.github.io/blog/2020/10/24/introducing-ungrammar.html>
 
 For older, by now mostly outdated stuff, see the [guide](./guide.md) and [another playlist](https://www.youtube.com/playlist?list=PL85XCvVPmGQho7MZkdW-wtPtuJcFpzycE).
 
-
 ## Bird's Eye View
 
 ![](https://user-images.githubusercontent.com/4789492/107129398-0ab70f00-687a-11eb-9bfc-d4eb023aec06.png)
 
+<!-- toc -->
+
 On the highest level, rust-analyzer is a thing which accepts input source code from the client and produces a structured semantic model of the code.
 
 More specifically, input data consists of a set of test files (`(PathBuf, String)` pairs) and information about project structure, captured in the so called `CrateGraph`.
@@ -295,7 +296,7 @@ For this reason, all path APIs generally take some existing path as a "file syst
 ### `crates/stdx`
 
 This crate contains various non-rust-analyzer specific utils, which could have been in std, as well
-as copies of unstable std items we would like to make use of already, like `std::str::split_once`.
+as copies of unstable std items we would like to make use of already.
 
 ### `crates/profile`
 
diff --git a/src/tools/rust-analyzer/docs/dev/debugging.md b/src/tools/rust-analyzer/docs/book/src/contributing/debugging.md
index 48caec1d8fa..db3a28eed1c 100644
--- a/src/tools/rust-analyzer/docs/dev/debugging.md
+++ b/src/tools/rust-analyzer/docs/book/src/contributing/debugging.md
@@ -8,6 +8,7 @@
   <img height=150px src="https://user-images.githubusercontent.com/36276403/74611090-92ec5380-5101-11ea-8a41-598f51f3f3e3.png" alt="Debug options view">
 
 - Install all TypeScript dependencies
+
   ```bash
   cd editors/code
   npm ci
@@ -19,7 +20,6 @@
 where **only** the `rust-analyzer` extension being debugged is enabled.
 * To activate the extension you need to open any Rust project folder in `[Extension Development Host]`.
 
-
 ## Debug TypeScript VSCode extension
 
 - `Run Installed Extension` - runs the extension with the globally installed `rust-analyzer` binary.
@@ -36,12 +36,12 @@ To apply changes to an already running debug process, press <kbd>Ctrl+Shift+P</k
 
 - When attaching a debugger to an already running `rust-analyzer` server on Linux you might need to enable `ptrace` for unrelated processes by running:
 
-  ```
+  ```bash
   echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
   ```
 
-
 - By default, the LSP server is built without debug information. To enable it, you'll need to change `Cargo.toml`:
+
   ```toml
     [profile.dev]
     debug = 2
@@ -58,6 +58,7 @@ To apply changes to an already running debug process, press <kbd>Ctrl+Shift+P</k
 - Go back to the `[Extension Development Host]` instance and hover over a Rust variable and your breakpoint should hit.
 
 If you need to debug the server from the very beginning, including its initialization code, you can use the `--wait-dbg` command line argument or `RA_WAIT_DBG` environment variable. The server will spin at the beginning of the `try_main` function (see `crates\rust-analyzer\src\bin\main.rs`)
+
 ```rust
     let mut d = 4;
     while d == 4 { // set a breakpoint here and change the value
@@ -66,6 +67,7 @@ If you need to debug the server from the very beginning, including its initializ
 ```
 
 However for this to work, you will need to enable debug_assertions in your build
+
 ```rust
 RUSTFLAGS='--cfg debug_assertions' cargo build --release
 ```
diff --git a/src/tools/rust-analyzer/docs/dev/guide.md b/src/tools/rust-analyzer/docs/book/src/contributing/guide.md
index bb77aa0eaae..2a2a39af264 100644
--- a/src/tools/rust-analyzer/docs/dev/guide.md
+++ b/src/tools/rust-analyzer/docs/book/src/contributing/guide.md
@@ -12,6 +12,8 @@ https://youtu.be/ANKBNiSWyfc.
 [guide-2019-01]: https://github.com/rust-lang/rust-analyzer/tree/guide-2019-01
 [2024-01-01]: https://github.com/rust-lang/rust-analyzer/tree/2024-01-01
 
+<!-- toc -->
+
 ## The big picture
 
 On the highest possible level, rust-analyzer is a stateful component. A client may
@@ -76,10 +78,10 @@ to study its methods to understand all the input data.
 
 The `change_file` method controls the set of the input files, where each file
 has an integer id (`FileId`, picked by the client) and text (`Option<Arc<str>>`).
-Paths are tricky; they'll be explained below, in source roots section, 
+Paths are tricky; they'll be explained below, in source roots section,
 together with the `set_roots` method. The "source root" [`is_library`] flag
-along with the concept of [`durability`] allows us to add a group of files which 
-are assumed to rarely change. It's mostly an optimization and does not change 
+along with the concept of [`durability`] allows us to add a group of files which
+are assumed to rarely change. It's mostly an optimization and does not change
 the fundamental picture.
 
 [`is_library`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/base-db/src/input.rs#L38
@@ -141,7 +143,7 @@ the source root, even `/dev/random`.
 
 ## Language Server Protocol
 
-Now let's see how the `Analysis` API is exposed via the JSON RPC based language server protocol. 
+Now let's see how the `Analysis` API is exposed via the JSON RPC based language server protocol.
 The hard part here is managing changes (which can come either from the file system
 or from the editor) and concurrency (we want to spawn background jobs for things
 like syntax highlighting). We use the event loop pattern to manage the zoo, and
@@ -152,13 +154,12 @@ the loop is the [`GlobalState::run`] function initiated by [`main_loop`] after
 [`GlobalState::new`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/rust-analyzer/src/global_state.rs#L148-L215
 [`GlobalState::run`]: https://github.com/rust-lang/rust-analyzer/blob/2024-01-01/crates/rust-analyzer/src/main_loop.rs#L114-L140
 
-
 Let's walk through a typical analyzer session!
 
 First, we need to figure out what to analyze. To do this, we run `cargo
 metadata` to learn about Cargo packages for current workspace and dependencies,
 and we run `rustc --print sysroot` and scan the "sysroot"
-(the directory containing the current Rust toolchain's files) to learn about crates 
+(the directory containing the current Rust toolchain's files) to learn about crates
 like `std`. This happens in the [`GlobalState::fetch_workspaces`] method.
 We load this configuration at the start of the server in [`GlobalState::new`],
 but it's also triggered by workspace change events and requests to reload the
diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md
index c7ee4e40236..14a3fd1ebd1 100644
--- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
+++ b/src/tools/rust-analyzer/docs/book/src/contributing/lsp-extensions.md
@@ -19,6 +19,8 @@ Requests, which are likely to always remain specific to `rust-analyzer` are unde
 
 If you want to be notified about the changes to this document, subscribe to [#4604](https://github.com/rust-lang/rust-analyzer/issues/4604).
 
+<!-- toc -->
+
 ## Configuration in `initializationOptions`
 
 **Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/567
diff --git a/src/tools/rust-analyzer/docs/dev/setup.md b/src/tools/rust-analyzer/docs/book/src/contributing/setup.md
index d8a7840d376..d8a7840d376 100644
--- a/src/tools/rust-analyzer/docs/dev/setup.md
+++ b/src/tools/rust-analyzer/docs/book/src/contributing/setup.md
diff --git a/src/tools/rust-analyzer/docs/dev/style.md b/src/tools/rust-analyzer/docs/book/src/contributing/style.md
index 51b60ab2ebb..5654e37753a 100644
--- a/src/tools/rust-analyzer/docs/dev/style.md
+++ b/src/tools/rust-analyzer/docs/book/src/contributing/style.md
@@ -1,3 +1,5 @@
+# Style
+
 Our approach to "clean code" is two-fold:
 
 * We generally don't block PRs on style changes.
@@ -274,7 +276,7 @@ fn f() {
 Assert liberally.
 Prefer [`stdx::never!`](https://docs.rs/always-assert/0.1.2/always_assert/macro.never.html) to standard `assert!`.
 
-**Rationale:** See [cross cutting concern: error handling](https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/architecture.md#error-handling).
+**Rationale:** See [cross cutting concern: error handling](https://github.com/rust-lang/rust-analyzer/blob/master/docs/book/src/contributing/architecture.md#error-handling).
 
 ## Getters & Setters
 
diff --git a/src/tools/rust-analyzer/docs/dev/syntax.md b/src/tools/rust-analyzer/docs/book/src/contributing/syntax.md
index 3dcd430cea5..3dcd430cea5 100644
--- a/src/tools/rust-analyzer/docs/dev/syntax.md
+++ b/src/tools/rust-analyzer/docs/book/src/contributing/syntax.md
diff --git a/src/tools/rust-analyzer/docs/book/src/editor_features.md b/src/tools/rust-analyzer/docs/book/src/editor_features.md
index 73fe9f49a96..5521e395c73 100644
--- a/src/tools/rust-analyzer/docs/book/src/editor_features.md
+++ b/src/tools/rust-analyzer/docs/book/src/editor_features.md
@@ -1,6 +1,5 @@
 # Editor Features
 
-
 ## VS Code
 
 ### Color configurations
@@ -118,7 +117,7 @@ Or it is possible to specify vars more granularly:
 "rust-analyzer.runnables.extraEnv": [
     {
         // "mask": null, // null mask means that this rule will be applied for all runnables
-        env: {
+        "env": {
                 "APP_ID": "1",
                 "APP_DATA": "asdf"
         }
@@ -145,7 +144,7 @@ If needed, you can set different values for different platforms:
 "rust-analyzer.runnables.extraEnv": [
     {
         "platform": "win32", // windows only
-        env: {
+        "env": {
                 "APP_DATA": "windows specific data"
         }
     },
diff --git a/src/tools/rust-analyzer/docs/book/src/other_editors.md b/src/tools/rust-analyzer/docs/book/src/other_editors.md
index 0a9a453e013..1eac7dd2c25 100644
--- a/src/tools/rust-analyzer/docs/book/src/other_editors.md
+++ b/src/tools/rust-analyzer/docs/book/src/other_editors.md
@@ -6,6 +6,8 @@ Protocol](https://microsoft.github.io/language-server-protocol/).
 This page assumes that you have already [installed the rust-analyzer
 binary](./rust_analyzer_binary.html).
 
+<!-- toc -->
+
 ## Emacs
 
 To use `rust-analyzer`, you need to install and enable one of the two
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
index 4006d06e4fe..6cd39fabeee 100644
--- a/src/tools/rust-analyzer/rust-version
+++ b/src/tools/rust-analyzer/rust-version
@@ -1 +1 @@
-273465e1f2932a30a5b56ac95859cdc86f3f33fa
+e0be1a02626abef2878cb7f4aaef7ae409477112
diff --git a/src/tools/rust-analyzer/xtask/src/codegen.rs b/src/tools/rust-analyzer/xtask/src/codegen.rs
index e84c259e979..8165a2a12b0 100644
--- a/src/tools/rust-analyzer/xtask/src/codegen.rs
+++ b/src/tools/rust-analyzer/xtask/src/codegen.rs
@@ -117,7 +117,13 @@ impl fmt::Display for Location {
         let path = self.file.strip_prefix(project_root()).unwrap().display().to_string();
         let path = path.replace('\\', "/");
         let name = self.file.file_name().unwrap();
-        write!(f, " [{}](/{}#{}) ", name.to_str().unwrap(), path, self.line)
+        write!(
+            f,
+            " [{}](https://github.com/rust-lang/rust-analyzer/blob/master/{}#L{}) ",
+            name.to_str().unwrap(),
+            path,
+            self.line
+        )
     }
 }
 
diff --git a/src/tools/rust-analyzer/xtask/src/codegen/parser_inline_tests.rs b/src/tools/rust-analyzer/xtask/src/codegen/parser_inline_tests.rs
index f9f73df8eb7..88732cebe72 100644
--- a/src/tools/rust-analyzer/xtask/src/codegen/parser_inline_tests.rs
+++ b/src/tools/rust-analyzer/xtask/src/codegen/parser_inline_tests.rs
@@ -18,92 +18,87 @@ use crate::{
     util::list_rust_files,
 };
 
-const PARSER_CRATE_ROOT: &str = "crates/parser";
-const PARSER_TEST_DATA: &str = "crates/parser/test_data";
-const PARSER_TEST_DATA_INLINE: &str = "crates/parser/test_data/parser/inline";
-
 pub(crate) fn generate(check: bool) {
-    let tests = tests_from_dir(
-        &project_root().join(Path::new(&format!("{PARSER_CRATE_ROOT}/src/grammar"))),
-    );
+    let parser_crate_root = project_root().join("crates/parser");
+    let parser_test_data = parser_crate_root.join("test_data");
+    let parser_test_data_inline = parser_test_data.join("parser/inline");
+
+    let tests = tests_from_dir(&parser_crate_root.join("src/grammar"));
 
     let mut some_file_was_updated = false;
     some_file_was_updated |=
-        install_tests(&tests.ok, &format!("{PARSER_TEST_DATA_INLINE}/ok"), check).unwrap();
+        install_tests(&tests.ok, parser_test_data_inline.join("ok"), check).unwrap();
     some_file_was_updated |=
-        install_tests(&tests.err, &format!("{PARSER_TEST_DATA_INLINE}/err"), check).unwrap();
+        install_tests(&tests.err, parser_test_data_inline.join("err"), check).unwrap();
 
     if some_file_was_updated {
-        let _ = fs::File::open(format!("{PARSER_CRATE_ROOT}/src/tests.rs"))
+        let _ = fs::File::open(parser_crate_root.join("src/tests.rs"))
             .unwrap()
             .set_modified(SystemTime::now());
+    }
 
-        let ok_tests = tests.ok.values().sorted_by(|a, b| a.name.cmp(&b.name)).map(|test| {
-            let test_name = quote::format_ident!("{}", test.name);
-            let test_file = format!("test_data/parser/inline/ok/{test_name}.rs");
-            let (test_func, args) = match &test.edition {
-                Some(edition) => {
-                    let edition = quote::format_ident!("Edition{edition}");
-                    (
-                        quote::format_ident!("run_and_expect_no_errors_with_edition"),
-                        quote::quote! {#test_file, crate::Edition::#edition},
-                    )
-                }
-                None => {
-                    (quote::format_ident!("run_and_expect_no_errors"), quote::quote! {#test_file})
-                }
-            };
-            quote::quote! {
-                #[test]
-                fn #test_name() {
-                    #test_func(#args);
-                }
-            }
-        });
-        let err_tests = tests.err.values().sorted_by(|a, b| a.name.cmp(&b.name)).map(|test| {
-            let test_name = quote::format_ident!("{}", test.name);
-            let test_file = format!("test_data/parser/inline/err/{test_name}.rs");
-            let (test_func, args) = match &test.edition {
-                Some(edition) => {
-                    let edition = quote::format_ident!("Edition{edition}");
-                    (
-                        quote::format_ident!("run_and_expect_errors_with_edition"),
-                        quote::quote! {#test_file, crate::Edition::#edition},
-                    )
-                }
-                None => (quote::format_ident!("run_and_expect_errors"), quote::quote! {#test_file}),
-            };
-            quote::quote! {
-                #[test]
-                fn #test_name() {
-                    #test_func(#args);
-                }
+    let ok_tests = tests.ok.values().sorted_by(|a, b| a.name.cmp(&b.name)).map(|test| {
+        let test_name = quote::format_ident!("{}", test.name);
+        let test_file = format!("test_data/parser/inline/ok/{test_name}.rs");
+        let (test_func, args) = match &test.edition {
+            Some(edition) => {
+                let edition = quote::format_ident!("Edition{edition}");
+                (
+                    quote::format_ident!("run_and_expect_no_errors_with_edition"),
+                    quote::quote! {#test_file, crate::Edition::#edition},
+                )
             }
-        });
-
-        let output = quote::quote! {
-            mod ok {
-                use crate::tests::*;
-                #(#ok_tests)*
+            None => (quote::format_ident!("run_and_expect_no_errors"), quote::quote! {#test_file}),
+        };
+        quote::quote! {
+            #[test]
+            fn #test_name() {
+                #test_func(#args);
             }
-            mod err {
-                use crate::tests::*;
-                #(#err_tests)*
+        }
+    });
+    let err_tests = tests.err.values().sorted_by(|a, b| a.name.cmp(&b.name)).map(|test| {
+        let test_name = quote::format_ident!("{}", test.name);
+        let test_file = format!("test_data/parser/inline/err/{test_name}.rs");
+        let (test_func, args) = match &test.edition {
+            Some(edition) => {
+                let edition = quote::format_ident!("Edition{edition}");
+                (
+                    quote::format_ident!("run_and_expect_errors_with_edition"),
+                    quote::quote! {#test_file, crate::Edition::#edition},
+                )
             }
+            None => (quote::format_ident!("run_and_expect_errors"), quote::quote! {#test_file}),
         };
+        quote::quote! {
+            #[test]
+            fn #test_name() {
+                #test_func(#args);
+            }
+        }
+    });
 
-        let pretty = reformat(output.to_string());
-        ensure_file_contents(
-            crate::flags::CodegenType::ParserTests,
-            format!("{PARSER_TEST_DATA}/generated/runner.rs").as_ref(),
-            &pretty,
-            check,
-        );
-    }
+    let output = quote::quote! {
+        mod ok {
+            use crate::tests::*;
+            #(#ok_tests)*
+        }
+        mod err {
+            use crate::tests::*;
+            #(#err_tests)*
+        }
+    };
+
+    let pretty = reformat(output.to_string());
+    ensure_file_contents(
+        crate::flags::CodegenType::ParserTests,
+        parser_test_data.join("generated/runner.rs").as_ref(),
+        &pretty,
+        check,
+    );
 }
 
-fn install_tests(tests: &HashMap<String, Test>, into: &str, check: bool) -> Result<bool> {
-    let tests_dir = project_root().join(into);
+fn install_tests(tests: &HashMap<String, Test>, tests_dir: PathBuf, check: bool) -> Result<bool> {
     if !tests_dir.is_dir() {
         fs::create_dir_all(&tests_dir)?;
     }
diff --git a/src/tools/rust-analyzer/xtask/src/tidy.rs b/src/tools/rust-analyzer/xtask/src/tidy.rs
index 35412be8764..b500b251ed3 100644
--- a/src/tools/rust-analyzer/xtask/src/tidy.rs
+++ b/src/tools/rust-analyzer/xtask/src/tidy.rs
@@ -27,8 +27,9 @@ fn check_lsp_extensions_docs(sh: &Shell) {
     };
 
     let actual_hash = {
-        let lsp_extensions_md =
-            sh.read_file(project_root().join("docs/dev/lsp-extensions.md")).unwrap();
+        let lsp_extensions_md = sh
+            .read_file(project_root().join("docs/book/src/contributing/lsp-extensions.md"))
+            .unwrap();
         let text = lsp_extensions_md
             .lines()
             .find_map(|line| line.strip_prefix("lsp/ext.rs hash:"))
@@ -185,7 +186,7 @@ Zlib OR Apache-2.0 OR MIT
 
 fn check_test_attrs(path: &Path, text: &str) {
     let panic_rule =
-        "https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/style.md#should_panic";
+        "https://github.com/rust-lang/rust-analyzer/blob/master/docs/book/src/contributing/style.md#should_panic";
     let need_panic: &[&str] = &[
         // This file.
         "slow-tests/tidy.rs",
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/codegen/issues/str-to-string-128690.rs b/tests/codegen/issues/str-to-string-128690.rs
index 8b416306ba6..d9e69764be2 100644
--- a/tests/codegen/issues/str-to-string-128690.rs
+++ b/tests/codegen/issues/str-to-string-128690.rs
@@ -2,25 +2,27 @@
 #![crate_type = "lib"]
 
 //! Make sure str::to_string is specialized not to use fmt machinery.
+//!
+//! Note that the `CHECK-NOT`s here try to match on calls to functions under `core::fmt`.
 
 // CHECK-LABEL: define {{(dso_local )?}}void @one_ref
 #[no_mangle]
 pub fn one_ref(input: &str) -> String {
-    // CHECK-NOT: {{(call|invoke).*}}fmt
+    // CHECK-NOT: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}}
     input.to_string()
 }
 
 // CHECK-LABEL: define {{(dso_local )?}}void @two_ref
 #[no_mangle]
 pub fn two_ref(input: &&str) -> String {
-    // CHECK-NOT: {{(call|invoke).*}}fmt
+    // CHECK-NOT: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}}
     input.to_string()
 }
 
 // CHECK-LABEL: define {{(dso_local )?}}void @thirteen_ref
 #[no_mangle]
 pub fn thirteen_ref(input: &&&&&&&&&&&&&str) -> String {
-    // CHECK-NOT: {{(call|invoke).*}}fmt
+    // CHECK-NOT: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}}
     input.to_string()
 }
 
@@ -31,6 +33,6 @@ pub fn thirteen_ref(input: &&&&&&&&&&&&&str) -> String {
 // CHECK-LABEL: define {{(dso_local )?}}void @fourteen_ref
 #[no_mangle]
 pub fn fourteen_ref(input: &&&&&&&&&&&&&&str) -> String {
-    // CHECK: {{(call|invoke).*}}fmt
+    // CHECK: {{(call|invoke)}}{{.*}}@{{.*}}core{{.*}}fmt{{.*}}
     input.to_string()
 }
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-gui/docblock-code-block-line-number.goml b/tests/rustdoc-gui/docblock-code-block-line-number.goml
index 032746a6bdf..97273ceb195 100644
--- a/tests/rustdoc-gui/docblock-code-block-line-number.goml
+++ b/tests/rustdoc-gui/docblock-code-block-line-number.goml
@@ -21,7 +21,7 @@ assert-css: (
 set-local-storage: {"rustdoc-line-numbers": "true"}
 reload:
 // We wait for the line numbers to be added into the DOM by the JS...
-wait-for: "pre.example-line-numbers"
+wait-for: ".digits-1 pre"
 
 // Otherwise, we can't check text color
 show-text: true
@@ -35,30 +35,21 @@ define-function: (
         call-function: ("switch-theme", {"theme": |theme|})
         // If the test didn't fail, it means that it was found!
         assert-css: (
-            "pre.example-line-numbers",
+            ".digits-1 pre [data-nosnippet]",
             {
                 "color": |color|,
-                "margin": "0px",
-                "padding-top": "14px",
-                "padding-bottom": "14px",
-                "padding-left": "8px",
-                "padding-right": "2px",
+                "margin-top": "0px",
+                "margin-bottom": "0px",
+                "margin-left": "0px",
+                "margin-right": "20px",
+                "padding-top": "0px",
+                "padding-bottom": "0px",
+                "padding-left": "4px",
+                "padding-right": "4px",
                 "text-align": "right",
-                // There should not be a radius on the right of the line numbers.
-                "border-top-left-radius": "6px",
-                "border-bottom-left-radius": "6px",
-                "border-top-right-radius": "0px",
-                "border-bottom-right-radius": "0px",
             },
             ALL,
         )
-        // There should not be a radius on the left of the line numbers.
-        assert-css: ("pre.example-line-numbers + .rust", {
-            "border-top-left-radius": "0px",
-            "border-bottom-left-radius": "0px",
-            "border-top-right-radius": "6px",
-            "border-bottom-right-radius": "6px",
-        })
     },
 )
 call-function: ("check-colors", {
@@ -74,9 +65,6 @@ call-function: ("check-colors", {
     "color": "#c67e2d",
 })
 
-// The first code block has two lines so let's check its `<pre>` elements lists both of them.
-assert-text: ("pre.example-line-numbers", "1\n2")
-
 // Now, try changing the setting dynamically. We'll turn it off, using the settings menu,
 // and make sure it goes away.
 
@@ -87,42 +75,17 @@ assert-css: ("#settings", {"display": "block"})
 
 // Then, click the toggle button.
 click: "input#line-numbers"
-wait-for-false: "pre.example-line-numbers"
+wait-for: ".digits-1.hide-lines"
 assert-local-storage: {"rustdoc-line-numbers": "false" }
 
-// Check that the rounded corners are back.
-assert-css: (
-    ".example-wrap .rust",
-    {
-        "border-top-left-radius": "6px",
-        "border-bottom-left-radius": "6px",
-        "border-top-right-radius": "6px",
-        "border-bottom-right-radius": "6px",
-    },
-    ALL,
-)
-
 // Finally, turn it on again.
 click: "input#line-numbers"
-wait-for: "pre.example-line-numbers"
+wait-for: ".digits-1:not(.hide-lines)"
 assert-local-storage: {"rustdoc-line-numbers": "true" }
-wait-for: "pre.example-line-numbers"
 
 // Same check with scraped examples line numbers.
 go-to: "file://" + |DOC_PATH| + "/scrape_examples/fn.test_many.html"
 
-assert-css: (
-    ".scraped-example .rust",
-    {
-        // There should not be a radius on the left of the code.
-        "border-top-left-radius": "0px",
-        "border-bottom-left-radius": "0px",
-        "border-top-right-radius": "6px",
-        "border-bottom-right-radius": "6px",
-    },
-    ALL,
-)
-
 define-function: (
     "check-padding",
     [path, padding_bottom],
@@ -203,17 +166,18 @@ assert-local-storage: {"rustdoc-line-numbers": "true" }
 assert: ".example-wrap > pre.language-txt"
 assert: ".example-wrap > pre.rust"
 assert-count: (".example-wrap", 2)
-assert-count: (".example-wrap > pre.example-line-numbers", 2)
+assert-count: (".example-wrap.digits-1", 2)
 
 click: "#settings-menu"
 wait-for: "#settings"
 
 // Then, click the toggle button.
 click: "input#line-numbers"
-wait-for-count: (".example-wrap > pre.example-line-numbers", 0)
+wait-for-count: (".example-wrap.digits-1.hide-lines", 2)
 assert-local-storage-false: {"rustdoc-line-numbers": "true" }
 
 // Now turning off the setting.
 click: "input#line-numbers"
-wait-for-count: (".example-wrap > pre.example-line-numbers", 2)
+wait-for-count: (".example-wrap.digits-1", 2)
+wait-for-count: (".example-wrap.digits-1.hide-lines", 0)
 assert-local-storage: {"rustdoc-line-numbers": "true" }
diff --git a/tests/rustdoc-gui/source-code-wrapping.goml b/tests/rustdoc-gui/source-code-wrapping.goml
new file mode 100644
index 00000000000..cb2fd3052cd
--- /dev/null
+++ b/tests/rustdoc-gui/source-code-wrapping.goml
@@ -0,0 +1,47 @@
+// Checks that the interactions with the source code pages are working as expected.
+go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
+show-text: true
+set-window-size: (1000, 1000)
+
+define-function: (
+    "click-code-wrapping",
+    [expected],
+    block {
+        click: "#word-wrap-source-code"
+        wait-for-local-storage: {"rustdoc-word-wrap-source-code": |expected|}
+    },
+)
+
+store-size: (".rust code", {"width": width, "height": height})
+click: "#settings-menu"
+wait-for: "#settings"
+call-function: ("click-code-wrapping", {"expected": "true"})
+wait-for-size-false: (".rust code", {"width": |width|, "height": |height|})
+store-size: (".rust code", {"width": new_width, "height": new_height})
+// The width should now be smaller than the window's and the height
+// should have increased.
+assert: |width| > |new_width| && |height| < |new_height|
+
+// Switching back to the original setting.
+call-function: ("click-code-wrapping", {"expected": "false"})
+assert-size: (".rust code", {"width": |width|, "height": |height|})
+
+// Now let's check in docs code examples.
+go-to: "file://" + |DOC_PATH| + "/test_docs/trait_bounds/index.html"
+click: "#settings-menu"
+wait-for: "#settings"
+
+store-size: (".example-wrap .rust code", {"width": rust_width, "height": rust_height})
+store-size: (".example-wrap .language-text code", {"width": txt_width, "height": txt_height})
+call-function: ("click-code-wrapping", {"expected": "true"})
+wait-for-size-false: (".example-wrap .rust code", {"width": |rust_width|, "height": |rust_height|})
+
+store-size: (".example-wrap .rust code", {"width": new_rust_width, "height": new_rust_height})
+store-size: (".example-wrap .language-text code", {"width": new_txt_width, "height": new_txt_height})
+
+assert: |rust_width| > |new_rust_width| && |rust_height| < |new_rust_height|
+assert: |txt_width| > |new_txt_width| && |txt_height| < |new_txt_height|
+
+call-function: ("click-code-wrapping", {"expected": "false"})
+wait-for-size: (".example-wrap .rust code", {"width": |rust_width|, "height": |rust_height|})
+assert-size: (".example-wrap .language-text code", {"width": |txt_width|, "height": |txt_height|})
diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs
index f9c20ab22b8..31f6b7f09b7 100644
--- a/tests/rustdoc-gui/src/test_docs/lib.rs
+++ b/tests/rustdoc-gui/src/test_docs/lib.rs
@@ -615,6 +615,15 @@ pub mod private {
     }
 }
 
+/// ```
+/// fn super_long_function_name_because_i_need_to_hit_the_limit_and_break_beyond_it() {
+/// }
+/// ```
+///
+/// ```text
+/// fn super_long_function_name_because_i_need_to_hit_the_limit_and_break_beyond_it_v2() {
+/// }
+/// ```
 pub mod trait_bounds {
     pub trait OneBound: Sized {}
     pub trait TwoBounds: Sized + Copy {}
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/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`.