about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_ast/src/ast.rs26
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs6
-rw-r--r--compiler/rustc_ast/src/visit.rs6
-rw-r--r--compiler/rustc_ast_lowering/messages.ftl2
-rw-r--r--compiler/rustc_ast_lowering/src/errors.rs7
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs42
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs20
-rw-r--r--compiler/rustc_attr_data_structures/src/attributes.rs66
-rw-r--r--compiler/rustc_attr_data_structures/src/lib.rs4
-rw-r--r--compiler/rustc_attr_data_structures/src/lints.rs1
-rw-r--r--compiler/rustc_attr_parsing/messages.ftl14
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs3
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/confusables.rs53
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/deprecation.rs111
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/inline.rs8
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs21
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/mod.rs27
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/repr.rs4
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/stability.rs113
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/transparency.rs16
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs183
-rw-r--r--compiler/rustc_attr_parsing/src/lints.rs15
-rw-r--r--compiler/rustc_attr_parsing/src/session_diagnostics.rs166
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs5
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_eval.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs5
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs5
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core.rs66
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs66
-rw-r--r--compiler/rustc_codegen_gcc/example/mini_core.rs66
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/abi.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/builder/autodiff.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs19
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs18
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs57
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs15
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs54
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs3
-rw-r--r--compiler/rustc_data_structures/src/aligned.rs4
-rw-r--r--compiler/rustc_data_structures/src/lib.rs4
-rw-r--r--compiler/rustc_data_structures/src/marker.rs30
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0534.md8
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0535.md9
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0539.md29
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0565.md7
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0805.md26
-rw-r--r--compiler/rustc_error_codes/src/lib.rs1
-rw-r--r--compiler/rustc_expand/src/base.rs3
-rw-r--r--compiler/rustc_expand/src/expand.rs35
-rw-r--r--compiler/rustc_expand/src/placeholders.rs12
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs42
-rw-r--r--compiler/rustc_feature/src/unstable.rs2
-rw-r--r--compiler/rustc_hir/src/lang_items.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs25
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs346
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs53
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs9
-rw-r--r--compiler/rustc_lint/messages.ftl3
-rw-r--r--compiler/rustc_lint/src/dangling.rs3
-rw-r--r--compiler/rustc_lint/src/lints.rs13
-rw-r--r--compiler/rustc_lint/src/multiple_supertrait_upcastable.rs3
-rw-r--r--compiler/rustc_lint/src/redundant_semicolon.rs13
-rw-r--r--compiler/rustc_middle/src/lib.rs1
-rw-r--r--compiler/rustc_middle/src/query/keys.rs8
-rw-r--r--compiler/rustc_middle/src/query/mod.rs75
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs21
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs4
-rw-r--r--compiler/rustc_middle/src/ty/context.rs22
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs1
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs36
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs26
-rw-r--r--compiler/rustc_middle/src/ty/util.rs4
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs19
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs19
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs55
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/effect_goals.rs6
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs6
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/trait_goals.rs62
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs72
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs2
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs2
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs17
-rw-r--r--compiler/rustc_passes/src/check_attr.rs131
-rw-r--r--compiler/rustc_resolve/src/late.rs24
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs42
-rw-r--r--compiler/rustc_serialize/src/lib.rs17
-rw-r--r--compiler/rustc_serialize/src/serialize.rs4
-rw-r--r--compiler/rustc_session/src/config.rs1
-rw-r--r--compiler/rustc_session/src/options.rs10
-rw-r--r--compiler/rustc_smir/src/lib.rs1
-rw-r--r--compiler/rustc_smir/src/rustc_smir/context.rs33
-rw-r--r--compiler/rustc_smir/src/rustc_smir/convert/ty.rs8
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs3
-rw-r--r--compiler/rustc_smir/src/stable_mir/compiler_interface.rs23
-rw-r--r--compiler/rustc_smir/src/stable_mir/ty.rs15
-rw-r--r--compiler/rustc_span/src/symbol.rs3
-rw-r--r--compiler/rustc_target/src/callconv/mips64.rs15
-rw-r--r--compiler/rustc_target/src/callconv/mod.rs84
-rw-r--r--compiler/rustc_target/src/callconv/nvptx64.rs25
-rw-r--r--compiler/rustc_target/src/callconv/riscv.rs137
-rw-r--r--compiler/rustc_target/src/callconv/sparc64.rs18
-rw-r--r--compiler/rustc_target/src/spec/mod.rs47
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs1
-rw-r--r--compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs1
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs5
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs91
-rw-r--r--compiler/rustc_trait_selection/src/solve/delegate.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs23
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs41
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs30
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs20
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs57
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs8
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs82
-rw-r--r--compiler/rustc_type_ir/src/elaborate.rs38
-rw-r--r--compiler/rustc_type_ir/src/inherent.rs8
-rw-r--r--compiler/rustc_type_ir/src/lang_items.rs2
-rw-r--r--compiler/rustc_type_ir/src/search_graph/mod.rs23
-rw-r--r--compiler/rustc_type_ir/src/solve/mod.rs22
-rw-r--r--library/alloc/src/collections/linked_list/tests.rs161
-rw-r--r--library/alloc/src/string.rs25
m---------library/backtrace0
-rw-r--r--library/core/src/array/iter.rs7
-rw-r--r--library/core/src/cell.rs66
-rw-r--r--library/core/src/clone.rs16
-rw-r--r--library/core/src/cmp.rs35
-rw-r--r--library/core/src/convert/mod.rs11
-rw-r--r--library/core/src/fmt/mod.rs36
-rw-r--r--library/core/src/hash/mod.rs10
-rw-r--r--library/core/src/intrinsics/bounds.rs22
-rw-r--r--library/core/src/intrinsics/mod.rs4
-rw-r--r--library/core/src/io/borrowed_buf.rs6
-rw-r--r--library/core/src/iter/sources/repeat_n.rs161
-rw-r--r--library/core/src/marker.rs99
-rw-r--r--library/core/src/ops/deref.rs16
-rw-r--r--library/core/src/ops/unsize.rs30
-rw-r--r--library/core/src/panic/location.rs13
-rw-r--r--library/core/src/ptr/const_ptr.rs12
-rw-r--r--library/core/src/ptr/metadata.rs38
-rw-r--r--library/core/src/ptr/mod.rs18
-rw-r--r--library/core/src/ptr/mut_ptr.rs13
-rw-r--r--library/core/src/ptr/non_null.rs67
-rw-r--r--library/core/src/ptr/unique.rs28
-rw-r--r--library/core/src/tuple.rs10
-rw-r--r--library/coretests/tests/panic/location.rs8
-rw-r--r--library/proc_macro/src/lib.rs3
-rw-r--r--library/proc_macro/src/quote.rs328
-rw-r--r--library/rtstartup/rsbegin.rs26
-rw-r--r--library/rtstartup/rsend.rs26
-rw-r--r--library/std/src/fs.rs25
-rw-r--r--library/std/src/path.rs27
-rw-r--r--library/std/src/sys/pal/windows/c.rs17
-rw-r--r--library/std/src/sys/pal/windows/c/bindings.txt17
-rw-r--r--library/std/src/sys/pal/windows/c/windows_sys.rs19
-rw-r--r--library/std/src/sys/pal/windows/pipe.rs175
-rw-r--r--src/bootstrap/Cargo.lock36
-rw-r--r--src/bootstrap/Cargo.toml1
-rw-r--r--src/bootstrap/README.md4
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs27
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs9
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs4
-rw-r--r--src/bootstrap/src/core/builder/cargo.rs4
-rw-r--r--src/bootstrap/src/core/builder/mod.rs21
-rw-r--r--src/bootstrap/src/core/builder/tests.rs96
-rw-r--r--src/bootstrap/src/lib.rs49
-rw-r--r--src/bootstrap/src/utils/build_stamp/tests.rs24
-rw-r--r--src/bootstrap/src/utils/cache.rs39
-rw-r--r--src/bootstrap/src/utils/cc_detect.rs21
-rw-r--r--src/bootstrap/src/utils/cc_detect/tests.rs36
-rw-r--r--src/bootstrap/src/utils/helpers.rs2
-rw-r--r--src/bootstrap/src/utils/shared_helpers.rs3
-rw-r--r--src/bootstrap/src/utils/shared_helpers/tests.rs (renamed from src/bootstrap/src/utils/tests/shared_helpers_tests.rs)7
-rw-r--r--src/bootstrap/src/utils/tests/mod.rs3
-rw-r--r--src/build_helper/src/util.rs26
-rw-r--r--src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile4
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile6
-rw-r--r--src/ci/github-actions/jobs.yml2
m---------src/doc/book0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
-rw-r--r--src/librustdoc/clean/inline.rs18
-rw-r--r--src/librustdoc/clean/mod.rs19
-rw-r--r--src/librustdoc/clean/simplify.rs12
-rw-r--r--src/librustdoc/clean/types.rs10
-rw-r--r--src/librustdoc/html/render/write_shared.rs6
-rw-r--r--src/librustdoc/html/render/write_shared/tests.rs18
-rw-r--r--src/librustdoc/html/static/.eslintrc.js1
-rw-r--r--src/librustdoc/html/static/js/rustdoc.d.ts6
-rw-r--r--src/librustdoc/html/static/js/search.js1
-rw-r--r--src/librustdoc/html/static/js/src-script.js9
m---------src/llvm-project0
-rw-r--r--src/rustdoc-json-types/lib.rs10
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/inline_always.rs25
-rw-r--r--src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_inline.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs6
-rw-r--r--src/tools/clippy/tests/ui/def_id_nocore.rs8
-rw-r--r--src/tools/clippy/tests/ui/def_id_nocore.stderr2
-rw-r--r--src/tools/miri/src/lib.rs2
-rw-r--r--src/tools/miri/src/shims/native_lib.rs2
-rw-r--r--src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr4
-rw-r--r--src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr4
-rw-r--r--src/tools/miri/tests/pass/shims/fs.rs1
-rw-r--r--src/tools/rust-analyzer/.typos.toml1
-rw-r--r--src/tools/rust-analyzer/Cargo.lock559
-rw-r--r--src/tools/rust-analyzer/Cargo.toml44
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/input.rs4
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr.rs177
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/db.rs89
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs44
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs80
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/find_path.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs58
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs898
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs401
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs172
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs101
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs259
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs44
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs17
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs228
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs368
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs25
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs71
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs385
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs40
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/signatures.rs413
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/src.rs106
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/visibility.rs179
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/db.rs47
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/files.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/db.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/drop.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/generics.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs20
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs17
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs21
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs11
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs585
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tls.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/utils.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/variance.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs289
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs33
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs27
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/symbols.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs39
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt7
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt31
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt36
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt70
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs29
-rw-r--r--src/tools/rust-analyzer/crates/ide/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/annotations.rs82
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_definition.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/implied_dyn_trait.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/navigation_target.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/runnables.rs4
-rw-r--r--src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs1
-rw-r--r--src/tools/rust-analyzer/crates/load-cargo/src/lib.rs6
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/benchmark.rs4
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs11
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs4
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/parser.rs19
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/tests.rs232
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs9
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs70
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs1
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs54
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs4
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs344
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs8
-rw-r--r--src/tools/rust-analyzer/crates/profile/Cargo.toml4
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs8
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/sysroot.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml14
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs5
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs3
-rw-r--r--src/tools/rust-analyzer/crates/span/Cargo.toml3
-rw-r--r--src/tools/rust-analyzer/crates/span/src/ast_id.rs904
-rw-r--r--src/tools/rust-analyzer/crates/span/src/lib.rs24
-rw-r--r--src/tools/rust-analyzer/crates/span/src/map.rs2
-rw-r--r--src/tools/rust-analyzer/crates/stdx/Cargo.toml4
-rw-r--r--src/tools/rust-analyzer/crates/syntax/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs10
-rw-r--r--src/tools/rust-analyzer/crates/test-fixture/src/lib.rs42
-rw-r--r--src/tools/rust-analyzer/docs/book/README.md2
-rw-r--r--src/tools/rust-analyzer/docs/book/src/configuration_generated.md7
-rw-r--r--src/tools/rust-analyzer/docs/book/src/contributing/README.md4
-rw-r--r--src/tools/rust-analyzer/docs/book/src/troubleshooting.md3
-rw-r--r--src/tools/rust-analyzer/editors/code/package-lock.json30
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json10
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/Cargo.toml4
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/src/msg.rs4
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/src/stdio.rs2
-rw-r--r--src/tools/rust-analyzer/xtask/Cargo.toml6
-rw-r--r--tests/assembly/naked-functions/wasm32.rs9
-rw-r--r--tests/assembly/nvptx-c-abi-arg-v7.rs6
-rw-r--r--tests/assembly/nvptx-c-abi-ret-v7.rs6
-rw-r--r--tests/assembly/nvptx-kernel-abi/nvptx-kernel-args-abi-v7.rs6
-rw-r--r--tests/assembly/riscv-float-struct-abi.rs177
-rw-r--r--tests/assembly/rust-abi-arg-attr.rs10
-rw-r--r--tests/assembly/s390x-vector-abi.rs9
-rw-r--r--tests/assembly/small_data_threshold.rs8
-rw-r--r--tests/auxiliary/minicore.rs38
-rw-r--r--tests/codegen-units/item-collection/implicit-panic-call.rs8
-rw-r--r--tests/codegen/abi-x86-sse.rs8
-rw-r--r--tests/codegen/dst-offset.rs5
-rw-r--r--tests/codegen/emscripten-catch-unwind-js-eh.rs8
-rw-r--r--tests/codegen/emscripten-catch-unwind-wasm-eh.rs8
-rw-r--r--tests/codegen/iter-repeat-n-trivial-drop.rs7
-rw-r--r--tests/codegen/riscv-abi/cast-local-large-enough.rs44
-rw-r--r--tests/codegen/terminating-catchpad.rs8
-rw-r--r--tests/codegen/unwind-abis/aapcs-unwind-abi.rs9
-rw-r--r--tests/codegen/unwind-abis/fastcall-unwind-abi.rs9
-rw-r--r--tests/codegen/unwind-abis/stdcall-unwind-abi.rs9
-rw-r--r--tests/codegen/unwind-abis/sysv64-unwind-abi.rs9
-rw-r--r--tests/codegen/unwind-abis/thiscall-unwind-abi.rs9
-rw-r--r--tests/codegen/unwind-abis/vectorcall-unwind-abi.rs9
-rw-r--r--tests/codegen/unwind-abis/win64-unwind-abi.rs9
-rw-r--r--tests/crashes/120033.rs6
-rw-r--r--tests/debuginfo/recursive-type-with-gat.rs14
-rw-r--r--tests/incremental/hashes/trait_defs.rs12
-rw-r--r--tests/incremental/hashes/trait_impls.rs2
-rw-r--r--tests/mir-opt/inline/inline_instruction_set.rs8
-rw-r--r--tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs1
-rw-r--r--tests/run-make/allow-warnings-cmdline-stability/rmake.rs1
-rw-r--r--tests/run-make/amdgpu-kd/foo.rs8
-rw-r--r--tests/run-make/artifact-incr-cache-no-obj/rmake.rs2
-rw-r--r--tests/run-make/artifact-incr-cache/rmake.rs2
-rw-r--r--tests/run-make/atomic-lock-free/atomic_lock_free.rs8
-rw-r--r--tests/run-make/avr-rjmp-offset/avr-rjmp-offsets.rs10
-rw-r--r--tests/run-make/bin-emit-no-symbols/rmake.rs2
-rw-r--r--tests/run-make/box-struct-no-segfault/rmake.rs2
-rw-r--r--tests/run-make/checksum-freshness/rmake.rs1
-rw-r--r--tests/run-make/compiler-lookup-paths-2/rmake.rs2
-rw-r--r--tests/run-make/compiler-lookup-paths/rmake.rs2
-rw-r--r--tests/run-make/const-trait-stable-toolchain/rmake.rs2
-rw-r--r--tests/run-make/crate-circular-deps-link/rmake.rs2
-rw-r--r--tests/run-make/cross-lang-lto-riscv-abi/riscv-xlto.rs6
-rw-r--r--tests/run-make/cross-lang-lto-upstream-rlibs/rmake.rs2
-rw-r--r--tests/run-make/cross-lang-lto/rmake.rs2
-rw-r--r--tests/run-make/debugger-visualizer-dep-info/rmake.rs2
-rw-r--r--tests/run-make/dep-info/rmake.rs2
-rw-r--r--tests/run-make/diagnostics-traits-from-duplicate-crates/rmake.rs2
-rw-r--r--tests/run-make/doctests-merge/rmake.rs1
-rw-r--r--tests/run-make/doctests-runtool/rmake.rs2
-rw-r--r--tests/run-make/dump-ice-to-disk/rmake.rs16
-rw-r--r--tests/run-make/dump-mono-stats/rmake.rs2
-rw-r--r--tests/run-make/duplicate-output-flavors/rmake.rs1
-rw-r--r--tests/run-make/embed-metadata/rmake.rs2
-rw-r--r--tests/run-make/embed-source-dwarf/rmake.rs1
-rw-r--r--tests/run-make/emit-named-files/rmake.rs1
-rw-r--r--tests/run-make/emit-path-unhashed/rmake.rs2
-rw-r--r--tests/run-make/emit-stack-sizes/rmake.rs1
-rw-r--r--tests/run-make/emit-to-stdout/rmake.rs1
-rw-r--r--tests/run-make/env-dep-info/rmake.rs2
-rw-r--r--tests/run-make/error-found-staticlib-instead-crate/rmake.rs2
-rw-r--r--tests/run-make/exit-code/rmake.rs2
-rw-r--r--tests/run-make/export/disambiguator/rmake.rs11
-rw-r--r--tests/run-make/export/extern-opt/rmake.rs8
-rw-r--r--tests/run-make/export/simple/rmake.rs11
-rw-r--r--tests/run-make/extern-diff-internal-name/rmake.rs2
-rw-r--r--tests/run-make/extern-flag-fun/rmake.rs2
-rw-r--r--tests/run-make/extern-flag-rename-transitive/rmake.rs2
-rw-r--r--tests/run-make/extern-multiple-copies/rmake.rs2
-rw-r--r--tests/run-make/extern-multiple-copies2/rmake.rs2
-rw-r--r--tests/run-make/ice-static-mir/rmake.rs2
-rw-r--r--tests/run-make/include-all-symbols-linking/rmake.rs1
-rw-r--r--tests/run-make/include-bytes-deps/rmake.rs2
-rw-r--r--tests/run-make/incremental-debugger-visualizer/rmake.rs2
-rw-r--r--tests/run-make/inline-always-many-cgu/rmake.rs1
-rw-r--r--tests/run-make/invalid-so/rmake.rs2
-rw-r--r--tests/run-make/invalid-staticlib/rmake.rs2
-rw-r--r--tests/run-make/invalid-symlink-search-path/rmake.rs1
-rw-r--r--tests/run-make/invalid-tmpdir-env-var/rmake.rs2
-rw-r--r--tests/run-make/issue-107495-archive-permissions/rmake.rs1
-rw-r--r--tests/run-make/issue-125484-used-dependencies/rmake.rs2
-rw-r--r--tests/run-make/json-error-no-offset/rmake.rs2
-rw-r--r--tests/run-make/lib-trait-for-trait-no-ice/rmake.rs2
-rw-r--r--tests/run-make/link-arg/rmake.rs2
-rw-r--r--tests/run-make/link-args-order/rmake.rs2
-rw-r--r--tests/run-make/link-dedup/rmake.rs2
-rw-r--r--tests/run-make/linker-warning/rmake.rs1
-rw-r--r--tests/run-make/llvm-outputs/rmake.rs1
-rw-r--r--tests/run-make/lto-avoid-object-duplication/rmake.rs1
-rw-r--r--tests/run-make/manual-crate-name/rmake.rs1
-rw-r--r--tests/run-make/many-crates-but-no-match/rmake.rs2
-rw-r--r--tests/run-make/metadata-dep-info/rmake.rs2
-rw-r--r--tests/run-make/metadata-only-crate-no-ice/rmake.rs2
-rw-r--r--tests/run-make/min-global-align/min_global_align.rs8
-rw-r--r--tests/run-make/missing-crate-dependency/rmake.rs2
-rw-r--r--tests/run-make/multiple-emits/rmake.rs1
-rw-r--r--tests/run-make/native-lib-alt-naming/rmake.rs2
-rw-r--r--tests/run-make/native-link-modifier-verbatim-linker/rmake.rs1
-rw-r--r--tests/run-make/native-link-modifier-verbatim-rustc/rmake.rs2
-rw-r--r--tests/run-make/no-builtins-attribute/rmake.rs2
-rw-r--r--tests/run-make/no-builtins-lto/rmake.rs2
-rw-r--r--tests/run-make/non-unicode-env/rmake.rs1
-rw-r--r--tests/run-make/non-unicode-in-incremental-dir/rmake.rs1
-rw-r--r--tests/run-make/notify-all-emit-artifacts/rmake.rs2
-rw-r--r--tests/run-make/optimization-remarks-dir/rmake.rs2
-rw-r--r--tests/run-make/overwrite-input/rmake.rs2
-rw-r--r--tests/run-make/parallel-rustc-no-overwrite/rmake.rs2
-rw-r--r--tests/run-make/pass-linker-flags-from-dep/rmake.rs2
-rw-r--r--tests/run-make/pass-linker-flags/rmake.rs2
-rw-r--r--tests/run-make/pgo-gen-no-imp-symbols/rmake.rs2
-rw-r--r--tests/run-make/pretty-print-with-dep-file/rmake.rs2
-rw-r--r--tests/run-make/proc-macro-three-crates/rmake.rs2
-rw-r--r--tests/run-make/raw-dylib-cross-compilation/lib.rs6
-rw-r--r--tests/run-make/remap-path-prefix-dwarf/rmake.rs1
-rw-r--r--tests/run-make/remap-path-prefix/rmake.rs2
-rw-r--r--tests/run-make/repr128-dwarf/rmake.rs1
-rw-r--r--tests/run-make/reproducible-build-2/rmake.rs1
-rw-r--r--tests/run-make/resolve-rename/rmake.rs2
-rw-r--r--tests/run-make/rlib-format-packed-bundled-libs-2/rmake.rs2
-rw-r--r--tests/run-make/rustc-macro-dep-files/rmake.rs2
-rw-r--r--tests/run-make/rustdoc-scrape-examples-invalid-expr/rmake.rs1
-rw-r--r--tests/run-make/rustdoc-scrape-examples-multiple/rmake.rs1
-rw-r--r--tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs1
-rw-r--r--tests/run-make/rustdoc-scrape-examples-remap/rmake.rs1
-rw-r--r--tests/run-make/rustdoc-scrape-examples-test/rmake.rs1
-rw-r--r--tests/run-make/rustdoc-scrape-examples-whitespace/rmake.rs1
-rw-r--r--tests/run-make/rustdoc-with-short-out-dir-option/rmake.rs1
-rw-r--r--tests/run-make/share-generics-dylib/rmake.rs2
-rw-r--r--tests/run-make/short-ice/rmake.rs1
-rw-r--r--tests/run-make/simd-ffi/simd.rs8
-rw-r--r--tests/run-make/stable-symbol-names/rmake.rs2
-rw-r--r--tests/run-make/staticlib-blank-lib/rmake.rs2
-rw-r--r--tests/run-make/staticlib-broken-bitcode/rmake.rs2
-rw-r--r--tests/run-make/staticlib-thin-archive/rmake.rs2
-rw-r--r--tests/run-make/stdin-rustc/rmake.rs1
-rw-r--r--tests/run-make/symbol-visibility/rmake.rs2
-rw-r--r--tests/run-make/symbols-include-type-name/rmake.rs2
-rw-r--r--tests/run-make/target-specs/foo.rs8
-rw-r--r--tests/run-make/track-path-dep-info/rmake.rs2
-rw-r--r--tests/run-make/type-mismatch-same-crate-name/rmake.rs2
-rw-r--r--tests/run-make/unknown-mod-stdin/rmake.rs2
-rw-r--r--tests/run-make/unstable-feature-usage-metrics-incremental/rmake.rs12
-rw-r--r--tests/run-make/unstable-feature-usage-metrics/rmake.rs11
-rw-r--r--tests/run-make/use-suggestions-rust-2018/rmake.rs2
-rw-r--r--tests/run-make/used/rmake.rs2
-rw-r--r--tests/rustdoc-gui/globals.goml3
-rw-r--r--tests/rustdoc-json/attrs/inline.rs6
-rw-r--r--tests/rustdoc-json/impls/auto.rs12
-rw-r--r--tests/rustdoc-json/primitives/primitive_impls.rs8
-rw-r--r--tests/rustdoc-ui/custom_code_classes_in_docs-warning3.rs8
-rw-r--r--tests/rustdoc-ui/custom_code_classes_in_docs-warning3.stderr4
-rw-r--r--tests/rustdoc-ui/target-feature-stability.rs8
-rw-r--r--tests/rustdoc/file-creation-111249.rs12
-rw-r--r--tests/rustdoc/foreigntype.rs2
-rw-r--r--tests/rustdoc/intra-doc/auxiliary/my-core.rs8
-rw-r--r--tests/rustdoc/intra-doc/extern-type.rs4
-rw-r--r--tests/rustdoc/intra-doc/no-doc-primitive.rs8
-rw-r--r--tests/rustdoc/intra-doc/prim-methods-local.rs8
-rw-r--r--tests/rustdoc/intra-doc/prim-self.rs8
-rw-r--r--tests/rustdoc/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs8
-rw-r--r--tests/rustdoc/primitive/cross-crate-primitive-doc.rs8
-rw-r--r--tests/rustdoc/reexport/cfg_doc_reexport.rs8
-rw-r--r--tests/rustdoc/reexport/reexport-trait-from-hidden-111064-2.rs10
-rw-r--r--tests/rustdoc/safe-intrinsic.rs8
-rw-r--r--tests/ui-fulldeps/pprust-expr-roundtrip.rs8
-rw-r--r--tests/ui-fulldeps/pprust-parenthesis-insertion.rs3
-rw-r--r--tests/ui-fulldeps/stable-mir/check_variant.rs183
-rw-r--r--tests/ui/abi/fixed_x18.rs6
-rw-r--r--tests/ui/abi/numbers-arithmetic/float-struct.rs44
-rw-r--r--tests/ui/abi/shadow-call-stack-without-fixed-x18.rs8
-rw-r--r--tests/ui/attributes/dump-preds.stderr2
-rw-r--r--tests/ui/attributes/export/lang-item.rs8
-rw-r--r--tests/ui/attributes/export/lang-item.stderr14
-rw-r--r--tests/ui/attributes/multiple-invalid.stderr18
-rw-r--r--tests/ui/attributes/rustc_confusables.rs4
-rw-r--r--tests/ui/attributes/rustc_confusables.stderr29
-rw-r--r--tests/ui/borrowck/span-semicolon-issue-139049.fixed59
-rw-r--r--tests/ui/borrowck/span-semicolon-issue-139049.rs59
-rw-r--r--tests/ui/borrowck/span-semicolon-issue-139049.stderr62
-rw-r--r--tests/ui/codegen/mismatched-data-layouts.rs8
-rw-r--r--tests/ui/const-generics/unused-type-param-suggestion.rs1
-rw-r--r--tests/ui/const-generics/unused-type-param-suggestion.stderr1
-rw-r--r--tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs6
-rw-r--r--tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr26
-rw-r--r--tests/ui/debuginfo/dwarf-versions.rs8
-rw-r--r--tests/ui/deprecation/deprecation-sanity.rs14
-rw-r--r--tests/ui/deprecation/deprecation-sanity.stderr128
-rw-r--r--tests/ui/deprecation/invalid-literal.stderr19
-rw-r--r--tests/ui/error-codes/E0534.rs6
-rw-r--r--tests/ui/error-codes/E0534.stderr9
-rw-r--r--tests/ui/error-codes/E0539.rs (renamed from tests/ui/error-codes/E0565-2.rs)2
-rw-r--r--tests/ui/error-codes/E0539.stderr13
-rw-r--r--tests/ui/error-codes/E0540.rs6
-rw-r--r--tests/ui/error-codes/E0540.stderr19
-rw-r--r--tests/ui/error-codes/E0565-1.stderr20
-rw-r--r--tests/ui/error-codes/E0565-2.stderr11
-rw-r--r--tests/ui/extern/extern-type-diag-not-similar.rs7
-rw-r--r--tests/ui/extern/extern-type-diag-not-similar.stderr6
-rw-r--r--tests/ui/extern/extern-types-manual-sync-send.rs8
-rw-r--r--tests/ui/extern/extern-types-not-sync-send.rs8
-rw-r--r--tests/ui/extern/extern-types-not-sync-send.stderr16
-rw-r--r--tests/ui/extern/extern-types-pointer-cast.rs5
-rw-r--r--tests/ui/extern/extern-types-size_of_val.rs16
-rw-r--r--tests/ui/extern/extern-types-size_of_val.stderr39
-rw-r--r--tests/ui/extern/extern-types-thin-pointer.rs7
-rw-r--r--tests/ui/extern/extern-types-trait-impl.rs9
-rw-r--r--tests/ui/extern/extern-types-unsized.rs2
-rw-r--r--tests/ui/extern/extern-types-unsized.stderr30
-rw-r--r--tests/ui/extern/unsized-extern-derefmove.rs13
-rw-r--r--tests/ui/extern/unsized-extern-derefmove.stderr52
-rw-r--r--tests/ui/feature-gates/feature-gate-default-field-values.rs10
-rw-r--r--tests/ui/feature-gates/feature-gate-default-field-values.stderr54
-rw-r--r--tests/ui/feature-gates/feature-gate-sized-hierarchy.rs29
-rw-r--r--tests/ui/feature-gates/feature-gate-sized-hierarchy.stderr42
-rw-r--r--tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr20
-rw-r--r--tests/ui/force-inlining/invalid.rs1
-rw-r--r--tests/ui/force-inlining/invalid.stderr132
-rw-r--r--tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.rs8
-rw-r--r--tests/ui/invalid/invalid-inline.rs4
-rw-r--r--tests/ui/invalid/invalid-inline.stderr31
-rw-r--r--tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.rs7
-rw-r--r--tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr14
-rw-r--r--tests/ui/issues/issue-43988.rs4
-rw-r--r--tests/ui/issues/issue-43988.stderr76
-rw-r--r--tests/ui/lang-items/issue-83471.rs10
-rw-r--r--tests/ui/lang-items/issue-83471.stderr30
-rw-r--r--tests/ui/lang-items/issue-87573.rs8
-rw-r--r--tests/ui/lang-items/issue-87573.stderr4
-rw-r--r--tests/ui/lang-items/lang-item-generic-requirements.rs8
-rw-r--r--tests/ui/lang-items/lang-item-generic-requirements.stderr24
-rw-r--r--tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs8
-rw-r--r--tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr2
-rw-r--r--tests/ui/lang-items/start_lang_item_args.argc.stderr2
-rw-r--r--tests/ui/lang-items/start_lang_item_args.argv.stderr2
-rw-r--r--tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr2
-rw-r--r--tests/ui/lang-items/start_lang_item_args.main_args.stderr2
-rw-r--r--tests/ui/lang-items/start_lang_item_args.main_ret.stderr2
-rw-r--r--tests/ui/lang-items/start_lang_item_args.main_ty.stderr2
-rw-r--r--tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr2
-rw-r--r--tests/ui/lang-items/start_lang_item_args.missing_ret.stderr2
-rw-r--r--tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr2
-rw-r--r--tests/ui/lang-items/start_lang_item_args.rs6
-rw-r--r--tests/ui/lang-items/start_lang_item_args.sigpipe.stderr2
-rw-r--r--tests/ui/lang-items/start_lang_item_args.start_ret.stderr2
-rw-r--r--tests/ui/lang-items/start_lang_item_args.too_many_args.stderr2
-rw-r--r--tests/ui/lang-items/start_lang_item_with_target_feature.rs9
-rw-r--r--tests/ui/lang-items/start_lang_item_with_target_feature.stderr2
-rw-r--r--tests/ui/layout/unconstrained-param-ice-137308.rs4
-rw-r--r--tests/ui/layout/unconstrained-param-ice-137308.stderr11
-rw-r--r--tests/ui/lint/redundant-semicolon/suggest-remove-semi-in-macro-expansion-issue-142143.rs11
-rw-r--r--tests/ui/lint/redundant-semicolon/suggest-remove-semi-in-macro-expansion-issue-142143.stderr18
-rw-r--r--tests/ui/lint/unused/unused-attr-duplicate.stderr26
-rw-r--r--tests/ui/macros/genercs-in-path-with-prettry-hir.stdout2
-rw-r--r--tests/ui/malformed/malformed-regressions.stderr18
-rw-r--r--tests/ui/nll/issue-50716.rs3
-rw-r--r--tests/ui/nll/issue-50716.stderr20
-rw-r--r--tests/ui/offset-of/offset-of-dst-field.rs5
-rw-r--r--tests/ui/offset-of/offset-of-dst-field.stderr20
-rw-r--r--tests/ui/panic-handler/panic-handler-requires-panic-info.rs8
-rw-r--r--tests/ui/parser/doc-comment-after-missing-comma-issue-142311.rs34
-rw-r--r--tests/ui/parser/doc-comment-after-missing-comma-issue-142311.stderr43
-rw-r--r--tests/ui/print-request/emit-warning-print-link-info-without-staticlib.rs5
-rw-r--r--tests/ui/print-request/emit-warning-print-link-info-without-staticlib.stderr6
-rw-r--r--tests/ui/print-request/emit-warning-while-exe-and-print-link-info.rs3
-rw-r--r--tests/ui/print-request/emit-warning-while-exe-and-print-link-info.stderr4
-rw-r--r--tests/ui/print-request/stability.rs1
-rw-r--r--tests/ui/privacy/privacy1.rs10
-rw-r--r--tests/ui/privacy/privacy1.stderr62
-rw-r--r--tests/ui/privacy/privacy4.rs4
-rw-r--r--tests/ui/privacy/privacy4.stderr4
-rw-r--r--tests/ui/proc-macro/quote/auxiliary/basic.rs152
-rw-r--r--tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.rs6
-rw-r--r--tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.stderr11
-rw-r--r--tests/ui/proc-macro/quote/does-not-have-iter-interpolated.rs6
-rw-r--r--tests/ui/proc-macro/quote/does-not-have-iter-interpolated.stderr11
-rw-r--r--tests/ui/proc-macro/quote/does-not-have-iter-separated.rs6
-rw-r--r--tests/ui/proc-macro/quote/does-not-have-iter-separated.stderr10
-rw-r--r--tests/ui/proc-macro/quote/does-not-have-iter.rs6
-rw-r--r--tests/ui/proc-macro/quote/does-not-have-iter.stderr10
-rw-r--r--tests/ui/proc-macro/quote/not-quotable.stderr4
-rw-r--r--tests/ui/proc-macro/quote/not-repeatable.rs6
-rw-r--r--tests/ui/proc-macro/quote/not-repeatable.stderr23
-rw-r--r--tests/ui/repr/repr.stderr22
-rw-r--r--tests/ui/sized-hierarchy/alias-bounds.rs28
-rw-r--r--tests/ui/sized-hierarchy/auxiliary/pretty-print-dep.rs19
-rw-r--r--tests/ui/sized-hierarchy/auxiliary/pretty-print-no-feat-dep.rs7
-rw-r--r--tests/ui/sized-hierarchy/default-bound.rs49
-rw-r--r--tests/ui/sized-hierarchy/default-bound.stderr88
-rw-r--r--tests/ui/sized-hierarchy/default-supertrait.rs61
-rw-r--r--tests/ui/sized-hierarchy/default-supertrait.stderr125
-rw-r--r--tests/ui/sized-hierarchy/elaboration-opt-regions-1.rs18
-rw-r--r--tests/ui/sized-hierarchy/elaboration-opt-regions.rs18
-rw-r--r--tests/ui/sized-hierarchy/extern-type-behind-ptr.rs20
-rw-r--r--tests/ui/sized-hierarchy/impls.rs310
-rw-r--r--tests/ui/sized-hierarchy/impls.stderr394
-rw-r--r--tests/ui/sized-hierarchy/overflow.current.stderr45
-rw-r--r--tests/ui/sized-hierarchy/overflow.rs21
-rw-r--r--tests/ui/sized-hierarchy/pointee-supertrait.rs28
-rw-r--r--tests/ui/sized-hierarchy/pretty-print-no-feat-dep-has-feat.rs26
-rw-r--r--tests/ui/sized-hierarchy/pretty-print-no-feat-dep-has-feat.stderr42
-rw-r--r--tests/ui/sized-hierarchy/pretty-print-no-feat.rs19
-rw-r--r--tests/ui/sized-hierarchy/pretty-print-no-feat.stderr22
-rw-r--r--tests/ui/sized-hierarchy/pretty-print-opaque-no-feat.rs13
-rw-r--r--tests/ui/sized-hierarchy/pretty-print-opaque-no-feat.stderr12
-rw-r--r--tests/ui/sized-hierarchy/pretty-print-opaque.rs45
-rw-r--r--tests/ui/sized-hierarchy/pretty-print-opaque.stderr59
-rw-r--r--tests/ui/sized-hierarchy/pretty-print.rs28
-rw-r--r--tests/ui/sized-hierarchy/pretty-print.stderr43
-rw-r--r--tests/ui/sized-hierarchy/trait-aliases.rs9
-rw-r--r--tests/ui/span/E0535.rs6
-rw-r--r--tests/ui/span/E0535.stderr11
-rw-r--r--tests/ui/span/E0539.rs6
-rw-r--r--tests/ui/span/E0539.stderr20
-rw-r--r--tests/ui/stability-attribute/stability-attribute-sanity-2.rs2
-rw-r--r--tests/ui/stability-attribute/stability-attribute-sanity-2.stderr9
-rw-r--r--tests/ui/stability-attribute/stability-attribute-sanity.rs8
-rw-r--r--tests/ui/stability-attribute/stability-attribute-sanity.stderr36
-rw-r--r--tests/ui/stack-protector/warn-stack-protector-unsupported.rs9
-rw-r--r--tests/ui/structs/default-field-values/failures.rs6
-rw-r--r--tests/ui/structs/default-field-values/failures.stderr30
-rw-r--r--tests/ui/symbol-names/foreign-types.rs5
-rw-r--r--tests/ui/symbol-names/foreign-types.stderr6
-rw-r--r--tests/ui/target-cpu/explicit-target-cpu.rs6
-rw-r--r--tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.rs8
-rw-r--r--tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.stderr4
-rw-r--r--tests/ui/target-feature/abi-incompatible-target-feature-attribute.riscv.stderr2
-rw-r--r--tests/ui/target-feature/abi-incompatible-target-feature-attribute.rs6
-rw-r--r--tests/ui/target-feature/abi-incompatible-target-feature-attribute.x86.stderr2
-rw-r--r--tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs6
-rw-r--r--tests/ui/target-feature/abi-irrelevant-target-feature-flag-disable.rs8
-rw-r--r--tests/ui/target-feature/abi-required-target-feature-attribute.rs8
-rw-r--r--tests/ui/target-feature/abi-required-target-feature-flag-disable.rs6
-rw-r--r--tests/ui/target-feature/feature-hierarchy.rs10
-rw-r--r--tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.rs8
-rw-r--r--tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.stderr2
-rw-r--r--tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.rs6
-rw-r--r--tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.stderr2
-rw-r--r--tests/ui/target-feature/forbidden-hardfloat-target-feature-cfg.rs20
-rw-r--r--tests/ui/target-feature/forbidden-target-feature-attribute.rs8
-rw-r--r--tests/ui/target-feature/forbidden-target-feature-attribute.stderr2
-rw-r--r--tests/ui/target-feature/forbidden-target-feature-cfg.rs8
-rw-r--r--tests/ui/target-feature/forbidden-target-feature-flag-disable.rs8
-rw-r--r--tests/ui/target-feature/forbidden-target-feature-flag.rs8
-rw-r--r--tests/ui/target-feature/target-cpu-lacks-required-target-feature.rs8
-rw-r--r--tests/ui/target-feature/tied-features-cli.rs10
-rw-r--r--tests/ui/target-feature/tied-features-no-implication-1.rs10
-rw-r--r--tests/ui/target-feature/tied-features-no-implication.pacg.stderr2
-rw-r--r--tests/ui/target-feature/tied-features-no-implication.rs10
-rw-r--r--tests/ui/traits/cache-reached-depth-ice.rs5
-rw-r--r--tests/ui/traits/cache-reached-depth-ice.stderr6
-rw-r--r--tests/ui/traits/const-traits/auxiliary/minicore.rs59
-rw-r--r--tests/ui/traits/default_auto_traits/backward-compatible-lazy-bounds-pass.rs8
-rw-r--r--tests/ui/traits/default_auto_traits/default-bounds.rs8
-rw-r--r--tests/ui/traits/default_auto_traits/default-bounds.stderr8
-rw-r--r--tests/ui/traits/default_auto_traits/extern-types.current.stderr6
-rw-r--r--tests/ui/traits/default_auto_traits/extern-types.next.stderr6
-rw-r--r--tests/ui/traits/default_auto_traits/extern-types.rs10
-rw-r--r--tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs8
-rw-r--r--tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr6
-rw-r--r--tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs8
-rw-r--r--tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr18
-rw-r--r--tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.current.stderr20
-rw-r--r--tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.next.stderr18
-rw-r--r--tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.rs2
-rw-r--r--tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr7
-rw-r--r--tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr19
-rw-r--r--tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr16
-rw-r--r--tests/ui/traits/non_lifetime_binders/basic.rs7
-rw-r--r--tests/ui/traits/non_lifetime_binders/basic.stderr2
-rw-r--r--tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.rs7
-rw-r--r--tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.stderr20
-rw-r--r--tests/ui/traits/non_lifetime_binders/on-rpit.rs7
-rw-r--r--tests/ui/traits/non_lifetime_binders/on-rpit.stderr2
-rw-r--r--tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs9
-rw-r--r--tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr6
-rw-r--r--tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.current.stderr2
-rw-r--r--tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.next.stderr2
-rw-r--r--tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.rs13
-rw-r--r--tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.current.stderr2
-rw-r--r--tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.next.stderr2
-rw-r--r--tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.rs9
-rw-r--r--tests/ui/traits/non_lifetime_binders/universe-error1.rs9
-rw-r--r--tests/ui/traits/non_lifetime_binders/universe-error1.stderr8
-rw-r--r--tests/ui/traits/resolve-impl-before-constrain-check.rs1
-rw-r--r--tests/ui/traits/resolve-impl-before-constrain-check.stderr11
-rw-r--r--tests/ui/traits/unconstrained-projection-normalization-2.next.stderr11
-rw-r--r--tests/ui/traits/unconstrained-projection-normalization-2.rs1
742 files changed, 13017 insertions, 6397 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 4489a424c0d..11afd359e5a 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -710,6 +710,12 @@ impl Pat {
     }
 }
 
+impl From<P<Pat>> for Pat {
+    fn from(value: P<Pat>) -> Self {
+        *value
+    }
+}
+
 /// A single field in a struct pattern.
 ///
 /// Patterns like the fields of `Foo { x, ref y, ref mut z }`
@@ -1553,17 +1559,23 @@ impl Expr {
         )
     }
 
-    /// Creates a dummy `P<Expr>`.
+    /// Creates a dummy `Expr`.
     ///
     /// Should only be used when it will be replaced afterwards or as a return value when an error was encountered.
-    pub fn dummy() -> P<Expr> {
-        P(Expr {
+    pub fn dummy() -> Expr {
+        Expr {
             id: DUMMY_NODE_ID,
             kind: ExprKind::Dummy,
             span: DUMMY_SP,
             attrs: ThinVec::new(),
             tokens: None,
-        })
+        }
+    }
+}
+
+impl From<P<Expr>> for Expr {
+    fn from(value: P<Expr>) -> Self {
+        *value
     }
 }
 
@@ -2374,6 +2386,12 @@ impl Clone for Ty {
     }
 }
 
+impl From<P<Ty>> for Ty {
+    fn from(value: P<Ty>) -> Self {
+        *value
+    }
+}
+
 impl Ty {
     pub fn peel_refs(&self) -> &Self {
         let mut final_ty = self;
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 71a47dcfcba..07fbe8045fc 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -168,7 +168,7 @@ pub trait MutVisitor: Sized + MutVisitorResult<Result = ()> {
         walk_flat_map_arm(self, arm)
     }
 
-    fn visit_pat(&mut self, p: &mut P<Pat>) {
+    fn visit_pat(&mut self, p: &mut Pat) {
         walk_pat(self, p);
     }
 
@@ -176,7 +176,7 @@ pub trait MutVisitor: Sized + MutVisitorResult<Result = ()> {
         walk_anon_const(self, c);
     }
 
-    fn visit_expr(&mut self, e: &mut P<Expr>) {
+    fn visit_expr(&mut self, e: &mut Expr) {
         walk_expr(self, e);
     }
 
@@ -194,7 +194,7 @@ pub trait MutVisitor: Sized + MutVisitorResult<Result = ()> {
         walk_generic_arg(self, arg);
     }
 
-    fn visit_ty(&mut self, t: &mut P<Ty>) {
+    fn visit_ty(&mut self, t: &mut Ty) {
         walk_ty(self, t);
     }
 
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 1449a4a5fb3..bd2ab34bfc1 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -884,7 +884,7 @@ macro_rules! common_visitor_and_walkers {
                 TyKind::BareFn(function_declaration) => {
                     let BareFnTy { safety, ext: _, generic_params, decl, decl_span } =
                         &$($mut)? **function_declaration;
-                    visit_safety(vis, safety);
+                    try_visit!(visit_safety(vis, safety));
                     try_visit!(visit_generic_params(vis, generic_params));
                     try_visit!(vis.visit_fn_decl(decl));
                     try_visit!(visit_span(vis, decl_span));
@@ -1235,7 +1235,7 @@ macro_rules! common_visitor_and_walkers {
                     bounds,
                     bound_generic_params,
                 }) => {
-                    visit_generic_params(vis, bound_generic_params);
+                    try_visit!(visit_generic_params(vis, bound_generic_params));
                     try_visit!(vis.visit_ty(bounded_ty));
                     walk_list!(vis, visit_param_bound, bounds, BoundKind::Bound);
                 }
@@ -1420,7 +1420,7 @@ macro_rules! common_visitor_and_walkers {
                     let StructExpr { qself, path, fields, rest } = &$($mut)?**se;
                     try_visit!(vis.visit_qself(qself));
                     try_visit!(vis.visit_path(path));
-                    visit_expr_fields(vis, fields);
+                    try_visit!(visit_expr_fields(vis, fields));
                     match rest {
                         StructRest::Base(expr) => try_visit!(vis.visit_expr(expr)),
                         StructRest::Rest(_span) => {}
diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl
index 5ef76fb64aa..50eb7c7ae99 100644
--- a/compiler/rustc_ast_lowering/messages.ftl
+++ b/compiler/rustc_ast_lowering/messages.ftl
@@ -179,6 +179,8 @@ ast_lowering_underscore_expr_lhs_assign =
     in expressions, `_` can only be used on the left-hand side of an assignment
     .label = `_` not allowed here
 
+ast_lowering_union_default_field_values = unions cannot have default field values
+
 ast_lowering_unstable_inline_assembly = inline assembly is not stable yet on this architecture
 ast_lowering_unstable_inline_assembly_label_operand_with_outputs =
     using both label and output operands for inline assembly is unstable
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index 576fa9731e9..b444324ef91 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -475,3 +475,10 @@ pub(crate) struct UseConstGenericArg {
     #[suggestion_part(code = "{other_args}")]
     pub call_args: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(ast_lowering_union_default_field_values)]
+pub(crate) struct UnionWithDefault {
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 49110c93954..ef27d0ef69b 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -17,6 +17,7 @@ use tracing::instrument;
 
 use super::errors::{
     InvalidAbi, InvalidAbiSuggestion, MisplacedRelaxTraitBound, TupleStructWithDefault,
+    UnionWithDefault,
 };
 use super::stability::{enabled_names, gate_unstable_abi};
 use super::{
@@ -316,7 +317,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| {
                         this.arena.alloc_from_iter(
-                            enum_definition.variants.iter().map(|x| this.lower_variant(x)),
+                            enum_definition.variants.iter().map(|x| this.lower_variant(i, x)),
                         )
                     },
                 );
@@ -328,7 +329,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     generics,
                     id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                    |this| this.lower_variant_data(hir_id, struct_def),
+                    |this| this.lower_variant_data(hir_id, i, struct_def),
                 );
                 hir::ItemKind::Struct(ident, generics, struct_def)
             }
@@ -338,7 +339,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     generics,
                     id,
                     ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
-                    |this| this.lower_variant_data(hir_id, vdata),
+                    |this| this.lower_variant_data(hir_id, i, vdata),
                 );
                 hir::ItemKind::Union(ident, generics, vdata)
             }
@@ -714,13 +715,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
         }
     }
 
-    fn lower_variant(&mut self, v: &Variant) -> hir::Variant<'hir> {
+    fn lower_variant(&mut self, item_kind: &ItemKind, v: &Variant) -> hir::Variant<'hir> {
         let hir_id = self.lower_node_id(v.id);
         self.lower_attrs(hir_id, &v.attrs, v.span);
         hir::Variant {
             hir_id,
             def_id: self.local_def_id(v.id),
-            data: self.lower_variant_data(hir_id, &v.data),
+            data: self.lower_variant_data(hir_id, item_kind, &v.data),
             disr_expr: v.disr_expr.as_ref().map(|e| self.lower_anon_const_to_anon_const(e)),
             ident: self.lower_ident(v.ident),
             span: self.lower_span(v.span),
@@ -730,15 +731,36 @@ impl<'hir> LoweringContext<'_, 'hir> {
     fn lower_variant_data(
         &mut self,
         parent_id: hir::HirId,
+        item_kind: &ItemKind,
         vdata: &VariantData,
     ) -> hir::VariantData<'hir> {
         match vdata {
-            VariantData::Struct { fields, recovered } => hir::VariantData::Struct {
-                fields: self
+            VariantData::Struct { fields, recovered } => {
+                let fields = self
                     .arena
-                    .alloc_from_iter(fields.iter().enumerate().map(|f| self.lower_field_def(f))),
-                recovered: *recovered,
-            },
+                    .alloc_from_iter(fields.iter().enumerate().map(|f| self.lower_field_def(f)));
+
+                if let ItemKind::Union(..) = item_kind {
+                    for field in &fields[..] {
+                        if let Some(default) = field.default {
+                            // Unions cannot derive `Default`, and it's not clear how to use default
+                            // field values of unions if that was supported. Therefore, blanket reject
+                            // trying to use field values with unions.
+                            if self.tcx.features().default_field_values() {
+                                self.dcx().emit_err(UnionWithDefault { span: default.span });
+                            } else {
+                                let _ = self.dcx().span_delayed_bug(
+                                default.span,
+                                "expected union default field values feature gate error but none \
+                                was produced",
+                            );
+                            }
+                        }
+                    }
+                }
+
+                hir::VariantData::Struct { fields, recovered: *recovered }
+            }
             VariantData::Tuple(fields, id) => {
                 let ctor_id = self.lower_node_id(*id);
                 self.alias_attrs(ctor_id, parent_id);
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 018887d0e8e..b69a91e2f5f 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -224,20 +224,6 @@ impl<'a> AstValidator<'a> {
         }
     }
 
-    fn visit_struct_field_def(&mut self, field: &'a FieldDef) {
-        if let Some(ref ident) = field.ident
-            && ident.name == kw::Underscore
-        {
-            self.visit_vis(&field.vis);
-            self.visit_ident(ident);
-            self.visit_ty_common(&field.ty);
-            self.walk_ty(&field.ty);
-            walk_list!(self, visit_attribute, &field.attrs);
-        } else {
-            self.visit_field_def(field);
-        }
-    }
-
     fn dcx(&self) -> DiagCtxtHandle<'a> {
         self.sess.dcx()
     }
@@ -1135,8 +1121,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 VariantData::Struct { fields, .. } => {
                     self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
                     self.visit_generics(generics);
-                    // Permit `Anon{Struct,Union}` as field type.
-                    walk_list!(self, visit_struct_field_def, fields);
+                    walk_list!(self, visit_field_def, fields);
                 }
                 _ => visit::walk_item(self, item),
             },
@@ -1148,8 +1133,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     VariantData::Struct { fields, .. } => {
                         self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
                         self.visit_generics(generics);
-                        // Permit `Anon{Struct,Union}` as field type.
-                        walk_list!(self, visit_struct_field_def, fields);
+                        walk_list!(self, visit_field_def, fields);
                     }
                     _ => visit::walk_item(self, item),
                 }
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index 845e4d5e5d0..d4c43456049 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -8,7 +8,7 @@ use thin_vec::ThinVec;
 
 use crate::{DefaultBodyStability, PartialConstStability, PrintAttribute, RustcVersion, Stability};
 
-#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, PrintAttribute)]
 pub enum InlineAttr {
     None,
     Hint,
@@ -130,24 +130,54 @@ impl Deprecation {
     }
 }
 
-/// Represent parsed, *built in*, inert attributes.
+/// Represents 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.
+/// ## Overview
+/// These attributes are markers that guide the compilation process and are never expanded into other code.
+/// They persist throughout the compilation phases, from AST to HIR and beyond.
 ///
-/// 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.
+/// ## Attribute Processing
+/// While attributes are initially parsed by [`rustc_parse`] into [`ast::Attribute`], they still contain raw token streams
+/// because different attributes have different internal structures. This enum represents the final,
+/// fully parsed form of these attributes, where each variant contains contains all the information and
+/// structure relevant for the specific attribute.
 ///
-/// For more docs, look in [`rustc_attr_parsing`].
+/// Some attributes can be applied multiple times to the same item, and they are "collapsed" into a single
+/// semantic attribute. For example:
+/// ```rust
+/// #[repr(C)]
+/// #[repr(packed)]
+/// struct S { }
+/// ```
+/// This is equivalent to `#[repr(C, packed)]` and results in a single [`AttributeKind::Repr`] containing
+/// both `C` and `packed` annotations. This collapsing happens during parsing and is reflected in the
+/// data structures defined in this enum.
 ///
+/// ## Usage
+/// These parsed attributes are used throughout the compiler to:
+/// - Control code generation (e.g., `#[repr]`)
+/// - Mark API stability (`#[stable]`, `#[unstable]`)
+/// - Provide documentation (`#[doc]`)
+/// - Guide compiler behavior (e.g., `#[allow_internal_unstable]`)
+///
+/// ## Note on Attribute Organization
+/// Some attributes like `InlineAttr`, `OptimizeAttr`, and `InstructionSetAttr` are defined separately
+/// from this enum because they are used in specific compiler phases (like code generation) and don't
+/// need to persist throughout the entire compilation process. They are typically processed and
+/// converted into their final form earlier in the compilation pipeline.
+///
+/// For example:
+/// - `InlineAttr` is used during code generation to control function inlining
+/// - `OptimizeAttr` is used to control optimization levels
+/// - `InstructionSetAttr` is used for target-specific code generation
+///
+/// These attributes are handled by their respective compiler passes in the [`rustc_codegen_ssa`] crate
+/// and don't need to be preserved in the same way as the attributes in this enum.
+///
+/// For more details on attribute parsing, see the [`rustc_attr_parsing`] crate.
+///
+/// [`rustc_parse`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_parse/index.html
+/// [`rustc_codegen_ssa`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/index.html
 /// [`rustc_attr_parsing`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html
 #[derive(Clone, Debug, HashStable_Generic, Encodable, Decodable, PrintAttribute)]
 pub enum AttributeKind {
@@ -158,6 +188,9 @@ pub enum AttributeKind {
     /// Represents `#[allow_internal_unstable]`.
     AllowInternalUnstable(ThinVec<(Symbol, Span)>),
 
+    /// Represents `#[rustc_as_ptr]` (used by the `dangling_pointers_from_temporaries` lint).
+    AsPtr(Span),
+
     /// Represents `#[rustc_default_body_unstable]`.
     BodyStability {
         stability: DefaultBodyStability,
@@ -188,6 +221,9 @@ pub enum AttributeKind {
     /// Represents [`#[doc]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html).
     DocComment { style: AttrStyle, kind: CommentKind, span: Span, comment: Symbol },
 
+    /// Represents `#[inline]` and `#[rustc_force_inline]`.
+    Inline(InlineAttr, Span),
+
     /// Represents `#[rustc_macro_transparency]`.
     MacroTransparency(Transparency),
 
diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs
index b0fc19d1cd7..f8355be09ad 100644
--- a/compiler/rustc_attr_data_structures/src/lib.rs
+++ b/compiler/rustc_attr_data_structures/src/lib.rs
@@ -1,3 +1,7 @@
+//! Data structures for representing parsed attributes in the Rust compiler.
+//! For detailed documentation about attribute processing,
+//! see [rustc_attr_parsing](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_attr_parsing/index.html).
+
 // tidy-alphabetical-start
 #![allow(internal_features)]
 #![doc(rust_logo)]
diff --git a/compiler/rustc_attr_data_structures/src/lints.rs b/compiler/rustc_attr_data_structures/src/lints.rs
index 7e3664b2263..e34c54c6d32 100644
--- a/compiler/rustc_attr_data_structures/src/lints.rs
+++ b/compiler/rustc_attr_data_structures/src/lints.rs
@@ -11,4 +11,5 @@ pub struct AttributeLint<Id> {
 #[derive(Clone, Debug, HashStable_Generic)]
 pub enum AttributeLintKind {
     UnusedDuplicate { this: Span, other: Span, warning: bool },
+    IllFormedAttributeInput { suggestions: Vec<String> },
 }
diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl
index c9443feb021..b9b386635f6 100644
--- a/compiler/rustc_attr_parsing/messages.ftl
+++ b/compiler/rustc_attr_parsing/messages.ftl
@@ -23,8 +23,10 @@ attr_parsing_expects_feature_list =
 attr_parsing_expects_features =
     `{$name}` expects feature names
 
-attr_parsing_incorrect_meta_item = expected a quoted string literal
-attr_parsing_incorrect_meta_item_suggestion = consider surrounding this with quotes
+attr_parsing_ill_formed_attribute_input = {$num_suggestions ->
+        [1] attribute must be of the form {$suggestions}
+        *[other] valid forms for the attribute are {$suggestions}
+    }
 
 attr_parsing_incorrect_repr_format_align_one_arg =
     incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
@@ -81,9 +83,6 @@ attr_parsing_missing_note =
 attr_parsing_missing_since =
     missing 'since'
 
-attr_parsing_multiple_item =
-    multiple '{$item}' items
-
 attr_parsing_multiple_stability_levels =
     multiple stability levels
 
@@ -122,10 +121,6 @@ attr_parsing_unsupported_literal_cfg_boolean =
     literal in `cfg` predicate value must be a boolean
 attr_parsing_unsupported_literal_cfg_string =
     literal in `cfg` predicate value must be a string
-attr_parsing_unsupported_literal_deprecated_kv_pair =
-    item in `deprecated` must be a key/value pair
-attr_parsing_unsupported_literal_deprecated_string =
-    literal in `deprecated` value must be a string
 attr_parsing_unsupported_literal_generic =
     unsupported literal
 attr_parsing_unsupported_literal_suggestion =
@@ -136,6 +131,7 @@ attr_parsing_unused_duplicate =
     .suggestion = remove this attribute
     .note = attribute also specified here
     .warn = {-passes_previously_accepted}
+
 attr_parsing_unused_multiple =
     multiple `{$name}` attributes
     .suggestion = remove this attribute
diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
index 81192f902a2..21b01a8d071 100644
--- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs
@@ -1,6 +1,7 @@
 use std::iter;
 
 use rustc_attr_data_structures::AttributeKind;
+use rustc_feature::{AttributeTemplate, template};
 use rustc_span::{Span, Symbol, sym};
 
 use super::{CombineAttributeParser, ConvertFn};
@@ -13,6 +14,7 @@ impl<S: Stage> CombineAttributeParser<S> for AllowInternalUnstableParser {
     const PATH: &[Symbol] = &[sym::allow_internal_unstable];
     type Item = (Symbol, Span);
     const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowInternalUnstable;
+    const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
 
     fn extend<'c>(
         cx: &'c mut AcceptContext<'_, '_, S>,
@@ -29,6 +31,7 @@ impl<S: Stage> CombineAttributeParser<S> for AllowConstFnUnstableParser {
     const PATH: &[Symbol] = &[sym::rustc_allow_const_fn_unstable];
     type Item = Symbol;
     const CONVERT: ConvertFn<Self::Item> = AttributeKind::AllowConstFnUnstable;
+    const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ...");
 
     fn extend<'c>(
         cx: &'c mut AcceptContext<'_, '_, S>,
diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs
index afd3c012f05..c911908dfb3 100644
--- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs
@@ -1,4 +1,5 @@
 use rustc_attr_data_structures::AttributeKind;
+use rustc_feature::template;
 use rustc_span::{Span, Symbol, sym};
 use thin_vec::ThinVec;
 
@@ -13,37 +14,33 @@ pub(crate) struct ConfusablesParser {
 }
 
 impl<S: Stage> AttributeParser<S> for ConfusablesParser {
-    const ATTRIBUTES: AcceptMapping<Self, S> = &[(&[sym::rustc_confusables], |this, cx, args| {
-        let Some(list) = args.list() else {
-            // FIXME(jdonszelmann): error when not a list? Bring validation code here.
-            //       NOTE: currently subsequent attributes are silently ignored using
-            //       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 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;
+    const ATTRIBUTES: AcceptMapping<Self, S> = &[(
+        &[sym::rustc_confusables],
+        template!(List: r#""name1", "name2", ..."#),
+        |this, cx, args| {
+            let Some(list) = args.list() else {
+                cx.expected_list(cx.attr_span);
+                return;
             };
 
-            this.confusables.push(lit.symbol);
-        }
+            if list.is_empty() {
+                cx.emit_err(session_diagnostics::EmptyConfusables { span: cx.attr_span });
+            }
+
+            for param in list.mixed() {
+                let span = param.span();
+
+                let Some(lit) = param.lit().and_then(|i| i.value_str()) else {
+                    cx.expected_string_literal(span, param.lit());
+                    continue;
+                };
+
+                this.confusables.push(lit);
+            }
 
-        this.first_span.get_or_insert(cx.attr_span);
-    })];
+            this.first_span.get_or_insert(cx.attr_span);
+        },
+    )];
 
     fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         if self.confusables.is_empty() {
diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
index 1faee41c2a9..702ad66f578 100644
--- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
@@ -1,4 +1,5 @@
 use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation};
+use rustc_feature::{AttributeTemplate, template};
 use rustc_span::{Span, Symbol, sym};
 
 use super::util::parse_version;
@@ -6,7 +7,6 @@ use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
 use crate::context::{AcceptContext, Stage};
 use crate::parser::ArgParser;
 use crate::session_diagnostics;
-use crate::session_diagnostics::UnsupportedLiteralReason;
 
 pub(crate) struct DeprecationParser;
 
@@ -18,25 +18,18 @@ fn get<S: Stage>(
     item: &Option<Symbol>,
 ) -> Option<Symbol> {
     if item.is_some() {
-        cx.emit_err(session_diagnostics::MultipleItem { span: param_span, item: name.to_string() });
+        cx.duplicate_key(param_span, name);
         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),
-            });
+            cx.expected_string_literal(v.value_span, Some(&v.value_as_lit()));
             None
         }
     } else {
-        // FIXME(jdonszelmann): suggestion?
-        cx.emit_err(session_diagnostics::IncorrectMetaItem { span: param_span, suggestion: None });
+        cx.expected_name_value(param_span, Some(name));
         None
     }
 }
@@ -45,6 +38,11 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
     const PATH: &[Symbol] = &[sym::deprecated];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const TEMPLATE: AttributeTemplate = template!(
+        Word,
+        List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#,
+        NameValueStr: "reason"
+    );
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let features = cx.features();
@@ -55,57 +53,60 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
 
         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 None;
-                };
+        match args {
+            ArgParser::NoArgs => {
+                // ok
+            }
+            ArgParser::List(list) => {
+                for param in list.mixed() {
+                    let Some(param) = param.meta_item() else {
+                        cx.unexpected_literal(param.span());
+                        return None;
+                    };
 
-                let ident_name = param.path().word_sym();
+                    let ident_name = param.path().word_sym();
 
-                match ident_name {
-                    Some(name @ sym::since) => {
-                        since = Some(get(cx, name, param_span, param.args(), &since)?);
-                    }
-                    Some(name @ sym::note) => {
-                        note = Some(get(cx, name, param_span, param.args(), &note)?);
-                    }
-                    Some(name @ sym::suggestion) => {
-                        if !features.deprecated_suggestion() {
-                            cx.emit_err(session_diagnostics::DeprecatedItemSuggestion {
-                                span: param_span,
-                                is_nightly: cx.sess().is_nightly_build(),
-                                details: (),
-                            });
+                    match ident_name {
+                        Some(name @ sym::since) => {
+                            since = Some(get(cx, name, param.span(), param.args(), &since)?);
+                        }
+                        Some(name @ sym::note) => {
+                            note = Some(get(cx, name, param.span(), param.args(), &note)?);
                         }
+                        Some(name @ sym::suggestion) => {
+                            if !features.deprecated_suggestion() {
+                                cx.emit_err(session_diagnostics::DeprecatedItemSuggestion {
+                                    span: param.span(),
+                                    is_nightly: cx.sess().is_nightly_build(),
+                                    details: (),
+                                });
+                            }
 
-                        suggestion = Some(get(cx, name, param_span, param.args(), &suggestion)?);
-                    }
-                    _ => {
-                        cx.emit_err(session_diagnostics::UnknownMetaItem {
-                            span: param_span,
-                            item: param.path().to_string(),
-                            expected: if features.deprecated_suggestion() {
-                                &["since", "note", "suggestion"]
-                            } else {
-                                &["since", "note"]
-                            },
-                        });
-                        return None;
+                            suggestion =
+                                Some(get(cx, name, param.span(), param.args(), &suggestion)?);
+                        }
+                        _ => {
+                            cx.unknown_key(
+                                param.span(),
+                                param.path().to_string(),
+                                if features.deprecated_suggestion() {
+                                    &["since", "note", "suggestion"]
+                                } else {
+                                    &["since", "note"]
+                                },
+                            );
+                            return None;
+                        }
                     }
                 }
             }
+            ArgParser::NameValue(v) => {
+                let Some(value) = v.value_as_str() else {
+                    cx.expected_string_literal(v.value_span, Some(v.value_as_lit()));
+                    return None;
+                };
+                note = Some(value);
+            }
         }
 
         let since = if let Some(since) = since {
diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs
index c7f82082c2e..25efc3ae49b 100644
--- a/compiler/rustc_attr_parsing/src/attributes/inline.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs
@@ -29,7 +29,7 @@ impl<S: Stage> SingleAttributeParser<S> for InlineParser {
                     return None;
                 };
 
-                match l.meta_item().and_then(|i| i.word_without_args().map(|i| i.name)) {
+                match l.meta_item().and_then(|i| i.path().word_sym()) {
                     Some(sym::always) => {
                         Some(AttributeKind::Inline(InlineAttr::Always, cx.attr_span))
                     }
@@ -63,7 +63,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
     const TEMPLATE: AttributeTemplate = template!(Word, List: "reason", NameValueStr: "reason");
 
-    fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
         let reason = match args {
             ArgParser::NoArgs => None,
             ArgParser::List(list) => {
@@ -73,7 +73,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
                 };
 
                 let Some(reason) = l.lit().and_then(|i| i.kind.str()) else {
-                    cx.expected_string_literal(l.span());
+                    cx.expected_string_literal(l.span(), l.lit());
                     return None;
                 };
 
@@ -81,7 +81,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
             }
             ArgParser::NameValue(v) => {
                 let Some(reason) = v.value_as_str() else {
-                    cx.expected_string_literal(v.value_span);
+                    cx.expected_string_literal(v.value_span, Some(v.value_as_lit()));
                     return None;
                 };
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
new file mode 100644
index 00000000000..d4c846de56e
--- /dev/null
+++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
@@ -0,0 +1,21 @@
+use rustc_attr_data_structures::AttributeKind;
+use rustc_feature::{AttributeTemplate, template};
+use rustc_span::{Symbol, sym};
+
+use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
+use crate::context::{AcceptContext, Stage};
+use crate::parser::ArgParser;
+
+pub(crate) struct AsPtrParser;
+
+impl<S: Stage> SingleAttributeParser<S> for AsPtrParser {
+    const PATH: &[Symbol] = &[sym::rustc_as_ptr];
+    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
+    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const TEMPLATE: AttributeTemplate = template!(Word);
+
+    fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
+        // FIXME: check that there's no args (this is currently checked elsewhere)
+        Some(AttributeKind::AsPtr(cx.attr_span))
+    }
+}
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index caf55e6685e..fa2a6087506 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -18,6 +18,7 @@ use std::marker::PhantomData;
 
 use rustc_attr_data_structures::AttributeKind;
 use rustc_attr_data_structures::lints::AttributeLintKind;
+use rustc_feature::AttributeTemplate;
 use rustc_span::{Span, Symbol};
 use thin_vec::ThinVec;
 
@@ -29,13 +30,15 @@ pub(crate) mod allow_unstable;
 pub(crate) mod cfg;
 pub(crate) mod confusables;
 pub(crate) mod deprecation;
+pub(crate) mod inline;
+pub(crate) mod lint_helpers;
 pub(crate) mod repr;
 pub(crate) mod stability;
 pub(crate) mod transparency;
 pub(crate) mod util;
 
 type AcceptFn<T, S> = for<'sess> fn(&mut T, &mut AcceptContext<'_, 'sess, S>, &ArgParser<'_>);
-type AcceptMapping<T, S> = &'static [(&'static [Symbol], AcceptFn<T, S>)];
+type AcceptMapping<T, S> = &'static [(&'static [Symbol], AttributeTemplate, AcceptFn<T, S>)];
 
 /// An [`AttributeParser`] is a type which searches for syntactic attributes.
 ///
@@ -87,6 +90,9 @@ pub(crate) trait SingleAttributeParser<S: Stage>: 'static {
     const ATTRIBUTE_ORDER: AttributeOrder;
     const ON_DUPLICATE: OnDuplicate<S>;
 
+    /// The template this attribute parser should implement. Used for diagnostics.
+    const TEMPLATE: AttributeTemplate;
+
     /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`]
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind>;
 }
@@ -103,8 +109,10 @@ impl<T: SingleAttributeParser<S>, S: Stage> Default for Single<T, S> {
 }
 
 impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S> {
-    const ATTRIBUTES: AcceptMapping<Self, S> =
-        &[(T::PATH, |group: &mut Single<T, S>, cx, args| {
+    const ATTRIBUTES: AcceptMapping<Self, S> = &[(
+        T::PATH,
+        <T as SingleAttributeParser<S>>::TEMPLATE,
+        |group: &mut Single<T, S>, cx, args| {
             if let Some(pa) = T::convert(cx, args) {
                 match T::ATTRIBUTE_ORDER {
                     // keep the first and report immediately. ignore this attribute
@@ -125,7 +133,8 @@ impl<T: SingleAttributeParser<S>, S: Stage> AttributeParser<S> for Single<T, S>
 
                 group.1 = Some((pa, cx.attr_span));
             }
-        })];
+        },
+    )];
 
     fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         Some(self.1?.0)
@@ -222,6 +231,9 @@ pub(crate) trait CombineAttributeParser<S: Stage>: 'static {
     type Item;
     const CONVERT: ConvertFn<Self::Item>;
 
+    /// The template this attribute parser should implement. Used for diagnostics.
+    const TEMPLATE: AttributeTemplate;
+
     /// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`]
     fn extend<'c>(
         cx: &'c mut AcceptContext<'_, '_, S>,
@@ -241,8 +253,11 @@ impl<T: CombineAttributeParser<S>, S: Stage> Default for Combine<T, S> {
 }
 
 impl<T: CombineAttributeParser<S>, S: Stage> AttributeParser<S> for Combine<T, S> {
-    const ATTRIBUTES: AcceptMapping<Self, S> =
-        &[(T::PATH, |group: &mut Combine<T, S>, cx, args| group.1.extend(T::extend(cx, args)))];
+    const ATTRIBUTES: AcceptMapping<Self, S> = &[(
+        T::PATH,
+        <T as CombineAttributeParser<S>>::TEMPLATE,
+        |group: &mut Combine<T, S>, cx, args| group.1.extend(T::extend(cx, args)),
+    )];
 
     fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         if self.1.is_empty() { None } else { Some(T::CONVERT(self.1)) }
diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs
index 753b2366b41..ae9e7871874 100644
--- a/compiler/rustc_attr_parsing/src/attributes/repr.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs
@@ -1,6 +1,7 @@
 use rustc_abi::Align;
 use rustc_ast::{IntTy, LitIntType, LitKind, UintTy};
 use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr};
+use rustc_feature::{AttributeTemplate, template};
 use rustc_span::{DUMMY_SP, Span, Symbol, sym};
 
 use super::{CombineAttributeParser, ConvertFn};
@@ -23,6 +24,8 @@ impl<S: Stage> CombineAttributeParser<S> for ReprParser {
     type Item = (ReprAttr, Span);
     const PATH: &[Symbol] = &[sym::repr];
     const CONVERT: ConvertFn<Self::Item> = AttributeKind::Repr;
+    // FIXME(jdonszelmann): never used
+    const TEMPLATE: AttributeTemplate = template!(List: "C");
 
     fn extend<'c>(
         cx: &'c mut AcceptContext<'_, '_, S>,
@@ -31,6 +34,7 @@ impl<S: Stage> CombineAttributeParser<S> for ReprParser {
         let mut reprs = Vec::new();
 
         let Some(list) = args.list() else {
+            cx.expected_list(cx.attr_span);
             return reprs;
         };
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs
index 6589a51db2b..6871ff4ec9f 100644
--- a/compiler/rustc_attr_parsing/src/attributes/stability.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs
@@ -5,7 +5,8 @@ use rustc_attr_data_structures::{
     StableSince, UnstableReason, VERSION_PLACEHOLDER,
 };
 use rustc_errors::ErrorGuaranteed;
-use rustc_span::{Span, Symbol, sym};
+use rustc_feature::{AttributeTemplate, template};
+use rustc_span::{Ident, Span, Symbol, sym};
 
 use super::util::parse_version;
 use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser};
@@ -43,26 +44,39 @@ impl StabilityParser {
 
 impl<S: Stage> AttributeParser<S> for StabilityParser {
     const ATTRIBUTES: AcceptMapping<Self, S> = &[
-        (&[sym::stable], |this, cx, args| {
-            reject_outside_std!(cx);
-            if !this.check_duplicate(cx)
-                && 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 = args.name_value().and_then(|i| i.value_as_str())
-        }),
+        (
+            &[sym::stable],
+            template!(List: r#"feature = "name", since = "version""#),
+            |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],
+            template!(List: r#"feature = "name", reason = "...", issue = "N""#),
+            |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],
+            template!(NameValueStr: "deprecation message"),
+            |this, cx, args| {
+                reject_outside_std!(cx);
+                this.allowed_through_unstable_modules =
+                    args.name_value().and_then(|i| i.value_as_str())
+            },
+        ),
     ];
 
     fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
@@ -96,8 +110,10 @@ pub(crate) struct BodyStabilityParser {
 }
 
 impl<S: Stage> AttributeParser<S> for BodyStabilityParser {
-    const ATTRIBUTES: AcceptMapping<Self, S> =
-        &[(&[sym::rustc_default_body_unstable], |this, cx, args| {
+    const ATTRIBUTES: AcceptMapping<Self, S> = &[(
+        &[sym::rustc_default_body_unstable],
+        template!(List: r#"feature = "name", reason = "...", issue = "N""#),
+        |this, cx, args| {
             reject_outside_std!(cx);
             if this.stability.is_some() {
                 cx.dcx()
@@ -105,7 +121,8 @@ impl<S: Stage> AttributeParser<S> for BodyStabilityParser {
             } else if let Some((feature, level)) = parse_unstability(cx, args) {
                 this.stability = Some((DefaultBodyStability { level, feature }, cx.attr_span));
             }
-        })];
+        },
+    )];
 
     fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
         let (stability, span) = self.stability?;
@@ -120,6 +137,7 @@ impl<S: Stage> SingleAttributeParser<S> for ConstStabilityIndirectParser {
     const PATH: &[Symbol] = &[sym::rustc_const_stable_indirect];
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Ignore;
+    const TEMPLATE: AttributeTemplate = template!(Word);
 
     fn convert(_cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
         Some(AttributeKind::ConstStabilityIndirect)
@@ -146,7 +164,7 @@ impl ConstStabilityParser {
 
 impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
     const ATTRIBUTES: AcceptMapping<Self, S> = &[
-        (&[sym::rustc_const_stable], |this, cx, args| {
+        (&[sym::rustc_const_stable], template!(List: r#"feature = "name""#), |this, cx, args| {
             reject_outside_std!(cx);
 
             if !this.check_duplicate(cx)
@@ -158,7 +176,7 @@ impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
                 ));
             }
         }),
-        (&[sym::rustc_const_unstable], |this, cx, args| {
+        (&[sym::rustc_const_unstable], template!(List: r#"feature = "name""#), |this, cx, args| {
             reject_outside_std!(cx);
             if !this.check_duplicate(cx)
                 && let Some((feature, level)) = parse_unstability(cx, args)
@@ -169,7 +187,7 @@ impl<S: Stage> AttributeParser<S> for ConstStabilityParser {
                 ));
             }
         }),
-        (&[sym::rustc_promotable], |this, cx, _| {
+        (&[sym::rustc_promotable], template!(Word), |this, cx, _| {
             reject_outside_std!(cx);
             this.promotable = true;
         }),
@@ -199,12 +217,10 @@ fn insert_value_into_option_or_error<S: Stage>(
     cx: &AcceptContext<'_, '_, S>,
     param: &MetaItemParser<'_>,
     item: &mut Option<Symbol>,
+    name: Ident,
 ) -> Option<()> {
     if item.is_some() {
-        cx.emit_err(session_diagnostics::MultipleItem {
-            span: param.span(),
-            item: param.path().to_string(),
-        });
+        cx.duplicate_key(name.span, name.name);
         None
     } else if let Some(v) = param.args().name_value()
         && let Some(s) = v.value_as_str()
@@ -212,10 +228,7 @@ fn insert_value_into_option_or_error<S: Stage>(
         *item = Some(s);
         Some(())
     } else {
-        cx.emit_err(session_diagnostics::IncorrectMetaItem {
-            span: param.span(),
-            suggestion: None,
-        });
+        cx.expected_name_value(param.span(), Some(name.name));
         None
     }
 }
@@ -241,9 +254,14 @@ pub(crate) fn parse_stability<S: Stage>(
             return None;
         };
 
-        match param.path().word_sym() {
-            Some(sym::feature) => insert_value_into_option_or_error(cx, &param, &mut feature)?,
-            Some(sym::since) => insert_value_into_option_or_error(cx, &param, &mut since)?,
+        let word = param.path().word();
+        match word.map(|i| i.name) {
+            Some(sym::feature) => {
+                insert_value_into_option_or_error(cx, &param, &mut feature, word.unwrap())?
+            }
+            Some(sym::since) => {
+                insert_value_into_option_or_error(cx, &param, &mut since, word.unwrap())?
+            }
             _ => {
                 cx.emit_err(session_diagnostics::UnknownMetaItem {
                     span: param_span,
@@ -310,11 +328,16 @@ pub(crate) fn parse_unstability<S: Stage>(
             return None;
         };
 
-        match param.path().word_sym() {
-            Some(sym::feature) => insert_value_into_option_or_error(cx, &param, &mut feature)?,
-            Some(sym::reason) => insert_value_into_option_or_error(cx, &param, &mut reason)?,
+        let word = param.path().word();
+        match word.map(|i| i.name) {
+            Some(sym::feature) => {
+                insert_value_into_option_or_error(cx, &param, &mut feature, word.unwrap())?
+            }
+            Some(sym::reason) => {
+                insert_value_into_option_or_error(cx, &param, &mut reason, word.unwrap())?
+            }
             Some(sym::issue) => {
-                insert_value_into_option_or_error(cx, &param, &mut issue)?;
+                insert_value_into_option_or_error(cx, &param, &mut issue, word.unwrap())?;
 
                 // These unwraps are safe because `insert_value_into_option_or_error` ensures the meta item
                 // is a name/value pair string literal.
@@ -344,9 +367,11 @@ pub(crate) fn parse_unstability<S: Stage>(
                 is_soft = true;
             }
             Some(sym::implied_by) => {
-                insert_value_into_option_or_error(cx, &param, &mut implied_by)?
+                insert_value_into_option_or_error(cx, &param, &mut implied_by, word.unwrap())?
+            }
+            Some(sym::old_name) => {
+                insert_value_into_option_or_error(cx, &param, &mut old_name, word.unwrap())?
             }
-            Some(sym::old_name) => insert_value_into_option_or_error(cx, &param, &mut old_name)?,
             _ => {
                 cx.emit_err(session_diagnostics::UnknownMetaItem {
                     span: param.span(),
diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs
index 16ad9d03e50..ce5ceb9139a 100644
--- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs
@@ -1,4 +1,5 @@
 use rustc_attr_data_structures::AttributeKind;
+use rustc_feature::{AttributeTemplate, template};
 use rustc_span::hygiene::Transparency;
 use rustc_span::{Symbol, sym};
 
@@ -17,14 +18,23 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Custom(|cx, used, unused| {
         cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes");
     });
+    const TEMPLATE: AttributeTemplate =
+        template!(NameValueStr: "transparent|semitransparent|opaque");
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
-        match args.name_value().and_then(|nv| nv.value_as_str()) {
+        let Some(nv) = args.name_value() else {
+            cx.expected_name_value(cx.attr_span, None);
+            return None;
+        };
+        match nv.value_as_str() {
             Some(sym::transparent) => Some(Transparency::Transparent),
             Some(sym::semiopaque | sym::semitransparent) => Some(Transparency::SemiOpaque),
             Some(sym::opaque) => Some(Transparency::Opaque),
-            Some(other) => {
-                cx.dcx().span_err(cx.attr_span, format!("unknown macro transparency: `{other}`"));
+            Some(_) => {
+                cx.expected_specific_argument_strings(
+                    nv.value_span,
+                    vec!["transparent", "semitransparent", "opaque"],
+                );
                 None
             }
             None => None,
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index 47f72232828..51c1760da30 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -5,12 +5,11 @@ use std::ops::{Deref, DerefMut};
 use std::sync::LazyLock;
 
 use private::Sealed;
-use rustc_ast as ast;
-use rustc_ast::NodeId;
+use rustc_ast::{self as ast, MetaItemLit, NodeId};
 use rustc_attr_data_structures::AttributeKind;
 use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind};
 use rustc_errors::{DiagCtxtHandle, Diagnostic};
-use rustc_feature::Features;
+use rustc_feature::{AttributeTemplate, Features};
 use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId};
 use rustc_session::Session;
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
@@ -18,6 +17,8 @@ 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::inline::{InlineParser, RustcForceInlineParser};
+use crate::attributes::lint_helpers::AsPtrParser;
 use crate::attributes::repr::ReprParser;
 use crate::attributes::stability::{
     BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
@@ -25,11 +26,12 @@ use crate::attributes::stability::{
 use crate::attributes::transparency::TransparencyParser;
 use crate::attributes::{AttributeParser as _, Combine, Single};
 use crate::parser::{ArgParser, MetaItemParser};
+use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem};
 
 macro_rules! group_type {
     ($stage: ty) => {
          LazyLock<(
-            BTreeMap<&'static [Symbol], Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $stage>, &ArgParser<'a>) + Send + Sync>>,
+            BTreeMap<&'static [Symbol], Vec<(AttributeTemplate, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $stage>, &ArgParser<'a>) + Send + Sync>)>>,
             Vec<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $stage>) -> Option<AttributeKind>>>
         )>
     };
@@ -58,7 +60,7 @@ macro_rules! attribute_parsers {
         @[$ty: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
     ) => {
         pub(crate) static $name: group_type!($ty) = LazyLock::new(|| {
-            let mut accepts = BTreeMap::<_, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $ty>, &ArgParser<'a>) + Send + Sync>>::new();
+            let mut accepts = BTreeMap::<_, Vec<(AttributeTemplate, Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, $ty>, &ArgParser<'a>) + Send + Sync>)>>::new();
             let mut finalizes = Vec::<Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, $ty>) -> Option<AttributeKind>>>::new();
             $(
                 {
@@ -66,13 +68,12 @@ macro_rules! attribute_parsers {
                         static STATE_OBJECT: RefCell<$names> = RefCell::new(<$names>::default());
                     };
 
-                    for (k, v) in <$names>::ATTRIBUTES {
-                        let old = accepts.insert(*k, Box::new(|cx, args| {
+                    for (path, template, accept_fn) in <$names>::ATTRIBUTES {
+                        accepts.entry(*path).or_default().push((*template, Box::new(|cx, args| {
                             STATE_OBJECT.with_borrow_mut(|s| {
-                                v(s, cx, args)
+                                accept_fn(s, cx, args)
                             })
-                        }));
-                        assert!(old.is_none());
+                        })));
                     }
 
                     finalizes.push(Box::new(|cx| {
@@ -102,8 +103,11 @@ attribute_parsers!(
         // tidy-alphabetical-end
 
         // tidy-alphabetical-start
+        Single<AsPtrParser>,
         Single<ConstStabilityIndirectParser>,
         Single<DeprecationParser>,
+        Single<InlineParser>,
+        Single<RustcForceInlineParser>,
         Single<TransparencyParser>,
         // tidy-alphabetical-end
     ];
@@ -163,6 +167,14 @@ pub(crate) struct AcceptContext<'f, 'sess, S: Stage> {
     pub(crate) finalize_cx: FinalizeContext<'f, 'sess, S>,
     /// The span of the attribute currently being parsed
     pub(crate) attr_span: Span,
+
+    /// The expected structure of the attribute.
+    ///
+    /// Used in reporting errors to give a hint to users what the attribute *should* look like.
+    pub(crate) template: &'f AttributeTemplate,
+
+    /// The name of the attribute we're currently accepting.
+    pub(crate) attr_path: AttrPath,
 }
 
 impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
@@ -170,10 +182,133 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
         S::emit_err(&self.sess, diag)
     }
 
+    /// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
+    /// must be delayed until after HIR is built. This method will take care of the details of
+    /// that.
     pub(crate) fn emit_lint(&mut self, lint: AttributeLintKind, span: Span) {
         let id = self.target_id;
         (self.emit_lint)(AttributeLint { id, span, kind: lint });
     }
+
+    pub(crate) fn unknown_key(
+        &self,
+        span: Span,
+        found: String,
+        options: &'static [&'static str],
+    ) -> ErrorGuaranteed {
+        self.emit_err(UnknownMetaItem { span, item: found, expected: options })
+    }
+
+    /// error that a string literal was expected.
+    /// You can optionally give the literal you did find (which you found not to be a string literal)
+    /// which can make better errors. For example, if the literal was a byte string it will suggest
+    /// removing the `b` prefix.
+    pub(crate) fn expected_string_literal(
+        &self,
+        span: Span,
+        actual_literal: Option<&MetaItemLit>,
+    ) -> ErrorGuaranteed {
+        self.emit_err(AttributeParseError {
+            span,
+            attr_span: self.attr_span,
+            template: self.template.clone(),
+            attribute: self.attr_path.clone(),
+            reason: AttributeParseErrorReason::ExpectedStringLiteral {
+                byte_string: actual_literal.and_then(|i| {
+                    i.kind.is_bytestr().then(|| self.sess().source_map().start_point(i.span))
+                }),
+            },
+        })
+    }
+
+    pub(crate) fn expected_list(&self, span: Span) -> ErrorGuaranteed {
+        self.emit_err(AttributeParseError {
+            span,
+            attr_span: self.attr_span,
+            template: self.template.clone(),
+            attribute: self.attr_path.clone(),
+            reason: AttributeParseErrorReason::ExpectedList,
+        })
+    }
+
+    /// emit an error that a `name = value` pair was expected at this span. The symbol can be given for
+    /// a nicer error message talking about the specific name that was found lacking a value.
+    pub(crate) fn expected_name_value(&self, span: Span, name: Option<Symbol>) -> ErrorGuaranteed {
+        self.emit_err(AttributeParseError {
+            span,
+            attr_span: self.attr_span,
+            template: self.template.clone(),
+            attribute: self.attr_path.clone(),
+            reason: AttributeParseErrorReason::ExpectedNameValue(name),
+        })
+    }
+
+    /// emit an error that a `name = value` pair was found where that name was already seen.
+    pub(crate) fn duplicate_key(&self, span: Span, key: Symbol) -> ErrorGuaranteed {
+        self.emit_err(AttributeParseError {
+            span,
+            attr_span: self.attr_span,
+            template: self.template.clone(),
+            attribute: self.attr_path.clone(),
+            reason: AttributeParseErrorReason::DuplicateKey(key),
+        })
+    }
+
+    /// an error that should be emitted when a [`MetaItemOrLitParser`](crate::parser::MetaItemOrLitParser)
+    /// was expected *not* to be a literal, but instead a meta item.
+    pub(crate) fn unexpected_literal(&self, span: Span) -> ErrorGuaranteed {
+        self.emit_err(AttributeParseError {
+            span,
+            attr_span: self.attr_span,
+            template: self.template.clone(),
+            attribute: self.attr_path.clone(),
+            reason: AttributeParseErrorReason::UnexpectedLiteral,
+        })
+    }
+
+    pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed {
+        self.emit_err(AttributeParseError {
+            span,
+            attr_span: self.attr_span,
+            template: self.template.clone(),
+            attribute: self.attr_path.clone(),
+            reason: AttributeParseErrorReason::ExpectedSingleArgument,
+        })
+    }
+
+    pub(crate) fn expected_specific_argument(
+        &self,
+        span: Span,
+        possibilities: Vec<&'static str>,
+    ) -> ErrorGuaranteed {
+        self.emit_err(AttributeParseError {
+            span,
+            attr_span: self.attr_span,
+            template: self.template.clone(),
+            attribute: self.attr_path.clone(),
+            reason: AttributeParseErrorReason::ExpectedSpecificArgument {
+                possibilities,
+                strings: false,
+            },
+        })
+    }
+
+    pub(crate) fn expected_specific_argument_strings(
+        &self,
+        span: Span,
+        possibilities: Vec<&'static str>,
+    ) -> ErrorGuaranteed {
+        self.emit_err(AttributeParseError {
+            span,
+            attr_span: self.attr_span,
+            template: self.template.clone(),
+            attribute: self.attr_path.clone(),
+            reason: AttributeParseErrorReason::ExpectedSpecificArgument {
+                possibilities,
+                strings: true,
+            },
+        })
+    }
 }
 
 impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> {
@@ -372,18 +507,22 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
                     let args = parser.args();
                     let parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
 
-                    if let Some(accept) = S::parsers().0.get(parts.as_slice()) {
-                        let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
-                            finalize_cx: FinalizeContext {
-                                cx: self,
-                                target_span,
-                                target_id,
-                                emit_lint: &mut emit_lint,
-                            },
-                            attr_span: lower_span(attr.span),
-                        };
-
-                        accept(&mut cx, args)
+                    if let Some(accepts) = S::parsers().0.get(parts.as_slice()) {
+                        for (template, accept) in accepts {
+                            let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
+                                finalize_cx: FinalizeContext {
+                                    cx: self,
+                                    target_span,
+                                    target_id,
+                                    emit_lint: &mut emit_lint,
+                                },
+                                attr_span: lower_span(attr.span),
+                                template,
+                                attr_path: path.get_attribute_path(),
+                            };
+
+                            accept(&mut cx, args)
+                        }
                     } else {
                         // If we're here, we must be compiling a tool attribute... Or someone
                         // forgot to parse their fancy new attribute. Let's warn them in any case.
diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs
index d0d112446b4..fee22293b47 100644
--- a/compiler/rustc_attr_parsing/src/lints.rs
+++ b/compiler/rustc_attr_parsing/src/lints.rs
@@ -1,5 +1,5 @@
 use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind};
-use rustc_errors::LintEmitter;
+use rustc_errors::{DiagArgValue, LintEmitter};
 use rustc_hir::HirId;
 
 use crate::session_diagnostics;
@@ -15,5 +15,18 @@ pub fn emit_attribute_lint<L: LintEmitter>(lint: &AttributeLint<HirId>, lint_emi
                 *span,
                 session_diagnostics::UnusedDuplicate { this, other, warning },
             ),
+        AttributeLintKind::IllFormedAttributeInput { suggestions } => {
+            lint_emitter.emit_node_span_lint(
+                rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT,
+                *id,
+                *span,
+                session_diagnostics::IllFormedAttributeInput {
+                    num_suggestions: suggestions.len(),
+                    suggestions: DiagArgValue::StrListSepByAnd(
+                        suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
+                    ),
+                },
+            );
+        }
     }
 }
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
index 7f847d3dd4c..57ac92a0ca1 100644
--- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs
+++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -2,7 +2,11 @@ use std::num::IntErrorKind;
 
 use rustc_ast as ast;
 use rustc_errors::codes::*;
-use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level};
+use rustc_errors::{
+    Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level,
+};
+use rustc_feature::AttributeTemplate;
+use rustc_hir::AttrPath;
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_span::{Span, Symbol};
 
@@ -12,8 +16,6 @@ pub(crate) enum UnsupportedLiteralReason {
     Generic,
     CfgString,
     CfgBoolean,
-    DeprecatedString,
-    DeprecatedKvPair,
 }
 
 #[derive(Diagnostic)]
@@ -32,37 +34,6 @@ pub(crate) struct InvalidPredicate {
     pub predicate: String,
 }
 
-#[derive(Diagnostic)]
-#[diag(attr_parsing_multiple_item, code = E0538)]
-pub(crate) struct MultipleItem {
-    #[primary_span]
-    pub span: Span,
-
-    pub item: String,
-}
-
-#[derive(Diagnostic)]
-#[diag(attr_parsing_incorrect_meta_item, code = E0539)]
-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
 pub(crate) struct UnknownMetaItem<'a> {
     pub span: Span,
@@ -217,6 +188,7 @@ pub(crate) struct InvalidReprHintNoValue {
 }
 
 /// Error code: E0565
+// FIXME(jdonszelmann): slowly phased out
 pub(crate) struct UnsupportedLiteral {
     pub span: Span,
     pub reason: UnsupportedLiteralReason,
@@ -239,12 +211,6 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral {
                 UnsupportedLiteralReason::CfgBoolean => {
                     fluent::attr_parsing_unsupported_literal_cfg_boolean
                 }
-                UnsupportedLiteralReason::DeprecatedString => {
-                    fluent::attr_parsing_unsupported_literal_deprecated_string
-                }
-                UnsupportedLiteralReason::DeprecatedKvPair => {
-                    fluent::attr_parsing_unsupported_literal_deprecated_kv_pair
-                }
             },
         );
         diag.span(self.span);
@@ -462,6 +428,14 @@ pub(crate) struct UnusedDuplicate {
     pub warning: bool,
 }
 
+// FIXME(jdonszelmann): duplicated in rustc_lints, should be moved here completely.
+#[derive(LintDiagnostic)]
+#[diag(attr_parsing_ill_formed_attribute_input)]
+pub(crate) struct IllFormedAttributeInput {
+    pub num_suggestions: usize,
+    pub suggestions: DiagArgValue,
+}
+
 #[derive(Diagnostic)]
 #[diag(attr_parsing_stability_outside_std, code = E0734)]
 pub(crate) struct StabilityOutsideStd {
@@ -490,3 +464,115 @@ pub(crate) struct UnrecognizedReprHint {
     #[primary_span]
     pub span: Span,
 }
+
+pub(crate) enum AttributeParseErrorReason {
+    ExpectedStringLiteral { byte_string: Option<Span> },
+    ExpectedSingleArgument,
+    ExpectedList,
+    UnexpectedLiteral,
+    ExpectedNameValue(Option<Symbol>),
+    DuplicateKey(Symbol),
+    ExpectedSpecificArgument { possibilities: Vec<&'static str>, strings: bool },
+}
+
+pub(crate) struct AttributeParseError {
+    pub(crate) span: Span,
+    pub(crate) attr_span: Span,
+    pub(crate) template: AttributeTemplate,
+    pub(crate) attribute: AttrPath,
+    pub(crate) reason: AttributeParseErrorReason,
+}
+
+impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
+    fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
+        let name = self.attribute.to_string();
+
+        let mut diag = Diag::new(dcx, level, format!("malformed `{name}` attribute input"));
+        diag.span(self.attr_span);
+        diag.code(E0539);
+        match self.reason {
+            AttributeParseErrorReason::ExpectedStringLiteral { byte_string } => {
+                if let Some(start_point_span) = byte_string {
+                    diag.span_suggestion(
+                        start_point_span,
+                        fluent::attr_parsing_unsupported_literal_suggestion,
+                        "",
+                        Applicability::MaybeIncorrect,
+                    );
+                    diag.note("expected a normal string literal, not a byte string literal");
+
+                    return diag;
+                } else {
+                    diag.span_label(self.span, "expected a string literal here");
+                }
+            }
+            AttributeParseErrorReason::ExpectedSingleArgument => {
+                diag.span_label(self.span, "expected a single argument here");
+                diag.code(E0805);
+            }
+            AttributeParseErrorReason::ExpectedList => {
+                diag.span_label(self.span, "expected this to be a list");
+            }
+            AttributeParseErrorReason::DuplicateKey(key) => {
+                diag.span_label(self.span, format!("found `{key}` used as a key more than once"));
+                diag.code(E0538);
+            }
+            AttributeParseErrorReason::UnexpectedLiteral => {
+                diag.span_label(self.span, format!("didn't expect a literal here"));
+                diag.code(E0565);
+            }
+            AttributeParseErrorReason::ExpectedNameValue(None) => {
+                diag.span_label(
+                    self.span,
+                    format!("expected this to be of the form `{name} = \"...\"`"),
+                );
+            }
+            AttributeParseErrorReason::ExpectedNameValue(Some(name)) => {
+                diag.span_label(
+                    self.span,
+                    format!("expected this to be of the form `{name} = \"...\"`"),
+                );
+            }
+            AttributeParseErrorReason::ExpectedSpecificArgument { possibilities, strings } => {
+                let quote = if strings { '"' } else { '`' };
+                match possibilities.as_slice() {
+                    &[] => {}
+                    &[x] => {
+                        diag.span_label(
+                            self.span,
+                            format!("the only valid argument here is {quote}{x}{quote}"),
+                        );
+                    }
+                    [first, second] => {
+                        diag.span_label(self.span, format!("valid arguments are {quote}{first}{quote} or {quote}{second}{quote}"));
+                    }
+                    [first @ .., second_to_last, last] => {
+                        let mut res = String::new();
+                        for i in first {
+                            res.push_str(&format!("{quote}{i}{quote}, "));
+                        }
+                        res.push_str(&format!(
+                            "{quote}{second_to_last}{quote} or {quote}{last}{quote}"
+                        ));
+
+                        diag.span_label(self.span, format!("valid arguments are {res}"));
+                    }
+                }
+            }
+        }
+
+        let suggestions = self.template.suggestions(false, &name);
+        diag.span_suggestions(
+            self.attr_span,
+            if suggestions.len() == 1 {
+                "must be of the form"
+            } else {
+                "try changing it to one of the following valid forms of the attribute"
+            },
+            suggestions,
+            Applicability::HasPlaceholders,
+        );
+
+        diag
+    }
+}
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index c4b0f503664..095c0df98ac 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -342,10 +342,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
                                 }
                             }
                         } else if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() {
-                            let sp = info
-                                .span
-                                .find_ancestor_in_same_ctxt(local_decl.source_info.span)
-                                .unwrap_or(info.span);
+                            let sp = info.span.find_oldest_ancestor_in_same_ctxt();
                             if info.tail_result_is_ignored {
                                 // #85581: If the first mutable borrow's scope contains
                                 // the second borrow, this suggestion isn't helpful.
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index da01e3e9607..fe44350863c 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -155,7 +155,7 @@ impl CfgEval<'_> {
 
 impl MutVisitor for CfgEval<'_> {
     #[instrument(level = "trace", skip(self))]
-    fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
+    fn visit_expr(&mut self, expr: &mut ast::Expr) {
         self.0.configure_expr(expr, false);
         mut_visit::walk_expr(self, expr);
     }
diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
index 0794192621a..3a20b39798d 100644
--- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs
@@ -1,5 +1,4 @@
 use ast::HasAttrs;
-use ast::ptr::P;
 use rustc_ast::mut_visit::MutVisitor;
 use rustc_ast::visit::BoundKind;
 use rustc_ast::{
@@ -378,11 +377,11 @@ struct TypeSubstitution<'a> {
 }
 
 impl<'a> ast::mut_visit::MutVisitor for TypeSubstitution<'a> {
-    fn visit_ty(&mut self, ty: &mut P<ast::Ty>) {
+    fn visit_ty(&mut self, ty: &mut ast::Ty) {
         if let Some(name) = ty.kind.is_simple_path()
             && name == self.from_name
         {
-            **ty = self.to_ty.clone();
+            *ty = self.to_ty.clone();
             self.rewritten = true;
         } else {
             ast::mut_visit::walk_ty(self, ty);
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index b439fa34f5b..b067578794b 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -118,10 +118,7 @@ pub(crate) fn expand_test_or_bench(
 
     let (item, is_stmt) = match item {
         Annotatable::Item(i) => (i, false),
-        Annotatable::Stmt(stmt) if matches!(stmt.kind, ast::StmtKind::Item(_)) => {
-            // FIXME: Use an 'if let' guard once they are implemented
-            if let ast::StmtKind::Item(i) = stmt.kind { (i, true) } else { unreachable!() }
-        }
+        Annotatable::Stmt(box ast::Stmt { kind: ast::StmtKind::Item(i), .. }) => (i, true),
         other => {
             not_testable_error(cx, attr_sp, None);
             return vec![other];
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs
index 012e4dbc3ec..524ebde1c74 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs
@@ -14,8 +14,14 @@
 #![no_core]
 #![allow(dead_code, internal_features, ambiguous_wide_pointer_comparisons)]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-pub trait Sized {}
+pub trait Sized: MetaSized {}
 
 #[lang = "destruct"]
 pub trait Destruct {}
@@ -24,35 +30,35 @@ pub trait Destruct {}
 pub trait Tuple {}
 
 #[lang = "unsize"]
-pub trait Unsize<T: ?Sized> {}
+pub trait Unsize<T: PointeeSized>: PointeeSized {}
 
 #[lang = "coerce_unsized"]
 pub trait CoerceUnsized<T> {}
 
-impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
-impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
-impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
-impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
+impl<'a, 'b: 'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a U> for &'b T {}
+impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a mut U> for &'a mut T {}
+impl<T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*const U> for *const T {}
+impl<T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*mut U> for *mut T {}
 
 #[lang = "dispatch_from_dyn"]
 pub trait DispatchFromDyn<T> {}
 
 // &T -> &U
-impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
+impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<&'a U> for &'a T {}
 // &mut T -> &mut U
-impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
+impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<&'a mut U> for &'a mut T {}
 // *const T -> *const U
-impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
+impl<T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<*const U> for *const T {}
 // *mut T -> *mut U
-impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
-impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T> {}
+impl<T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<*mut U> for *mut T {}
+impl<T: MetaSized + Unsize<U>, U: MetaSized> DispatchFromDyn<Box<U>> for Box<T> {}
 
 #[lang = "legacy_receiver"]
 pub trait LegacyReceiver {}
 
-impl<T: ?Sized> LegacyReceiver for &T {}
-impl<T: ?Sized> LegacyReceiver for &mut T {}
-impl<T: ?Sized> LegacyReceiver for Box<T> {}
+impl<T: PointeeSized> LegacyReceiver for &T {}
+impl<T: PointeeSized> LegacyReceiver for &mut T {}
+impl<T: MetaSized> LegacyReceiver for Box<T> {}
 
 #[lang = "copy"]
 pub trait Copy {}
@@ -74,9 +80,9 @@ impl Copy for isize {}
 impl Copy for f32 {}
 impl Copy for f64 {}
 impl Copy for char {}
-impl<'a, T: ?Sized> Copy for &'a T {}
-impl<T: ?Sized> Copy for *const T {}
-impl<T: ?Sized> Copy for *mut T {}
+impl<'a, T: PointeeSized> Copy for &'a T {}
+impl<T: PointeeSized> Copy for *const T {}
+impl<T: PointeeSized> Copy for *mut T {}
 impl<T: Copy> Copy for Option<T> {}
 
 #[lang = "sync"]
@@ -94,17 +100,17 @@ unsafe impl Sync for i32 {}
 unsafe impl Sync for isize {}
 unsafe impl Sync for char {}
 unsafe impl Sync for f32 {}
-unsafe impl<'a, T: ?Sized> Sync for &'a T {}
+unsafe impl<'a, T: PointeeSized> Sync for &'a T {}
 unsafe impl<T: Sync, const N: usize> Sync for [T; N] {}
 
 #[lang = "freeze"]
 unsafe auto trait Freeze {}
 
-unsafe impl<T: ?Sized> Freeze for PhantomData<T> {}
-unsafe impl<T: ?Sized> Freeze for *const T {}
-unsafe impl<T: ?Sized> Freeze for *mut T {}
-unsafe impl<T: ?Sized> Freeze for &T {}
-unsafe impl<T: ?Sized> Freeze for &mut T {}
+unsafe impl<T: PointeeSized> Freeze for PhantomData<T> {}
+unsafe impl<T: PointeeSized> Freeze for *const T {}
+unsafe impl<T: PointeeSized> Freeze for *mut T {}
+unsafe impl<T: PointeeSized> Freeze for &T {}
+unsafe impl<T: PointeeSized> Freeze for &mut T {}
 
 #[lang = "structural_peq"]
 pub trait StructuralPartialEq {}
@@ -443,7 +449,7 @@ pub enum Option<T> {
 pub use Option::*;
 
 #[lang = "phantom_data"]
-pub struct PhantomData<T: ?Sized>;
+pub struct PhantomData<T: PointeeSized>;
 
 #[lang = "fn_once"]
 #[rustc_paren_sugar]
@@ -564,18 +570,18 @@ pub trait Deref {
 #[repr(transparent)]
 #[rustc_layout_scalar_valid_range_start(1)]
 #[rustc_nonnull_optimization_guaranteed]
-pub struct NonNull<T: ?Sized>(pub *const T);
+pub struct NonNull<T: PointeeSized>(pub *const T);
 
-impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
-impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
+impl<T: PointeeSized, U: PointeeSized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
+impl<T: PointeeSized, U: PointeeSized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
 
-pub struct Unique<T: ?Sized> {
+pub struct Unique<T: PointeeSized> {
     pub pointer: NonNull<T>,
     pub _marker: PhantomData<T>,
 }
 
-impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}
-impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> {}
+impl<T: PointeeSized, U: PointeeSized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}
+impl<T: PointeeSized, U: PointeeSized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> {}
 
 #[lang = "global_alloc_ty"]
 pub struct Global;
diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
index 9a0a5b51039..cd0afee0cfb 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
@@ -40,7 +40,18 @@ fn apply_attrs_to_abi_param(param: AbiParam, arg_attrs: ArgAttributes) -> AbiPar
     }
 }
 
-fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[AbiParam; 2]> {
+fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[(Size, AbiParam); 2]> {
+    if let Some(offset_from_start) = cast.rest_offset {
+        assert!(cast.prefix[1..].iter().all(|p| p.is_none()));
+        assert_eq!(cast.rest.unit.size, cast.rest.total);
+        let first = cast.prefix[0].unwrap();
+        let second = cast.rest.unit;
+        return smallvec![
+            (Size::ZERO, reg_to_abi_param(first)),
+            (offset_from_start, reg_to_abi_param(second))
+        ];
+    }
+
     let (rest_count, rem_bytes) = if cast.rest.unit.size.bytes() == 0 {
         (0, 0)
     } else {
@@ -55,25 +66,32 @@ fn cast_target_to_abi_params(cast: &CastTarget) -> SmallVec<[AbiParam; 2]> {
     // different types in Cranelift IR. Instead a single array of primitive types is used.
 
     // Create list of fields in the main structure
-    let mut args = cast
+    let args = cast
         .prefix
         .iter()
         .flatten()
         .map(|&reg| reg_to_abi_param(reg))
-        .chain((0..rest_count).map(|_| reg_to_abi_param(cast.rest.unit)))
-        .collect::<SmallVec<_>>();
+        .chain((0..rest_count).map(|_| reg_to_abi_param(cast.rest.unit)));
+
+    let mut res = SmallVec::new();
+    let mut offset = Size::ZERO;
+
+    for arg in args {
+        res.push((offset, arg));
+        offset += Size::from_bytes(arg.value_type.bytes());
+    }
 
     // Append final integer
     if rem_bytes != 0 {
         // Only integers can be really split further.
         assert_eq!(cast.rest.unit.kind, RegKind::Integer);
-        args.push(reg_to_abi_param(Reg {
-            kind: RegKind::Integer,
-            size: Size::from_bytes(rem_bytes),
-        }));
+        res.push((
+            offset,
+            reg_to_abi_param(Reg { kind: RegKind::Integer, size: Size::from_bytes(rem_bytes) }),
+        ));
     }
 
-    args
+    res
 }
 
 impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
@@ -104,7 +122,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
             },
             PassMode::Cast { ref cast, pad_i32 } => {
                 assert!(!pad_i32, "padding support not yet implemented");
-                cast_target_to_abi_params(cast)
+                cast_target_to_abi_params(cast).into_iter().map(|(_, param)| param).collect()
             }
             PassMode::Indirect { attrs, meta_attrs: None, on_stack } => {
                 if on_stack {
@@ -160,9 +178,10 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
                 }
                 _ => unreachable!("{:?}", self.layout.backend_repr),
             },
-            PassMode::Cast { ref cast, .. } => {
-                (None, cast_target_to_abi_params(cast).into_iter().collect())
-            }
+            PassMode::Cast { ref cast, .. } => (
+                None,
+                cast_target_to_abi_params(cast).into_iter().map(|(_, param)| param).collect(),
+            ),
             PassMode::Indirect { attrs, meta_attrs: None, on_stack } => {
                 assert!(!on_stack);
                 (
@@ -187,12 +206,14 @@ pub(super) fn to_casted_value<'tcx>(
 ) -> SmallVec<[Value; 2]> {
     let (ptr, meta) = arg.force_stack(fx);
     assert!(meta.is_none());
-    let mut offset = 0;
     cast_target_to_abi_params(cast)
         .into_iter()
-        .map(|param| {
-            let val = ptr.offset_i64(fx, offset).load(fx, param.value_type, MemFlags::new());
-            offset += i64::from(param.value_type.bytes());
+        .map(|(offset, param)| {
+            let val = ptr.offset_i64(fx, offset.bytes() as i64).load(
+                fx,
+                param.value_type,
+                MemFlags::new(),
+            );
             val
         })
         .collect()
@@ -205,7 +226,7 @@ pub(super) fn from_casted_value<'tcx>(
     cast: &CastTarget,
 ) -> CValue<'tcx> {
     let abi_params = cast_target_to_abi_params(cast);
-    let abi_param_size: u32 = abi_params.iter().map(|param| param.value_type.bytes()).sum();
+    let abi_param_size: u32 = abi_params.iter().map(|(_, param)| param.value_type.bytes()).sum();
     let layout_size = u32::try_from(layout.size.bytes()).unwrap();
     let ptr = fx.create_stack_slot(
         // Stack slot size may be bigger for example `[u8; 3]` which is packed into an `i32`.
@@ -214,16 +235,13 @@ pub(super) fn from_casted_value<'tcx>(
         std::cmp::max(abi_param_size, layout_size),
         u32::try_from(layout.align.abi.bytes()).unwrap(),
     );
-    let mut offset = 0;
     let mut block_params_iter = block_params.iter().copied();
-    for param in abi_params {
-        let val = ptr.offset_i64(fx, offset).store(
+    for (offset, _) in abi_params {
+        ptr.offset_i64(fx, offset.bytes() as i64).store(
             fx,
             block_params_iter.next().unwrap(),
             MemFlags::new(),
-        );
-        offset += i64::from(param.value_type.bytes());
-        val
+        )
     }
     assert_eq!(block_params_iter.next(), None, "Leftover block param");
     CValue::by_ref(ptr, layout)
diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs
index aca1f0080ef..9dfb12be243 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core.rs
@@ -19,8 +19,14 @@ unsafe extern "C" fn _Unwind_Resume() {
     intrinsics::unreachable();
 }
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-pub trait Sized {}
+pub trait Sized: MetaSized {}
 
 #[lang = "destruct"]
 pub trait Destruct {}
@@ -29,35 +35,35 @@ pub trait Destruct {}
 pub trait Tuple {}
 
 #[lang = "unsize"]
-pub trait Unsize<T: ?Sized> {}
+pub trait Unsize<T: PointeeSized>: PointeeSized {}
 
 #[lang = "coerce_unsized"]
 pub trait CoerceUnsized<T> {}
 
-impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
-impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
-impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
-impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
+impl<'a, 'b: 'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a U> for &'b T {}
+impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a mut U> for &'a mut T {}
+impl<T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*const U> for *const T {}
+impl<T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*mut U> for *mut T {}
 
 #[lang = "dispatch_from_dyn"]
 pub trait DispatchFromDyn<T> {}
 
 // &T -> &U
-impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
+impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<&'a U> for &'a T {}
 // &mut T -> &mut U
-impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
+impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<&'a mut U> for &'a mut T {}
 // *const T -> *const U
-impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
+impl<T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<*const U> for *const T {}
 // *mut T -> *mut U
-impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
-impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U, ()>> for Box<T, ()> {}
+impl<T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<*mut U> for *mut T {}
+impl<T: MetaSized + Unsize<U>, U: MetaSized> DispatchFromDyn<Box<U, ()>> for Box<T, ()> {}
 
 #[lang = "legacy_receiver"]
 pub trait LegacyReceiver {}
 
-impl<T: ?Sized> LegacyReceiver for &T {}
-impl<T: ?Sized> LegacyReceiver for &mut T {}
-impl<T: ?Sized, A: Allocator> LegacyReceiver for Box<T, A> {}
+impl<T: PointeeSized> LegacyReceiver for &T {}
+impl<T: PointeeSized> LegacyReceiver for &mut T {}
+impl<T: MetaSized> LegacyReceiver for Box<T> {}
 
 #[lang = "receiver"]
 trait Receiver {}
@@ -84,9 +90,9 @@ impl Copy for i128 {}
 impl Copy for f32 {}
 impl Copy for f64 {}
 impl Copy for char {}
-impl<'a, T: ?Sized> Copy for &'a T {}
-impl<T: ?Sized> Copy for *const T {}
-impl<T: ?Sized> Copy for *mut T {}
+impl<'a, T: PointeeSized> Copy for &'a T {}
+impl<T: PointeeSized> Copy for *const T {}
+impl<T: PointeeSized> Copy for *mut T {}
 
 #[lang = "sync"]
 pub unsafe trait Sync {}
@@ -102,17 +108,17 @@ unsafe impl Sync for i16 {}
 unsafe impl Sync for i32 {}
 unsafe impl Sync for isize {}
 unsafe impl Sync for char {}
-unsafe impl<'a, T: ?Sized> Sync for &'a T {}
+unsafe impl<'a, T: PointeeSized> Sync for &'a T {}
 unsafe impl Sync for [u8; 16] {}
 
 #[lang = "freeze"]
 unsafe auto trait Freeze {}
 
-unsafe impl<T: ?Sized> Freeze for PhantomData<T> {}
-unsafe impl<T: ?Sized> Freeze for *const T {}
-unsafe impl<T: ?Sized> Freeze for *mut T {}
-unsafe impl<T: ?Sized> Freeze for &T {}
-unsafe impl<T: ?Sized> Freeze for &mut T {}
+unsafe impl<T: PointeeSized> Freeze for PhantomData<T> {}
+unsafe impl<T: PointeeSized> Freeze for *const T {}
+unsafe impl<T: PointeeSized> Freeze for *mut T {}
+unsafe impl<T: PointeeSized> Freeze for &T {}
+unsafe impl<T: PointeeSized> Freeze for &mut T {}
 
 #[lang = "structural_peq"]
 pub trait StructuralPartialEq {}
@@ -456,7 +462,7 @@ pub enum Option<T> {
 pub use Option::*;
 
 #[lang = "phantom_data"]
-pub struct PhantomData<T: ?Sized>;
+pub struct PhantomData<T: PointeeSized>;
 
 #[lang = "fn_once"]
 #[rustc_paren_sugar]
@@ -576,18 +582,18 @@ impl Allocator for Global {}
 #[repr(transparent)]
 #[rustc_layout_scalar_valid_range_start(1)]
 #[rustc_nonnull_optimization_guaranteed]
-pub struct NonNull<T: ?Sized>(pub *const T);
+pub struct NonNull<T: PointeeSized>(pub *const T);
 
-impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
-impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
+impl<T: PointeeSized, U: PointeeSized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
+impl<T: PointeeSized, U: PointeeSized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
 
-pub struct Unique<T: ?Sized> {
+pub struct Unique<T: PointeeSized> {
     pub pointer: NonNull<T>,
     pub _marker: PhantomData<T>,
 }
 
-impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}
-impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> {}
+impl<T: PointeeSized, U: PointeeSized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}
+impl<T: PointeeSized, U: PointeeSized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> {}
 
 #[lang = "owned_box"]
 pub struct Box<T: ?Sized, A: Allocator = Global>(Unique<T>, A);
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 9e05b8f23aa..c921851b42b 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -626,7 +626,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
                 bx.lifetime_start(llscratch, scratch_size);
 
                 // ... where we first store the value...
-                bx.store(val, llscratch, scratch_align);
+                rustc_codegen_ssa::mir::store_cast(bx, cast, val, llscratch, scratch_align);
 
                 // ... and then memcpy it to the intended destination.
                 bx.memcpy(
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index aba63d75f1d..4b07c8aef91 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -229,7 +229,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
                 let llscratch = bx.alloca(scratch_size, scratch_align);
                 bx.lifetime_start(llscratch, scratch_size);
                 // ...store the value...
-                bx.store(val, llscratch, scratch_align);
+                rustc_codegen_ssa::mir::store_cast(bx, cast, val, llscratch, scratch_align);
                 // ... and then memcpy it to the intended destination.
                 bx.memcpy(
                     dst.val.llval,
diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
index c5c13ac097a..b07d9a5cfca 100644
--- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
+++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
@@ -114,7 +114,7 @@ fn match_args_from_caller_to_enzyme<'ll>(
             let mul = unsafe {
                 llvm::LLVMBuildMul(
                     builder.llbuilder,
-                    cx.get_const_i64(elem_bytes_size),
+                    cx.get_const_int(cx.type_i64(), elem_bytes_size),
                     next_outer_arg,
                     UNNAMED,
                 )
@@ -385,7 +385,7 @@ fn generate_enzyme_call<'ll>(
         if attrs.width > 1 {
             let enzyme_width = cx.create_metadata("enzyme_width".to_string()).unwrap();
             args.push(cx.get_metadata_value(enzyme_width));
-            args.push(cx.get_const_i64(attrs.width as u64));
+            args.push(cx.get_const_int(cx.type_i64(), attrs.width as u64));
         }
 
         let has_sret = has_sret(outer_fn);
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index 3cfa96393e9..ae5add59322 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -99,14 +99,14 @@ impl<'ll, CX: Borrow<SCx<'ll>>> BackendTypes for GenericCx<'ll, CX> {
     type DIVariable = &'ll llvm::debuginfo::DIVariable;
 }
 
-impl<'ll> CodegenCx<'ll, '_> {
+impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
     pub(crate) fn const_array(&self, ty: &'ll Type, elts: &[&'ll Value]) -> &'ll Value {
         let len = u64::try_from(elts.len()).expect("LLVMConstArray2 elements len overflow");
         unsafe { llvm::LLVMConstArray2(ty, elts.as_ptr(), len) }
     }
 
     pub(crate) fn const_bytes(&self, bytes: &[u8]) -> &'ll Value {
-        bytes_in_context(self.llcx, bytes)
+        bytes_in_context(self.llcx(), bytes)
     }
 
     pub(crate) fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value {
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index bff95ea46fa..0324dff6ff2 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -679,11 +679,8 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> {
         llvm::LLVMMetadataAsValue(self.llcx(), metadata)
     }
 
-    // FIXME(autodiff): We should split `ConstCodegenMethods` to pull the reusable parts
-    // onto a trait that is also implemented for GenericCx.
-    pub(crate) fn get_const_i64(&self, n: u64) -> &'ll Value {
-        let ty = unsafe { llvm::LLVMInt64TypeInContext(self.llcx()) };
-        unsafe { llvm::LLVMConstInt(ty, n, llvm::False) }
+    pub(crate) fn get_const_int(&self, ty: &'ll Type, val: u64) -> &'ll Value {
+        unsafe { llvm::LLVMConstInt(ty, val, llvm::False) }
     }
 
     pub(crate) fn get_function(&self, name: &str) -> Option<&'ll Value> {
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 8c52ed6ed12..8882ba359b7 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -69,23 +69,6 @@ pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) {
     }
 }
 
-fn check_link_info_print_request(sess: &Session, crate_types: &[CrateType]) {
-    let print_native_static_libs =
-        sess.opts.prints.iter().any(|p| p.kind == PrintKind::NativeStaticLibs);
-    let has_staticlib = crate_types.iter().any(|ct| *ct == CrateType::Staticlib);
-    if print_native_static_libs {
-        if !has_staticlib {
-            sess.dcx()
-                .warn(format!("cannot output linkage information without staticlib crate-type"));
-            sess.dcx()
-                .note(format!("consider `--crate-type staticlib` to print linkage information"));
-        } else if !sess.opts.output_types.should_link() {
-            sess.dcx()
-                .warn(format!("cannot output linkage information when --emit link is not passed"));
-        }
-    }
-}
-
 /// Performs the linkage portion of the compilation phase. This will generate all
 /// of the requested outputs for this compilation session.
 pub fn link_binary(
@@ -208,8 +191,6 @@ pub fn link_binary(
         }
     }
 
-    check_link_info_print_request(sess, &codegen_results.crate_info.crate_types);
-
     // Remove the temporary object file and metadata if we aren't saving temps.
     sess.time("link_binary_remove_temps", || {
         // If the user requests that temporaries are saved, don't delete any.
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index a16862c41ee..d091c46d9c1 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -379,6 +379,24 @@ pub(super) fn elf_e_flags(architecture: Architecture, sess: &Session) -> u32 {
             };
             e_flags
         }
+        Architecture::PowerPc64 => {
+            const EF_PPC64_ABI_UNKNOWN: u32 = 0;
+            const EF_PPC64_ABI_ELF_V1: u32 = 1;
+            const EF_PPC64_ABI_ELF_V2: u32 = 2;
+
+            match sess.target.options.llvm_abiname.as_ref() {
+                // If the flags do not correctly indicate the ABI,
+                // linkers such as ld.lld assume that the ppc64 object files are always ELFv2
+                // which leads to broken binaries if ELFv1 is used for the object files.
+                "elfv1" => EF_PPC64_ABI_ELF_V1,
+                "elfv2" => EF_PPC64_ABI_ELF_V2,
+                "" if sess.target.options.binary_format.to_object() == BinaryFormat::Elf => {
+                    bug!("No ABI specified for this PPC64 ELF target");
+                }
+                // Fall back
+                _ => EF_PPC64_ABI_UNKNOWN,
+            }
+        }
         _ => 0,
     }
 }
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 0b31fa8fa88..188a9a98ce7 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -4,7 +4,9 @@ use rustc_abi::ExternAbi;
 use rustc_ast::expand::autodiff_attrs::{AutoDiffAttrs, DiffActivity, DiffMode};
 use rustc_ast::{LitKind, MetaItem, MetaItemInner, attr};
 use rustc_attr_data_structures::ReprAttr::ReprAlign;
-use rustc_attr_data_structures::{AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr};
+use rustc_attr_data_structures::{
+    AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, find_attr,
+};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
@@ -21,7 +23,6 @@ use rustc_session::parse::feature_err;
 use rustc_session::{Session, lint};
 use rustc_span::{Ident, Span, sym};
 use rustc_target::spec::SanitizerSet;
-use tracing::debug;
 
 use crate::errors;
 use crate::target_features::{check_target_feature_trait_unsafe, from_target_feature_attr};
@@ -83,7 +84,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
 
     let rust_target_features = tcx.rust_target_features(LOCAL_CRATE);
 
-    let mut inline_span = None;
     let mut link_ordinal_span = None;
     let mut no_sanitize_span = None;
     let mut mixed_export_name_no_mangle_lint_state = MixedExportNameAndNoMangleState::default();
@@ -449,48 +449,14 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
 
     mixed_export_name_no_mangle_lint_state.lint_if_mixed(tcx);
 
-    codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| {
-        if !attr.has_name(sym::inline) {
-            return ia;
-        }
-
-        if attr.is_word() {
-            return InlineAttr::Hint;
-        }
-        let Some(ref items) = attr.meta_item_list() else {
-            return ia;
-        };
-        inline_span = Some(attr.span());
-
-        let [item] = &items[..] else {
-            tcx.dcx().emit_err(errors::ExpectedOneArgument { span: attr.span() });
-            return InlineAttr::None;
-        };
-
-        if item.has_name(sym::always) {
-            InlineAttr::Always
-        } else if item.has_name(sym::never) {
-            InlineAttr::Never
-        } else {
-            tcx.dcx().emit_err(errors::InvalidArgument { span: items[0].span() });
-
-            InlineAttr::None
-        }
-    });
-    codegen_fn_attrs.inline = attrs.iter().fold(codegen_fn_attrs.inline, |ia, attr| {
-        if !attr.has_name(sym::rustc_force_inline) || !tcx.features().rustc_attrs() {
-            return ia;
-        }
-
-        if attr.is_word() {
-            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) }
-        } else {
-            debug!("`rustc_force_inline` not checked by attribute validation");
-            ia
-        }
-    });
+    let inline_span;
+    (codegen_fn_attrs.inline, inline_span) = if let Some((inline_attr, span)) =
+        find_attr!(attrs, AttributeKind::Inline(i, span) => (*i, *span))
+    {
+        (inline_attr, Some(span))
+    } else {
+        (InlineAttr::None, None)
+    };
 
     // naked function MUST NOT be inlined! This attribute is required for the rust compiler itself,
     // but not for the code generation backend because at that point the naked function will just be
@@ -511,7 +477,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
             return OptimizeAttr::Default;
         };
 
-        inline_span = Some(attr.span());
         let [item] = &items[..] else {
             tcx.dcx().emit_err(errors::ExpectedOneArgumentOptimize { span: attr.span() });
             return OptimizeAttr::Default;
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index bac02bdf983..5387b2a7f81 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -209,13 +209,6 @@ pub(crate) struct OutOfRangeInteger {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa_expected_one_argument, code = E0534)]
-pub(crate) struct ExpectedOneArgument {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(codegen_ssa_expected_one_argument, code = E0722)]
 pub(crate) struct ExpectedOneArgumentOptimize {
     #[primary_span]
@@ -223,14 +216,6 @@ pub(crate) struct ExpectedOneArgumentOptimize {
 }
 
 #[derive(Diagnostic)]
-#[diag(codegen_ssa_invalid_argument, code = E0535)]
-#[help]
-pub(crate) struct InvalidArgument {
-    #[primary_span]
-    pub span: Span,
-}
-
-#[derive(Diagnostic)]
 #[diag(codegen_ssa_invalid_argument, code = E0722)]
 pub(crate) struct InvalidArgumentOptimize {
     #[primary_span]
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 43b87171d51..3df97429e09 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -1,6 +1,6 @@
 use std::cmp;
 
-use rustc_abi::{BackendRepr, ExternAbi, HasDataLayout, Reg, Size, WrappingRange};
+use rustc_abi::{Align, BackendRepr, ExternAbi, HasDataLayout, Reg, Size, WrappingRange};
 use rustc_ast as ast;
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
 use rustc_data_structures::packed::Pu128;
@@ -13,7 +13,7 @@ use rustc_middle::{bug, span_bug};
 use rustc_session::config::OptLevel;
 use rustc_span::Span;
 use rustc_span::source_map::Spanned;
-use rustc_target::callconv::{ArgAbi, FnAbi, PassMode};
+use rustc_target::callconv::{ArgAbi, CastTarget, FnAbi, PassMode};
 use tracing::{debug, info};
 
 use super::operand::OperandRef;
@@ -558,8 +558,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     }
                     ZeroSized => bug!("ZST return value shouldn't be in PassMode::Cast"),
                 };
-                let ty = bx.cast_backend_type(cast_ty);
-                bx.load(ty, llslot, self.fn_abi.ret.layout.align.abi)
+                load_cast(bx, cast_ty, llslot, self.fn_abi.ret.layout.align.abi)
             }
         };
         bx.ret(llval);
@@ -1618,8 +1617,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     MemFlags::empty(),
                 );
                 // ...and then load it with the ABI type.
-                let cast_ty = bx.cast_backend_type(cast);
-                llval = bx.load(cast_ty, llscratch, scratch_align);
+                llval = load_cast(bx, cast, llscratch, scratch_align);
                 bx.lifetime_end(llscratch, scratch_size);
             } else {
                 // We can't use `PlaceRef::load` here because the argument
@@ -1969,3 +1967,47 @@ enum ReturnDest<'tcx, V> {
     /// Store a direct return value to an operand local place.
     DirectOperand(mir::Local),
 }
+
+fn load_cast<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
+    bx: &mut Bx,
+    cast: &CastTarget,
+    ptr: Bx::Value,
+    align: Align,
+) -> Bx::Value {
+    let cast_ty = bx.cast_backend_type(cast);
+    if let Some(offset_from_start) = cast.rest_offset {
+        assert!(cast.prefix[1..].iter().all(|p| p.is_none()));
+        assert_eq!(cast.rest.unit.size, cast.rest.total);
+        let first_ty = bx.reg_backend_type(&cast.prefix[0].unwrap());
+        let second_ty = bx.reg_backend_type(&cast.rest.unit);
+        let first = bx.load(first_ty, ptr, align);
+        let second_ptr = bx.inbounds_ptradd(ptr, bx.const_usize(offset_from_start.bytes()));
+        let second = bx.load(second_ty, second_ptr, align.restrict_for_offset(offset_from_start));
+        let res = bx.cx().const_poison(cast_ty);
+        let res = bx.insert_value(res, first, 0);
+        bx.insert_value(res, second, 1)
+    } else {
+        bx.load(cast_ty, ptr, align)
+    }
+}
+
+pub fn store_cast<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
+    bx: &mut Bx,
+    cast: &CastTarget,
+    value: Bx::Value,
+    ptr: Bx::Value,
+    align: Align,
+) {
+    if let Some(offset_from_start) = cast.rest_offset {
+        assert!(cast.prefix[1..].iter().all(|p| p.is_none()));
+        assert_eq!(cast.rest.unit.size, cast.rest.total);
+        assert!(cast.prefix[0].is_some());
+        let first = bx.extract_value(value, 0);
+        let second = bx.extract_value(value, 1);
+        bx.store(first, ptr, align);
+        let second_ptr = bx.inbounds_ptradd(ptr, bx.const_usize(offset_from_start.bytes()));
+        bx.store(second, second_ptr, align.restrict_for_offset(offset_from_start));
+    } else {
+        bx.store(value, ptr, align);
+    };
+}
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 96a04473aba..66c4af4c935 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -26,6 +26,7 @@ pub mod place;
 mod rvalue;
 mod statement;
 
+pub use self::block::store_cast;
 use self::debuginfo::{FunctionDebugContext, PerLocalVarDebugInfo};
 use self::operand::{OperandRef, OperandValue};
 use self::place::PlaceRef;
@@ -259,7 +260,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
                     }
                     PassMode::Cast { ref cast, .. } => {
                         debug!("alloc: {:?} (return place) -> place", local);
-                        let size = cast.size(&start_bx);
+                        let size = cast.size(&start_bx).max(layout.size);
                         return LocalRef::Place(PlaceRef::alloca_size(&mut start_bx, size, layout));
                     }
                     _ => {}
diff --git a/compiler/rustc_data_structures/src/aligned.rs b/compiler/rustc_data_structures/src/aligned.rs
index a636d09fcae..111740e5509 100644
--- a/compiler/rustc_data_structures/src/aligned.rs
+++ b/compiler/rustc_data_structures/src/aligned.rs
@@ -1,5 +1,7 @@
 use std::ptr::Alignment;
 
+use rustc_serialize::PointeeSized;
+
 /// Returns the ABI-required minimum alignment of a type in bytes.
 ///
 /// This is equivalent to [`align_of`], but also works for some unsized
@@ -17,7 +19,7 @@ pub const fn align_of<T: ?Sized + Aligned>() -> Alignment {
 /// example `[T]` has alignment of `T`.
 ///
 /// [`align_of::<Self>()`]: align_of
-pub unsafe trait Aligned {
+pub unsafe trait Aligned: PointeeSized {
     /// Alignment of `Self`.
     const ALIGN: Alignment;
 }
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index eb3817a80a7..0431182e9e2 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -12,6 +12,7 @@
 #![allow(rustc::potential_query_instability)]
 #![cfg_attr(bootstrap, feature(cfg_match))]
 #![cfg_attr(not(bootstrap), feature(cfg_select))]
+#![cfg_attr(not(bootstrap), feature(sized_hierarchy))]
 #![deny(unsafe_op_in_unsafe_fn)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
@@ -43,6 +44,9 @@ use std::fmt;
 pub use atomic_ref::AtomicRef;
 pub use ena::{snapshot_vec, undo_log, unify};
 pub use rustc_index::static_assert_size;
+// re-exported for `rustc_smir`
+// FIXME(sized_hierarchy): remove with `cfg(bootstrap)`, see `rustc_serialize/src/lib.rs`
+pub use rustc_serialize::PointeeSized;
 
 pub mod aligned;
 pub mod base_n;
diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs
index e0df1b232e1..4846bc997f1 100644
--- a/compiler/rustc_data_structures/src/marker.rs
+++ b/compiler/rustc_data_structures/src/marker.rs
@@ -1,5 +1,7 @@
 use std::alloc::Allocator;
 
+use rustc_serialize::PointeeSized;
+
 #[diagnostic::on_unimplemented(message = "`{Self}` doesn't implement `DynSend`. \
             Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Send`")]
 // This is an auto trait for types which can be sent across threads if `sync::is_dyn_thread_safe()`
@@ -15,7 +17,7 @@ pub unsafe auto trait DynSend {}
 pub unsafe auto trait DynSync {}
 
 // Same with `Sync` and `Send`.
-unsafe impl<T: DynSync + ?Sized> DynSend for &T {}
+unsafe impl<T: DynSync + ?Sized + PointeeSized> DynSend for &T {}
 
 macro_rules! impls_dyn_send_neg {
     ($([$t1: ty $(where $($generics1: tt)*)?])*) => {
@@ -27,9 +29,9 @@ macro_rules! impls_dyn_send_neg {
 impls_dyn_send_neg!(
     [std::env::Args]
     [std::env::ArgsOs]
-    [*const T where T: ?Sized]
-    [*mut T where T: ?Sized]
-    [std::ptr::NonNull<T> where T: ?Sized]
+    [*const T where T: ?Sized + PointeeSized]
+    [*mut T where T: ?Sized + PointeeSized]
+    [std::ptr::NonNull<T> where T: ?Sized + PointeeSized]
     [std::rc::Rc<T, A> where T: ?Sized, A: Allocator]
     [std::rc::Weak<T, A> where T: ?Sized, A: Allocator]
     [std::sync::MutexGuard<'_, T> where T: ?Sized]
@@ -100,12 +102,12 @@ macro_rules! impls_dyn_sync_neg {
 impls_dyn_sync_neg!(
     [std::env::Args]
     [std::env::ArgsOs]
-    [*const T where T: ?Sized]
-    [*mut T where T: ?Sized]
+    [*const T where T: ?Sized + PointeeSized]
+    [*mut T where T: ?Sized + PointeeSized]
     [std::cell::Cell<T> where T: ?Sized]
     [std::cell::RefCell<T> where T: ?Sized]
     [std::cell::UnsafeCell<T> where T: ?Sized]
-    [std::ptr::NonNull<T> where T: ?Sized]
+    [std::ptr::NonNull<T> where T: ?Sized + PointeeSized]
     [std::rc::Rc<T, A> where T: ?Sized, A: Allocator]
     [std::rc::Weak<T, A> where T: ?Sized, A: Allocator]
     [std::cell::OnceCell<T> where T]
@@ -175,10 +177,10 @@ impl_dyn_sync!(
     [thin_vec::ThinVec<T> where T: DynSync]
 );
 
-pub fn assert_dyn_sync<T: ?Sized + DynSync>() {}
-pub fn assert_dyn_send<T: ?Sized + DynSend>() {}
-pub fn assert_dyn_send_val<T: ?Sized + DynSend>(_t: &T) {}
-pub fn assert_dyn_send_sync_val<T: ?Sized + DynSync + DynSend>(_t: &T) {}
+pub fn assert_dyn_sync<T: ?Sized + PointeeSized + DynSync>() {}
+pub fn assert_dyn_send<T: ?Sized + PointeeSized + DynSend>() {}
+pub fn assert_dyn_send_val<T: ?Sized + PointeeSized + DynSend>(_t: &T) {}
+pub fn assert_dyn_send_sync_val<T: ?Sized + PointeeSized + DynSync + DynSend>(_t: &T) {}
 
 #[derive(Copy, Clone)]
 pub struct FromDyn<T>(T);
@@ -231,10 +233,10 @@ impl<T> std::ops::DerefMut for FromDyn<T> {
 // an instance of `DynSend` and `DynSync`, since the compiler cannot infer
 // it automatically in some cases. (e.g. Box<dyn Send / Sync>)
 #[derive(Copy, Clone)]
-pub struct IntoDynSyncSend<T: ?Sized>(pub T);
+pub struct IntoDynSyncSend<T: ?Sized + PointeeSized>(pub T);
 
-unsafe impl<T: ?Sized + Send> DynSend for IntoDynSyncSend<T> {}
-unsafe impl<T: ?Sized + Sync> DynSync for IntoDynSyncSend<T> {}
+unsafe impl<T: ?Sized + PointeeSized + Send> DynSend for IntoDynSyncSend<T> {}
+unsafe impl<T: ?Sized + PointeeSized + Sync> DynSync for IntoDynSyncSend<T> {}
 
 impl<T> std::ops::Deref for IntoDynSyncSend<T> {
     type Target = T;
diff --git a/compiler/rustc_error_codes/src/error_codes/E0534.md b/compiler/rustc_error_codes/src/error_codes/E0534.md
index 1ca9411b8d4..023c38c730c 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0534.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0534.md
@@ -1,8 +1,14 @@
+#### Note: this error code is no longer emitted by the compiler
+
+This is because it was too specific to the `inline` attribute.
+Similar diagnostics occur for other attributes too.
+The example here will now emit `E0805`
+
 The `inline` attribute was malformed.
 
 Erroneous code example:
 
-```compile_fail,E0534
+```compile_fail,E0805
 #[inline()] // error: expected one argument
 pub fn something() {}
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0535.md b/compiler/rustc_error_codes/src/error_codes/E0535.md
index 0cf3118b02c..93e2ba53826 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0535.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0535.md
@@ -1,8 +1,13 @@
-An unknown argument was given to the `inline` attribute.
+#### Note: this error code is no longer emitted by the compiler
+
+This is because it was too specific to the `inline` attribute.
+Similar diagnostics occur for other attributes too.
+The example here will now emit `E0539`
+
 
 Erroneous code example:
 
-```compile_fail,E0535
+```compile_fail,E0539
 #[inline(unknown)] // error: invalid argument
 pub fn something() {}
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0539.md b/compiler/rustc_error_codes/src/error_codes/E0539.md
index 6b2e23ba2d8..c76b60ac108 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0539.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0539.md
@@ -24,8 +24,7 @@ struct Stable;
 const fn stable_fn() {}
 ```
 
-Meta items are the key-value pairs inside of an attribute.
-To fix these issues you need to give required key-value pairs.
+To fix the above example, you can write the following:
 
 ```
 #![feature(staged_api)]
@@ -49,3 +48,29 @@ struct Stable;
 #[rustc_const_stable(feature = "stable_fn", since = "1.39.0")] // ok!
 const fn stable_fn() {}
 ```
+
+Several causes of this are,
+an attribute may have expected you to give a list but you gave a
+`name = value` pair:
+
+```compile_fail,E0539
+// wrong, should be `#[repr(C)]`
+#[repr = "C"]
+struct Foo {}
+```
+
+Or a `name = value` pair, but you gave a list:
+
+```compile_fail,E0539
+// wrong, should be `note = "reason"`
+#[deprecated(since = "1.0.0", note("reason"))]
+struct Foo {}
+```
+
+Or it expected some specific word but you gave an unexpected one:
+
+```compile_fail,E0539
+// should be `always` or `never`
+#[inline(maybe_if_you_feel_like_it)]
+fn foo() {}
+```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0565.md b/compiler/rustc_error_codes/src/error_codes/E0565.md
index d5bba941c1d..34152eb7cfe 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0565.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0565.md
@@ -9,10 +9,9 @@ struct Repr {}
 fn main() {}
 ```
 
-Literals in attributes are new and largely unsupported in built-in attributes.
-Work to support literals where appropriate is ongoing. Try using an unquoted
-name instead:
-
+Not all attributes support literals in their input,
+and in some cases they expect an identifier instead.
+That would be the solution in the case of `repr`:
 ```
 #[repr(C)] // ok!
 struct Repr {}
diff --git a/compiler/rustc_error_codes/src/error_codes/E0805.md b/compiler/rustc_error_codes/src/error_codes/E0805.md
new file mode 100644
index 00000000000..b1ed3a11d48
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0805.md
@@ -0,0 +1,26 @@
+An attribute was given an invalid number of arguments
+
+Erroneous code example:
+
+```compile_fail,E0805
+#[inline()] // error! should either have a single argument, or no parentheses
+fn foo() {}
+
+#[inline(always, never)] // error! should have only one argument, not two
+fn bar() {}
+```
+
+To fix this, either give the right number of arguments the attribute needs.
+In the case of inline, this could be none at all:
+
+```
+#[inline]
+fn foo() {}
+```
+
+or only one:
+
+```
+#[inline(always)]
+fn foo() {}
+```
diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs
index 2488d870899..6f5e4829802 100644
--- a/compiler/rustc_error_codes/src/lib.rs
+++ b/compiler/rustc_error_codes/src/lib.rs
@@ -547,6 +547,7 @@ E0801: 0801,
 E0802: 0802,
 E0803: 0803,
 E0804: 0804,
+E0805: 0805,
         );
     )
 }
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 311dadb53c4..7a29f8c9fbd 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -35,6 +35,7 @@ use crate::base::ast::MetaItemInner;
 use crate::errors;
 use crate::expand::{self, AstFragment, Invocation};
 use crate::module::DirOwnership;
+use crate::stats::MacroStat;
 
 // When adding new variants, make sure to
 // adjust the `visit_*` / `flat_map_*` calls in `InvocationCollector`
@@ -1191,7 +1192,7 @@ pub struct ExtCtxt<'a> {
     /// not to expand it again.
     pub(super) expanded_inert_attrs: MarkedAttrs,
     /// `-Zmacro-stats` data.
-    pub macro_stats: FxHashMap<(Symbol, MacroKind), crate::stats::MacroStat>, // njn: quals
+    pub macro_stats: FxHashMap<(Symbol, MacroKind), MacroStat>,
 }
 
 impl<'a> ExtCtxt<'a> {
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 3cfeb01ea47..9fd524ef45c 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1768,7 +1768,7 @@ impl InvocationCollectorNode for ast::Crate {
     }
 }
 
-impl InvocationCollectorNode for P<ast::Ty> {
+impl InvocationCollectorNode for ast::Ty {
     type OutputTy = P<ast::Ty>;
     const KIND: AstFragmentKind = AstFragmentKind::Ty;
     fn to_annotatable(self) -> Annotatable {
@@ -1791,7 +1791,7 @@ impl InvocationCollectorNode for P<ast::Ty> {
     }
 }
 
-impl InvocationCollectorNode for P<ast::Pat> {
+impl InvocationCollectorNode for ast::Pat {
     type OutputTy = P<ast::Pat>;
     const KIND: AstFragmentKind = AstFragmentKind::Pat;
     fn to_annotatable(self) -> Annotatable {
@@ -1814,11 +1814,11 @@ impl InvocationCollectorNode for P<ast::Pat> {
     }
 }
 
-impl InvocationCollectorNode for P<ast::Expr> {
+impl InvocationCollectorNode for ast::Expr {
     type OutputTy = P<ast::Expr>;
     const KIND: AstFragmentKind = AstFragmentKind::Expr;
     fn to_annotatable(self) -> Annotatable {
-        Annotatable::Expr(self)
+        Annotatable::Expr(P(self))
     }
     fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy {
         fragment.make_expr()
@@ -1955,29 +1955,29 @@ impl DummyAstNode for ast::Crate {
     }
 }
 
-impl DummyAstNode for P<ast::Ty> {
+impl DummyAstNode for ast::Ty {
     fn dummy() -> Self {
-        P(ast::Ty {
+        ast::Ty {
             id: DUMMY_NODE_ID,
             kind: TyKind::Dummy,
             span: Default::default(),
             tokens: Default::default(),
-        })
+        }
     }
 }
 
-impl DummyAstNode for P<ast::Pat> {
+impl DummyAstNode for ast::Pat {
     fn dummy() -> Self {
-        P(ast::Pat {
+        ast::Pat {
             id: DUMMY_NODE_ID,
             kind: PatKind::Wild,
             span: Default::default(),
             tokens: Default::default(),
-        })
+        }
     }
 }
 
-impl DummyAstNode for P<ast::Expr> {
+impl DummyAstNode for ast::Expr {
     fn dummy() -> Self {
         ast::Expr::dummy()
     }
@@ -1985,7 +1985,7 @@ impl DummyAstNode for P<ast::Expr> {
 
 impl DummyAstNode for AstNodeWrapper<P<ast::Expr>, MethodReceiverTag> {
     fn dummy() -> Self {
-        AstNodeWrapper::new(ast::Expr::dummy(), MethodReceiverTag)
+        AstNodeWrapper::new(P(ast::Expr::dummy()), MethodReceiverTag)
     }
 }
 
@@ -2272,7 +2272,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
         }
     }
 
-    fn visit_node<Node: InvocationCollectorNode<OutputTy = Node> + DummyAstNode>(
+    fn visit_node<Node: InvocationCollectorNode<OutputTy: Into<Node>> + DummyAstNode>(
         &mut self,
         node: &mut Node,
     ) {
@@ -2297,6 +2297,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                         *node = self
                             .collect_attr((attr, pos, derives), n.to_annotatable(), Node::KIND)
                             .make_ast::<Node>()
+                            .into()
                     }
                 },
                 None if node.is_mac_call() => {
@@ -2304,7 +2305,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                     let (mac, attrs, _) = n.take_mac_call();
                     self.check_attributes(&attrs, &mac);
 
-                    *node = self.collect_bang(mac, Node::KIND).make_ast::<Node>()
+                    *node = self.collect_bang(mac, Node::KIND).make_ast::<Node>().into()
                 }
                 None if node.delegation().is_some() => unreachable!(),
                 None => {
@@ -2414,15 +2415,15 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
         self.visit_node(node)
     }
 
-    fn visit_ty(&mut self, node: &mut P<ast::Ty>) {
+    fn visit_ty(&mut self, node: &mut ast::Ty) {
         self.visit_node(node)
     }
 
-    fn visit_pat(&mut self, node: &mut P<ast::Pat>) {
+    fn visit_pat(&mut self, node: &mut ast::Pat) {
         self.visit_node(node)
     }
 
-    fn visit_expr(&mut self, node: &mut P<ast::Expr>) {
+    fn visit_expr(&mut self, node: &mut ast::Expr) {
         // FIXME: Feature gating is performed inconsistently between `Expr` and `OptExpr`.
         if let Some(attr) = node.attrs.first() {
             self.cfg().maybe_emit_expr_attr_err(attr);
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index 3dcb20c8c76..2c486a02bdf 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -332,9 +332,9 @@ impl MutVisitor for PlaceholderExpander {
         }
     }
 
-    fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {
+    fn visit_expr(&mut self, expr: &mut ast::Expr) {
         match expr.kind {
-            ast::ExprKind::MacCall(_) => *expr = self.remove(expr.id).make_expr(),
+            ast::ExprKind::MacCall(_) => *expr = *self.remove(expr.id).make_expr(),
             _ => walk_expr(self, expr),
         }
     }
@@ -399,16 +399,16 @@ impl MutVisitor for PlaceholderExpander {
         stmts
     }
 
-    fn visit_pat(&mut self, pat: &mut P<ast::Pat>) {
+    fn visit_pat(&mut self, pat: &mut ast::Pat) {
         match pat.kind {
-            ast::PatKind::MacCall(_) => *pat = self.remove(pat.id).make_pat(),
+            ast::PatKind::MacCall(_) => *pat = *self.remove(pat.id).make_pat(),
             _ => walk_pat(self, pat),
         }
     }
 
-    fn visit_ty(&mut self, ty: &mut P<ast::Ty>) {
+    fn visit_ty(&mut self, ty: &mut ast::Ty) {
         match ty.kind {
-            ast::TyKind::MacCall(_) => *ty = self.remove(ty.id).make_ty(),
+            ast::TyKind::MacCall(_) => *ty = *self.remove(ty.id).make_ty(),
             _ => walk_ty(self, ty),
         }
     }
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 73a21789c5d..b5218ec267c 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -111,6 +111,7 @@ pub enum AttributeGate {
     Ungated,
 }
 
+// FIXME(jdonszelmann): move to rustc_attr_data_structures
 /// A template that the attribute input must match.
 /// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now.
 #[derive(Clone, Copy, Default)]
@@ -127,6 +128,26 @@ pub struct AttributeTemplate {
     pub name_value_str: Option<&'static str>,
 }
 
+impl AttributeTemplate {
+    pub fn suggestions(&self, inner: bool, name: impl std::fmt::Display) -> Vec<String> {
+        let mut suggestions = vec![];
+        let inner = if inner { "!" } else { "" };
+        if self.word {
+            suggestions.push(format!("#{inner}[{name}]"));
+        }
+        if let Some(descr) = self.list {
+            suggestions.push(format!("#{inner}[{name}({descr})]"));
+        }
+        suggestions.extend(self.one_of.iter().map(|&word| format!("#{inner}[{name}({word})]")));
+        if let Some(descr) = self.name_value_str {
+            suggestions.push(format!("#{inner}[{name} = \"{descr}\"]"));
+        }
+        suggestions.sort();
+
+        suggestions
+    }
+}
+
 /// How to handle multiple duplicate attributes on the same item.
 #[derive(Clone, Copy, Default)]
 pub enum AttributeDuplicates {
@@ -181,20 +202,21 @@ pub enum AttributeDuplicates {
 /// A convenience macro for constructing attribute templates.
 /// E.g., `template!(Word, List: "description")` means that the attribute
 /// supports forms `#[attr]` and `#[attr(description)]`.
+#[macro_export]
 macro_rules! template {
-    (Word) => { template!(@ true, None, &[], None) };
-    (List: $descr: expr) => { template!(@ false, Some($descr), &[], None) };
-    (OneOf: $one_of: expr) => { template!(@ false, None, $one_of, None) };
-    (NameValueStr: $descr: expr) => { template!(@ false, None, &[], Some($descr)) };
-    (Word, List: $descr: expr) => { template!(@ true, Some($descr), &[], None) };
-    (Word, NameValueStr: $descr: expr) => { template!(@ true, None, &[], Some($descr)) };
+    (Word) => { $crate::template!(@ true, None, &[], None) };
+    (List: $descr: expr) => { $crate::template!(@ false, Some($descr), &[], None) };
+    (OneOf: $one_of: expr) => { $crate::template!(@ false, None, $one_of, None) };
+    (NameValueStr: $descr: expr) => { $crate::template!(@ false, None, &[], Some($descr)) };
+    (Word, List: $descr: expr) => { $crate::template!(@ true, Some($descr), &[], None) };
+    (Word, NameValueStr: $descr: expr) => { $crate::template!(@ true, None, &[], Some($descr)) };
     (List: $descr1: expr, NameValueStr: $descr2: expr) => {
-        template!(@ false, Some($descr1), &[], Some($descr2))
+        $crate::template!(@ false, Some($descr1), &[], Some($descr2))
     };
     (Word, List: $descr1: expr, NameValueStr: $descr2: expr) => {
-        template!(@ true, Some($descr1), &[], Some($descr2))
+        $crate::template!(@ true, Some($descr1), &[], Some($descr2))
     };
-    (@ $word: expr, $list: expr, $one_of: expr, $name_value_str: expr) => { AttributeTemplate {
+    (@ $word: expr, $list: expr, $one_of: expr, $name_value_str: expr) => { $crate::AttributeTemplate {
         word: $word, list: $list, one_of: $one_of, name_value_str: $name_value_str
     } };
 }
@@ -887,7 +909,7 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
         rustc_legacy_const_generics, Normal, template!(List: "N"), ErrorFollowing,
         EncodeCrossCrate::Yes,
     ),
-    // Do not const-check this function's body. It will always get replaced during CTFE.
+    // Do not const-check this function's body. It will always get replaced during CTFE via `hook_special_const_fn`.
     rustc_attr!(
         rustc_do_not_const_check, Normal, template!(Word), WarnFollowing,
         EncodeCrossCrate::Yes, "`#[rustc_do_not_const_check]` skips const-check for this function's body",
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index bd6ea850147..5e42b919f9d 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -237,6 +237,8 @@ declare_features! (
     (internal, profiler_runtime, "1.18.0", None),
     /// Allows using `rustc_*` attributes (RFC 572).
     (internal, rustc_attrs, "1.0.0", None),
+    /// Introduces a hierarchy of `Sized` traits (RFC 3729).
+    (unstable, sized_hierarchy, "CURRENT_RUSTC_VERSION", None),
     /// Allows using the `#[stable]` and `#[unstable]` attributes.
     (internal, staged_api, "1.0.0", None),
     /// Added for testing unstable lints; perma-unstable.
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 21d36ed54cd..3a08e5ae336 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -165,6 +165,8 @@ pub fn extract(attrs: &[impl AttributeExt]) -> Option<(Symbol, Span)> {
 language_item_table! {
 //  Variant name,            Name,                     Getter method name,         Target                  Generic requirements;
     Sized,                   sym::sized,               sized_trait,                Target::Trait,          GenericRequirement::Exact(0);
+    MetaSized,               sym::meta_sized,          meta_sized_trait,           Target::Trait,          GenericRequirement::Exact(0);
+    PointeeSized,            sym::pointee_sized,       pointee_sized_trait,        Target::Trait,          GenericRequirement::Exact(0);
     Unsize,                  sym::unsize,              unsize_trait,               Target::Trait,          GenericRequirement::Minimum(1);
     /// Trait injected by `#[derive(PartialEq)]`, (i.e. "Partial EQ").
     StructuralPeq,           sym::structural_peq,      structural_peq_trait,       Target::Trait,          GenericRequirement::None;
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index c5c7e6b2aa7..5b8aa28102c 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -76,6 +76,7 @@ pub use check::{check_abi, check_abi_fn_ptr, check_custom_abi};
 use rustc_abi::{ExternAbi, VariantIdx};
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err};
+use rustc_hir::LangItem;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
 use rustc_index::bit_set::DenseBitSet;
@@ -331,7 +332,7 @@ fn bounds_from_generic_predicates<'tcx>(
             ty::ClauseKind::Trait(trait_predicate) => {
                 let entry = types.entry(trait_predicate.self_ty()).or_default();
                 let def_id = trait_predicate.def_id();
-                if !tcx.is_default_trait(def_id) {
+                if !tcx.is_default_trait(def_id) && !tcx.is_lang_item(def_id, LangItem::Sized) {
                     // Do not add that restriction to the list if it is a positive requirement.
                     entry.push(trait_predicate.def_id());
                 }
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index b8dc01cbc03..20d0e87b7a7 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1258,6 +1258,11 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) -> Result<(), ErrorGuarant
     debug!(?item.owner_id);
 
     let def_id = item.owner_id.def_id;
+    if tcx.is_lang_item(def_id.into(), LangItem::PointeeSized) {
+        // `PointeeSized` is removed during lowering.
+        return Ok(());
+    }
+
     let trait_def = tcx.trait_def(def_id);
     if trait_def.is_marker
         || matches!(trait_def.specialization_kind, TraitSpecializationKind::Marker)
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 5f1cdeddc19..53c44cdc411 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -44,6 +44,14 @@ fn associated_type_bounds<'tcx>(
             | PredicateFilter::SelfOnly
             | PredicateFilter::SelfTraitThatDefines(_)
             | PredicateFilter::SelfAndAssociatedTypeBounds => {
+                icx.lowerer().add_sizedness_bounds(
+                    &mut bounds,
+                    item_ty,
+                    hir_bounds,
+                    None,
+                    None,
+                    span,
+                );
                 icx.lowerer().add_default_traits(&mut bounds, item_ty, hir_bounds, None, span);
             }
             // `ConstIfConst` is only interested in `~const` bounds.
@@ -333,6 +341,14 @@ fn opaque_type_bounds<'tcx>(
             | PredicateFilter::SelfOnly
             | PredicateFilter::SelfTraitThatDefines(_)
             | PredicateFilter::SelfAndAssociatedTypeBounds => {
+                icx.lowerer().add_sizedness_bounds(
+                    &mut bounds,
+                    item_ty,
+                    hir_bounds,
+                    None,
+                    None,
+                    span,
+                );
                 icx.lowerer().add_default_traits(&mut bounds, item_ty, hir_bounds, None, span);
             }
             //`ConstIfConst` is only interested in `~const` bounds.
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index ce0f83d0ec2..c337765c5fe 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -162,7 +162,6 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                         .map(|t| ty::Binder::dummy(t.instantiate_identity()));
                 }
             }
-
             ItemKind::Trait(_, _, _, _, self_bounds, ..)
             | ItemKind::TraitAlias(_, _, self_bounds) => {
                 is_trait = Some((self_bounds, item.span));
@@ -183,21 +182,29 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
     // and the explicit where-clauses, but to get the full set of predicates
     // on a trait we must also consider the bounds that follow the trait's name,
     // like `trait Foo: A + B + C`.
-    if let Some(self_bounds) = is_trait {
+    if let Some((self_bounds, span)) = is_trait {
         let mut bounds = Vec::new();
         icx.lowerer().lower_bounds(
             tcx.types.self_param,
-            self_bounds.0,
+            self_bounds,
             &mut bounds,
             ty::List::empty(),
             PredicateFilter::All,
         );
+        icx.lowerer().add_sizedness_bounds(
+            &mut bounds,
+            tcx.types.self_param,
+            self_bounds,
+            None,
+            Some(def_id),
+            span,
+        );
         icx.lowerer().add_default_super_traits(
             def_id,
             &mut bounds,
-            self_bounds.0,
+            self_bounds,
             hir_generics,
-            self_bounds.1,
+            span,
         );
         predicates.extend(bounds);
     }
@@ -224,6 +231,14 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
                 let param_ty = icx.lowerer().lower_ty_param(param.hir_id);
                 let mut bounds = Vec::new();
                 // Implicit bounds are added to type params unless a `?Trait` bound is found
+                icx.lowerer().add_sizedness_bounds(
+                    &mut bounds,
+                    param_ty,
+                    &[],
+                    Some((param.def_id, hir_generics.predicates)),
+                    None,
+                    param.span,
+                );
                 icx.lowerer().add_default_traits(
                     &mut bounds,
                     param_ty,
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index 106420faa4c..ea1dfdfd806 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -4,15 +4,15 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::codes::*;
 use rustc_errors::struct_span_code_err;
 use rustc_hir as hir;
-use rustc_hir::AmbigArg;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::{AmbigArg, LangItem, PolyTraitRef};
 use rustc_middle::bug;
 use rustc_middle::ty::{
     self as ty, IsSuggestable, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
     TypeVisitor, Upcast,
 };
-use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
+use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw};
 use rustc_trait_selection::traits;
 use smallvec::SmallVec;
 use tracing::{debug, instrument};
@@ -23,23 +23,213 @@ use crate::hir_ty_lowering::{
     AssocItemQSelf, FeedConstTy, HirTyLowerer, PredicateFilter, RegionInferReason,
 };
 
+#[derive(Debug, Default)]
+struct CollectedBound {
+    /// `Trait`
+    positive: bool,
+    /// `?Trait`
+    maybe: bool,
+    /// `!Trait`
+    negative: bool,
+}
+
+impl CollectedBound {
+    /// Returns `true` if any of `Trait`, `?Trait` or `!Trait` were encountered.
+    fn any(&self) -> bool {
+        self.positive || self.maybe || self.negative
+    }
+}
+
+#[derive(Debug)]
+struct CollectedSizednessBounds {
+    // Collected `Sized` bounds
+    sized: CollectedBound,
+    // Collected `MetaSized` bounds
+    meta_sized: CollectedBound,
+    // Collected `PointeeSized` bounds
+    pointee_sized: CollectedBound,
+}
+
+impl CollectedSizednessBounds {
+    /// Returns `true` if any of `Trait`, `?Trait` or `!Trait` were encountered for `Sized`,
+    /// `MetaSized` or `PointeeSized`.
+    fn any(&self) -> bool {
+        self.sized.any() || self.meta_sized.any() || self.pointee_sized.any()
+    }
+}
+
+fn search_bounds_for<'tcx>(
+    hir_bounds: &'tcx [hir::GenericBound<'tcx>],
+    self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
+    mut f: impl FnMut(&'tcx PolyTraitRef<'tcx>),
+) {
+    let mut search_bounds = |hir_bounds: &'tcx [hir::GenericBound<'tcx>]| {
+        for hir_bound in hir_bounds {
+            let hir::GenericBound::Trait(ptr) = hir_bound else {
+                continue;
+            };
+
+            f(ptr)
+        }
+    };
+
+    search_bounds(hir_bounds);
+    if let Some((self_ty, where_clause)) = self_ty_where_predicates {
+        for clause in where_clause {
+            if let hir::WherePredicateKind::BoundPredicate(pred) = clause.kind
+                && pred.is_param_bound(self_ty.to_def_id())
+            {
+                search_bounds(pred.bounds);
+            }
+        }
+    }
+}
+
+fn collect_unbounds<'tcx>(
+    hir_bounds: &'tcx [hir::GenericBound<'tcx>],
+    self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
+) -> SmallVec<[&'tcx PolyTraitRef<'tcx>; 1]> {
+    let mut unbounds: SmallVec<[_; 1]> = SmallVec::new();
+    search_bounds_for(hir_bounds, self_ty_where_predicates, |ptr| {
+        if matches!(ptr.modifiers.polarity, hir::BoundPolarity::Maybe(_)) {
+            unbounds.push(ptr);
+        }
+    });
+    unbounds
+}
+
+fn collect_bounds<'a, 'tcx>(
+    hir_bounds: &'a [hir::GenericBound<'tcx>],
+    self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
+    target_did: DefId,
+) -> CollectedBound {
+    let mut collect_into = CollectedBound::default();
+    search_bounds_for(hir_bounds, self_ty_where_predicates, |ptr| {
+        if !matches!(ptr.trait_ref.path.res, Res::Def(DefKind::Trait, did) if did == target_did) {
+            return;
+        }
+
+        match ptr.modifiers.polarity {
+            hir::BoundPolarity::Maybe(_) => collect_into.maybe = true,
+            hir::BoundPolarity::Negative(_) => collect_into.negative = true,
+            hir::BoundPolarity::Positive => collect_into.positive = true,
+        }
+    });
+    collect_into
+}
+
+fn collect_sizedness_bounds<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    hir_bounds: &'tcx [hir::GenericBound<'tcx>],
+    self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
+    span: Span,
+) -> CollectedSizednessBounds {
+    let sized_did = tcx.require_lang_item(LangItem::Sized, span);
+    let sized = collect_bounds(hir_bounds, self_ty_where_predicates, sized_did);
+
+    let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span);
+    let meta_sized = collect_bounds(hir_bounds, self_ty_where_predicates, meta_sized_did);
+
+    let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span);
+    let pointee_sized = collect_bounds(hir_bounds, self_ty_where_predicates, pointee_sized_did);
+
+    CollectedSizednessBounds { sized, meta_sized, pointee_sized }
+}
+
+/// Add a trait bound for `did`.
+fn add_trait_bound<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
+    self_ty: Ty<'tcx>,
+    did: DefId,
+    span: Span,
+) {
+    let trait_ref = ty::TraitRef::new(tcx, did, [self_ty]);
+    // Preferable to put sizedness obligations first, since we report better errors for `Sized`
+    // ambiguity.
+    bounds.insert(0, (trait_ref.upcast(tcx), span));
+}
+
 impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
-    pub(crate) fn add_default_traits(
+    /// Skip `PointeeSized` bounds.
+    ///
+    /// `PointeeSized` is a "fake bound" insofar as anywhere a `PointeeSized` bound exists, there
+    /// is actually the absence of any bounds. This avoids limitations around non-global where
+    /// clauses being preferred over item bounds (where `PointeeSized` bounds would be
+    /// proven) - which can result in errors when a `PointeeSized` supertrait/bound/predicate is
+    /// added to some items.
+    pub(crate) fn should_skip_sizedness_bound<'hir>(
+        &self,
+        bound: &'hir hir::GenericBound<'tcx>,
+    ) -> bool {
+        bound
+            .trait_ref()
+            .and_then(|tr| tr.trait_def_id())
+            .map(|did| self.tcx().is_lang_item(did, LangItem::PointeeSized))
+            .unwrap_or(false)
+    }
+
+    /// Adds sizedness bounds to a trait, trait alias, parameter, opaque type or associated type.
+    ///
+    /// - On parameters, opaque type and associated types, add default `Sized` bound if no explicit
+    ///   sizedness bounds are present.
+    /// - On traits and trait aliases, add default `MetaSized` supertrait if no explicit sizedness
+    ///   bounds are present.
+    /// - On parameters, opaque type, associated types and trait aliases, add a `MetaSized` bound if
+    ///   a `?Sized` bound is present.
+    pub(crate) fn add_sizedness_bounds(
         &self,
         bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
         self_ty: Ty<'tcx>,
-        hir_bounds: &[hir::GenericBound<'tcx>],
+        hir_bounds: &'tcx [hir::GenericBound<'tcx>],
         self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
+        trait_did: Option<LocalDefId>,
         span: Span,
     ) {
-        self.add_default_traits_with_filter(
-            bounds,
-            self_ty,
-            hir_bounds,
-            self_ty_where_predicates,
-            span,
-            |_| true,
-        );
+        let tcx = self.tcx();
+
+        let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, span);
+        let pointee_sized_did = tcx.require_lang_item(LangItem::PointeeSized, span);
+
+        // If adding sizedness bounds to a trait, then there are some relevant early exits
+        if let Some(trait_did) = trait_did {
+            let trait_did = trait_did.to_def_id();
+            // Never add a default supertrait to `PointeeSized`.
+            if trait_did == pointee_sized_did {
+                return;
+            }
+            // Don't add default sizedness supertraits to auto traits because it isn't possible to
+            // relax an automatically added supertrait on the defn itself.
+            if tcx.trait_is_auto(trait_did) {
+                return;
+            }
+        } else {
+            // Report invalid unbounds on sizedness-bounded generic parameters.
+            let unbounds = collect_unbounds(hir_bounds, self_ty_where_predicates);
+            self.check_and_report_invalid_unbounds_on_param(unbounds);
+        }
+
+        let collected = collect_sizedness_bounds(tcx, hir_bounds, self_ty_where_predicates, span);
+        if (collected.sized.maybe || collected.sized.negative)
+            && !collected.sized.positive
+            && !collected.meta_sized.any()
+            && !collected.pointee_sized.any()
+        {
+            // `?Sized` is equivalent to `MetaSized` (but only add the bound if there aren't any
+            // other explicit ones) - this can happen for trait aliases as well as bounds.
+            add_trait_bound(tcx, bounds, self_ty, meta_sized_did, span);
+        } else if !collected.any() {
+            if trait_did.is_some() {
+                // If there are no explicit sizedness bounds on a trait then add a default
+                // `MetaSized` supertrait.
+                add_trait_bound(tcx, bounds, self_ty, meta_sized_did, span);
+            } else {
+                // If there are no explicit sizedness bounds on a parameter then add a default
+                // `Sized` bound.
+                let sized_did = tcx.require_lang_item(LangItem::Sized, span);
+                add_trait_bound(tcx, bounds, self_ty, sized_did, span);
+            }
+        }
     }
 
     /// Checks whether `Self: DefaultAutoTrait` bounds should be added on trait super bounds
@@ -146,13 +336,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
 
         if !self.requires_default_supertraits(trait_bounds, trait_generics) {
             let self_ty_where_predicates = (parent, trait_item.generics.predicates);
-            self.add_default_traits_with_filter(
+            self.add_default_traits(
                 bounds,
                 tcx.types.self_param,
                 &[],
                 Some(self_ty_where_predicates),
                 trait_item.span,
-                |tr| tr != hir::LangItem::Sized,
             );
         }
     }
@@ -174,41 +363,37 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         assert!(matches!(self.tcx().def_kind(trait_def_id), DefKind::Trait | DefKind::TraitAlias));
         if self.requires_default_supertraits(hir_bounds, hir_generics) {
             let self_ty_where_predicates = (trait_def_id, hir_generics.predicates);
-            self.add_default_traits_with_filter(
+            self.add_default_traits(
                 bounds,
                 self.tcx().types.self_param,
                 hir_bounds,
                 Some(self_ty_where_predicates),
                 span,
-                |default_trait| default_trait != hir::LangItem::Sized,
             );
         }
     }
 
-    pub(crate) fn add_default_traits_with_filter(
+    pub(crate) fn add_default_traits(
         &self,
         bounds: &mut Vec<(ty::Clause<'tcx>, Span)>,
         self_ty: Ty<'tcx>,
         hir_bounds: &[hir::GenericBound<'tcx>],
         self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
         span: Span,
-        f: impl Fn(hir::LangItem) -> bool,
     ) {
-        self.tcx().default_traits().iter().filter(|&&default_trait| f(default_trait)).for_each(
-            |default_trait| {
-                self.add_default_trait(
-                    *default_trait,
-                    bounds,
-                    self_ty,
-                    hir_bounds,
-                    self_ty_where_predicates,
-                    span,
-                );
-            },
-        );
+        self.tcx().default_traits().iter().for_each(|default_trait| {
+            self.add_default_trait(
+                *default_trait,
+                bounds,
+                self_ty,
+                hir_bounds,
+                self_ty_where_predicates,
+                span,
+            );
+        });
     }
 
-    /// Add a `Sized` or `experimental_default_bounds` bounds to the `bounds` if appropriate.
+    /// Add a `experimental_default_bounds` bound to the `bounds` if appropriate.
     ///
     /// Doesn't add the bound if the HIR bounds contain any of `Trait`, `?Trait` or `!Trait`.
     pub(crate) fn add_default_trait(
@@ -220,7 +405,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
         span: Span,
     ) {
-        let trait_id = self.tcx().lang_items().get(trait_);
+        let tcx = self.tcx();
+        let trait_id = tcx.lang_items().get(trait_);
         if let Some(trait_id) = trait_id
             && self.do_not_provide_default_trait_bound(
                 trait_id,
@@ -228,11 +414,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 self_ty_where_predicates,
             )
         {
-            // There was no `?Trait` or `!Trait` bound;
-            // add `Trait` if it's available.
-            let trait_ref = ty::TraitRef::new(self.tcx(), trait_id, [self_ty]);
-            // Preferable to put this obligation first, since we report better errors for sized ambiguity.
-            bounds.insert(0, (trait_ref.upcast(self.tcx()), span));
+            add_trait_bound(tcx, bounds, self_ty, trait_id, span);
         }
     }
 
@@ -242,90 +424,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         hir_bounds: &'a [hir::GenericBound<'tcx>],
         self_ty_where_predicates: Option<(LocalDefId, &'tcx [hir::WherePredicate<'tcx>])>,
     ) -> bool {
-        let tcx = self.tcx();
-        let mut seen_negative_bound = false;
-        let mut seen_positive_bound = false;
-
-        // Try to find an unbound in bounds.
-        let mut unbounds: SmallVec<[_; 1]> = SmallVec::new();
-        let mut search_bounds = |hir_bounds: &'a [hir::GenericBound<'tcx>]| {
-            for hir_bound in hir_bounds {
-                let hir::GenericBound::Trait(ptr) = hir_bound else {
-                    continue;
-                };
-                match ptr.modifiers.polarity {
-                    hir::BoundPolarity::Maybe(_) => unbounds.push(ptr),
-                    hir::BoundPolarity::Negative(_) => {
-                        if ptr.trait_ref.path.res == Res::Def(DefKind::Trait, trait_def_id) {
-                            seen_negative_bound = true;
-                        }
-                    }
-                    hir::BoundPolarity::Positive => {
-                        if ptr.trait_ref.path.res == Res::Def(DefKind::Trait, trait_def_id) {
-                            seen_positive_bound = true;
-                        }
-                    }
-                }
-            }
-        };
-        search_bounds(hir_bounds);
-        if let Some((self_ty, where_clause)) = self_ty_where_predicates {
-            for clause in where_clause {
-                if let hir::WherePredicateKind::BoundPredicate(pred) = clause.kind
-                    && pred.is_param_bound(self_ty.to_def_id())
-                {
-                    search_bounds(pred.bounds);
-                }
-            }
-        }
-
-        let mut unique_bounds = FxIndexSet::default();
-        let mut seen_repeat = false;
-        for unbound in &unbounds {
-            if let Res::Def(DefKind::Trait, unbound_def_id) = unbound.trait_ref.path.res {
-                seen_repeat |= !unique_bounds.insert(unbound_def_id);
-            }
-        }
-        if unbounds.len() > 1 {
-            let err = errors::MultipleRelaxedDefaultBounds {
-                spans: unbounds.iter().map(|ptr| ptr.span).collect(),
-            };
-            if seen_repeat {
-                self.dcx().emit_err(err);
-            } else if !tcx.features().more_maybe_bounds() {
-                self.tcx().sess.create_feature_err(err, sym::more_maybe_bounds).emit();
-            };
-        }
-
-        let mut seen_unbound = false;
-        for unbound in unbounds {
-            let unbound_def_id = unbound.trait_ref.trait_def_id();
-            if unbound_def_id == Some(trait_def_id) {
-                seen_unbound = true;
-            }
-            let emit_relax_err = || {
-                let unbound_traits = match tcx.sess.opts.unstable_opts.experimental_default_bounds {
-                    true => "`?Sized` and `experimental_default_bounds`",
-                    false => "`?Sized`",
-                };
-                // There was a `?Trait` bound, but it was neither `?Sized` nor `experimental_default_bounds`.
-                self.dcx().span_err(
-                    unbound.span,
-                    format!(
-                        "relaxing a default bound only does something for {}; \
-                    all other traits are not bound by default",
-                        unbound_traits
-                    ),
-                );
-            };
-            match unbound_def_id {
-                Some(def_id) if !tcx.is_default_trait(def_id) => emit_relax_err(),
-                None => emit_relax_err(),
-                _ => {}
-            }
-        }
-
-        !(seen_unbound || seen_negative_bound || seen_positive_bound)
+        let collected = collect_bounds(hir_bounds, self_ty_where_predicates, trait_def_id);
+        !collected.any()
     }
 
     /// Lower HIR bounds into `bounds` given the self type `param_ty` and the overarching late-bound vars if any.
@@ -361,6 +461,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         'tcx: 'hir,
     {
         for hir_bound in hir_bounds {
+            if self.should_skip_sizedness_bound(hir_bound) {
+                continue;
+            }
+
             // In order to avoid cycles, when we're lowering `SelfTraitThatDefines`,
             // we skip over any traits that don't define the given associated type.
             if let PredicateFilter::SelfTraitThatDefines(assoc_ident) = predicate_filter {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index c7cdf1d5bd2..05465b47a26 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -61,14 +61,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
         let ast_bounds: Vec<_> =
             hir_bounds.iter().map(|&trait_ref| hir::GenericBound::Trait(trait_ref)).collect();
 
-        self.add_default_traits_with_filter(
-            &mut user_written_bounds,
-            dummy_self,
-            &ast_bounds,
-            None,
-            span,
-            |tr| tr != hir::LangItem::Sized,
-        );
+        self.add_default_traits(&mut user_written_bounds, dummy_self, &ast_bounds, None, span);
 
         let (elaborated_trait_bounds, elaborated_projection_bounds) =
             traits::expand_trait_aliases(tcx, user_written_bounds.iter().copied());
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index 45fee0fa402..1cda6dff21e 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -8,7 +8,7 @@ use rustc_errors::{
 };
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::{self as hir, HirId};
+use rustc_hir::{self as hir, HirId, LangItem, PolyTraitRef};
 use rustc_middle::bug;
 use rustc_middle::ty::fast_reject::{TreatParams, simplify_type};
 use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
@@ -34,6 +34,57 @@ use crate::fluent_generated as fluent;
 use crate::hir_ty_lowering::{AssocItemQSelf, HirTyLowerer};
 
 impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
+    /// Check for multiple relaxed default bounds and relaxed bounds of non-sizedness traits.
+    pub(crate) fn check_and_report_invalid_unbounds_on_param(
+        &self,
+        unbounds: SmallVec<[&PolyTraitRef<'_>; 1]>,
+    ) {
+        let tcx = self.tcx();
+
+        let sized_did = tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
+
+        let mut unique_bounds = FxIndexSet::default();
+        let mut seen_repeat = false;
+        for unbound in &unbounds {
+            if let Res::Def(DefKind::Trait, unbound_def_id) = unbound.trait_ref.path.res {
+                seen_repeat |= !unique_bounds.insert(unbound_def_id);
+            }
+        }
+
+        if unbounds.len() > 1 {
+            let err = errors::MultipleRelaxedDefaultBounds {
+                spans: unbounds.iter().map(|ptr| ptr.span).collect(),
+            };
+
+            if seen_repeat {
+                tcx.dcx().emit_err(err);
+            } else if !tcx.features().more_maybe_bounds() {
+                tcx.sess.create_feature_err(err, sym::more_maybe_bounds).emit();
+            };
+        }
+
+        for unbound in unbounds {
+            if let Res::Def(DefKind::Trait, did) = unbound.trait_ref.path.res
+                && ((did == sized_did) || tcx.is_default_trait(did))
+            {
+                continue;
+            }
+
+            let unbound_traits = match tcx.sess.opts.unstable_opts.experimental_default_bounds {
+                true => "`?Sized` and `experimental_default_bounds`",
+                false => "`?Sized`",
+            };
+            self.dcx().span_err(
+                unbound.span,
+                format!(
+                    "relaxing a default bound only does something for {}; all other traits are \
+                     not bound by default",
+                    unbound_traits
+                ),
+            );
+        }
+    }
+
     /// On missing type parameters, emit an E0393 error and provide a structured suggestion using
     /// the type parameter's name as a placeholder.
     pub(crate) fn report_missing_type_params(
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index a43449a8f99..2df19cb21d5 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -22,8 +22,9 @@ use rustc_infer::infer::{DefineOpaqueTypes, InferResult};
 use rustc_lint::builtin::SELF_CONSTRUCTOR_FROM_OUTER_ITEM;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
 use rustc_middle::ty::{
-    self, AdtKind, CanonicalUserType, GenericArgsRef, GenericParamDefKind, IsIdentity, Ty, TyCtxt,
-    TypeFoldable, TypeVisitable, TypeVisitableExt, UserArgs, UserSelfTy,
+    self, AdtKind, CanonicalUserType, GenericArgsRef, GenericParamDefKind, IsIdentity,
+    SizedTraitKind, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitableExt, UserArgs,
+    UserSelfTy,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
@@ -439,7 +440,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 || {},
             );
             // Sized types have static alignment, and so do slices.
-            if tail.is_trivially_sized(self.tcx) || matches!(tail.kind(), ty::Slice(..)) {
+            if tail.has_trivial_sizedness(self.tcx, SizedTraitKind::Sized)
+                || matches!(tail.kind(), ty::Slice(..))
+            {
                 // Nothing else is required here.
             } else {
                 // We can't be sure, let's required full `Sized`.
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 46ae4146528..f92f8307808 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -738,7 +738,8 @@ lint_redundant_semicolons =
         [true] semicolons
         *[false] semicolon
     }
-    .suggestion = remove {$multiple ->
+
+lint_redundant_semicolons_suggestion = remove {$multiple_semicolons ->
         [true] these semicolons
         *[false] this semicolon
     }
diff --git a/compiler/rustc_lint/src/dangling.rs b/compiler/rustc_lint/src/dangling.rs
index 91c7922638d..c737919db9c 100644
--- a/compiler/rustc_lint/src/dangling.rs
+++ b/compiler/rustc_lint/src/dangling.rs
@@ -1,4 +1,5 @@
 use rustc_ast::visit::{visit_opt, walk_list};
+use rustc_attr_data_structures::{AttributeKind, find_attr};
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
 use rustc_hir::{Block, Body, Expr, ExprKind, FnDecl, LangItem};
@@ -133,7 +134,7 @@ fn lint_expr(cx: &LateContext<'_>, expr: &Expr<'_>) {
         && let ty = cx.typeck_results().expr_ty(receiver)
         && owns_allocation(cx.tcx, ty)
         && let Some(fn_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
-        && cx.tcx.has_attr(fn_id, sym::rustc_as_ptr)
+        && find_attr!(cx.tcx.get_all_attrs(fn_id), AttributeKind::AsPtr(_))
     {
         // FIXME: use `emit_node_lint` when `#[primary_span]` is added.
         cx.tcx.emit_node_span_lint(
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 3d17dfbc451..ae65cefda77 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -1538,8 +1538,16 @@ pub(crate) struct PassByValueDiag {
 #[diag(lint_redundant_semicolons)]
 pub(crate) struct RedundantSemicolonsDiag {
     pub multiple: bool,
-    #[suggestion(code = "", applicability = "maybe-incorrect")]
-    pub suggestion: Span,
+    #[subdiagnostic]
+    pub suggestion: Option<RedundantSemicolonsSuggestion>,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(lint_redundant_semicolons_suggestion, code = "", applicability = "maybe-incorrect")]
+pub(crate) struct RedundantSemicolonsSuggestion {
+    pub multiple_semicolons: bool,
+    #[primary_span]
+    pub span: Span,
 }
 
 // traits.rs
@@ -2618,6 +2626,7 @@ pub(crate) struct UnusedCrateDependency {
     pub local_crate: Symbol,
 }
 
+// FIXME(jdonszelmann): duplicated in rustc_attr_parsing, should be moved there completely.
 #[derive(LintDiagnostic)]
 #[diag(lint_ill_formed_attribute_input)]
 pub(crate) struct IllFormedAttributeInput {
diff --git a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
index dea7c8ac708..3cc55eaa0f2 100644
--- a/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
+++ b/compiler/rustc_lint/src/multiple_supertrait_upcastable.rs
@@ -46,7 +46,8 @@ impl<'tcx> LateLintPass<'tcx> for MultipleSupertraitUpcastable {
                 .tcx
                 .explicit_super_predicates_of(def_id)
                 .iter_identity_copied()
-                .filter_map(|(pred, _)| pred.as_trait_clause());
+                .filter_map(|(pred, _)| pred.as_trait_clause())
+                .filter(|pred| !cx.tcx.is_lang_item(pred.def_id(), hir::LangItem::MetaSized));
             if direct_super_traits_iter.count() > 1 {
                 cx.emit_span_lint(
                     MULTIPLE_SUPERTRAIT_UPCASTABLE,
diff --git a/compiler/rustc_lint/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs
index b43e4938b73..f6d2fbe4261 100644
--- a/compiler/rustc_lint/src/redundant_semicolon.rs
+++ b/compiler/rustc_lint/src/redundant_semicolon.rs
@@ -2,7 +2,7 @@ use rustc_ast::{Block, StmtKind};
 use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::Span;
 
-use crate::lints::RedundantSemicolonsDiag;
+use crate::lints::{RedundantSemicolonsDiag, RedundantSemicolonsSuggestion};
 use crate::{EarlyContext, EarlyLintPass, LintContext};
 
 declare_lint! {
@@ -44,16 +44,21 @@ impl EarlyLintPass for RedundantSemicolons {
 
 fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, bool)>) {
     if let Some((span, multiple)) = seq.take() {
-        // FIXME: Find a better way of ignoring the trailing
-        // semicolon from macro expansion
         if span == rustc_span::DUMMY_SP {
             return;
         }
 
+        // Ignore redundant semicolons inside macro expansion.(issue #142143)
+        let suggestion = if span.from_expansion() {
+            None
+        } else {
+            Some(RedundantSemicolonsSuggestion { multiple_semicolons: multiple, span })
+        };
+
         cx.emit_span_lint(
             REDUNDANT_SEMICOLONS,
             span,
-            RedundantSemicolonsDiag { multiple, suggestion: span },
+            RedundantSemicolonsDiag { multiple, suggestion },
         );
     }
 }
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 667361b3ca0..6cb1d8c5fc4 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -28,6 +28,7 @@
 #![allow(internal_features)]
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
+#![cfg_attr(not(bootstrap), feature(sized_hierarchy))]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
 #![feature(allocator_api)]
diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs
index 9ed1f10455a..4d914c42cfc 100644
--- a/compiler/rustc_middle/src/query/keys.rs
+++ b/compiler/rustc_middle/src/query/keys.rs
@@ -328,6 +328,14 @@ impl Key for (DefId, SimplifiedType) {
     }
 }
 
+impl Key for (DefId, ty::SizedTraitKind) {
+    type Cache<V> = DefaultCache<Self, V>;
+
+    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+        self.0.default_span(tcx)
+    }
+}
+
 impl<'tcx> Key for GenericArgsRef<'tcx> {
     type Cache<V> = DefaultCache<Self, V>;
 
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 15e8c1ef3cc..930d9fba433 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1,8 +1,64 @@
-//! Defines the various compiler queries.
 //!
-//! For more information on the query system, see
-//! ["Queries: demand-driven compilation"](https://rustc-dev-guide.rust-lang.org/query.html).
-//! This chapter includes instructions for adding new queries.
+//! # The rustc Query System: Query Definitions and Modifiers
+//!
+//! The core processes in rustc are shipped as queries. Each query is a demand-driven function from some key to a value.
+//! The execution result of the function is cached and directly read during the next request, thereby improving compilation efficiency.
+//! Some results are saved locally and directly read during the next compilation, which are core of incremental compilation.
+//!
+//! ## How to Read This Module
+//!
+//! Each `query` block in this file defines a single query, specifying its key and value types, along with various modifiers.
+//! These query definitions are processed by the [`rustc_macros`], which expands them into the necessary boilerplate code
+//! for the query system—including the [`Providers`] struct (a function table for all query implementations, where each field is
+//! a function pointer to the actual provider), caching, and dependency graph integration.
+//! **Note:** The `Providers` struct is not a Rust trait, but a struct generated by the `rustc_macros` to hold all provider functions.
+//! The `rustc_macros` also supports a set of **query modifiers** (see below) that control the behavior of each query.
+//!
+//! The actual provider functions are implemented in various modules and registered into the `Providers` struct
+//! during compiler initialization (see [`rustc_interface::passes::DEFAULT_QUERY_PROVIDERS`]).
+//!
+//! [`rustc_macros`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_macros/index.html
+//! [`rustc_interface::passes::DEFAULT_QUERY_PROVIDERS`]: ../../rustc_interface/passes/static.DEFAULT_QUERY_PROVIDERS.html
+//!
+//! ## Query Modifiers
+//!
+//! Query modifiers are special flags that alter the behavior of a query. They are parsed and processed by the `rustc_macros`
+//! The main modifiers are:
+//!
+//! - `desc { ... }`: Sets the human-readable description for diagnostics and profiling. Required for every query.
+//! - `arena_cache`: Use an arena for in-memory caching of the query result.
+//! - `cache_on_disk_if { ... }`: Cache the query result to disk if the provided block evaluates to true.
+//! - `fatal_cycle`: If a dependency cycle is detected, abort compilation with a fatal error.
+//! - `cycle_delay_bug`: If a dependency cycle is detected, emit a delayed bug instead of aborting immediately.
+//! - `cycle_stash`: If a dependency cycle is detected, stash the error for later handling.
+//! - `no_hash`: Do not hash the query result for incremental compilation; just mark as dirty if recomputed.
+//! - `anon`: Make the query anonymous in the dependency graph (no dep node is created).
+//! - `eval_always`: Always evaluate the query, ignoring its dependencies and cached results.
+//! - `depth_limit`: Impose a recursion depth limit on the query to prevent stack overflows.
+//! - `separate_provide_extern`: Use separate provider functions for local and external crates.
+//! - `feedable`: Allow the query result to be set from another query ("fed" externally).
+//! - `return_result_from_ensure_ok`: When called via `tcx.ensure_ok()`, return `Result<(), ErrorGuaranteed>` instead of `()`.
+//!   If the query needs to be executed and returns an error, the error is returned to the caller.
+//!   Only valid for queries returning `Result<_, ErrorGuaranteed>`.
+//!
+//! For the up-to-date list, see the `QueryModifiers` struct in
+//! [`rustc_macros/src/query.rs`](https://github.com/rust-lang/rust/blob/master/compiler/rustc_macros/src/query.rs)
+//! and for more details in incremental compilation, see the
+//! [Query modifiers in incremental compilation](https://rustc-dev-guide.rust-lang.org/queries/incremental-compilation-in-detail.html#query-modifiers) section of the rustc-dev-guide.
+//!
+//! ## Query Expansion and Code Generation
+//!
+//! The [`rustc_macros::rustc_queries`] macro expands each query definition into:
+//! - A method on [`TyCtxt`] (and [`TyCtxtAt`]) for invoking the query.
+//! - Provider traits and structs for supplying the query's value.
+//! - Caching and dependency graph integration.
+//! - Support for incremental compilation, disk caching, and arena allocation as controlled by the modifiers.
+//!
+//! [`rustc_macros::rustc_queries`]: ../../rustc_macros/macro.rustc_queries.html
+//!
+//! The macro-based approach allows the query system to be highly flexible and maintainable, while minimizing boilerplate.
+//!
+//! For more details, see the [rustc-dev-guide](https://rustc-dev-guide.rust-lang.org/query.html).
 
 #![allow(unused_parens)]
 
@@ -81,8 +137,8 @@ use crate::ty::layout::ValidityRequirement;
 use crate::ty::print::{PrintTraitRefExt, describe_as_module};
 use crate::ty::util::AlwaysRequiresDrop;
 use crate::ty::{
-    self, CrateInherentImpls, GenericArg, GenericArgsRef, PseudoCanonicalInput, Ty, TyCtxt,
-    TyCtxtFeed,
+    self, CrateInherentImpls, GenericArg, GenericArgsRef, PseudoCanonicalInput, SizedTraitKind, Ty,
+    TyCtxt, TyCtxtFeed,
 };
 use crate::{dep_graph, mir, thir};
 
@@ -854,9 +910,10 @@ rustc_queries! {
         cache_on_disk_if { key.is_local() }
         separate_provide_extern
     }
-
-    query adt_sized_constraint(key: DefId) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
-        desc { |tcx| "computing the `Sized` constraint for `{}`", tcx.def_path_str(key) }
+    query adt_sizedness_constraint(
+        key: (DefId, SizedTraitKind)
+    ) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
+        desc { |tcx| "computing the sizedness constraint for `{}`", tcx.def_path_str(key.0) }
     }
 
     query adt_dtorck_constraint(
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index d92b4f9c06b..6d5a3abf665 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -229,8 +229,12 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef<TyCtxt<'tcx>> for AdtDef<'tcx> {
         )
     }
 
-    fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
-        self.sized_constraint(tcx)
+    fn sizedness_constraint(
+        self,
+        tcx: TyCtxt<'tcx>,
+        sizedness: ty::SizedTraitKind,
+    ) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
+        self.sizedness_constraint(tcx, sizedness)
     }
 
     fn is_fundamental(self) -> bool {
@@ -634,10 +638,15 @@ impl<'tcx> AdtDef<'tcx> {
         tcx.adt_async_destructor(self.did())
     }
 
-    /// Returns a type such that `Self: Sized` if and only if that type is `Sized`,
-    /// or `None` if the type is always sized.
-    pub fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
-        if self.is_struct() { tcx.adt_sized_constraint(self.did()) } else { None }
+    /// If this ADT is a struct, returns a type such that `Self: {Meta,Pointee,}Sized` if and only
+    /// if that type is `{Meta,Pointee,}Sized`, or `None` if this ADT is always
+    /// `{Meta,Pointee,}Sized`.
+    pub fn sizedness_constraint(
+        self,
+        tcx: TyCtxt<'tcx>,
+        sizedness: ty::SizedTraitKind,
+    ) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
+        if self.is_struct() { tcx.adt_sizedness_constraint((self.did(), sizedness)) } else { None }
     }
 }
 
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index e0f70737add..3d7965f6cfe 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -13,7 +13,7 @@ use std::marker::DiscriminantKind;
 use rustc_abi::{FieldIdx, VariantIdx};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::LocalDefId;
-use rustc_serialize::{Decodable, Encodable};
+use rustc_serialize::{Decodable, Encodable, PointeeSized};
 use rustc_span::source_map::Spanned;
 use rustc_span::{Span, SpanDecoder, SpanEncoder};
 
@@ -96,7 +96,7 @@ impl<'tcx, E: TyEncoder<'tcx>> EncodableWithShorthand<'tcx, E> for ty::Predicate
 ///
 /// `Decodable` can still be implemented in cases where `Decodable` is required
 /// by a trait bound.
-pub trait RefDecodable<'tcx, D: TyDecoder<'tcx>> {
+pub trait RefDecodable<'tcx, D: TyDecoder<'tcx>>: PointeeSized {
     fn decode(d: &mut D) -> &'tcx Self;
 }
 
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index fe4dd8d080b..f1395c242f2 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -43,6 +43,7 @@ use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 use rustc_query_system::cache::WithDepNode;
 use rustc_query_system::dep_graph::DepNodeIndex;
 use rustc_query_system::ich::StableHashingContext;
+use rustc_serialize::PointeeSized;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
 use rustc_session::config::CrateType;
 use rustc_session::cstore::{CrateStoreDyn, Untracked};
@@ -774,7 +775,9 @@ bidirectional_lang_item_map! {
     FutureOutput,
     Iterator,
     Metadata,
+    MetaSized,
     Option,
+    PointeeSized,
     PointeeTrait,
     Poll,
     Sized,
@@ -1616,16 +1619,17 @@ impl<'tcx> TyCtxt<'tcx> {
         self.reserve_and_set_memory_dedup(alloc, salt)
     }
 
+    /// Traits added on all bounds by default, excluding `Sized` which is treated separately.
     pub fn default_traits(self) -> &'static [rustc_hir::LangItem] {
-        match self.sess.opts.unstable_opts.experimental_default_bounds {
-            true => &[
-                LangItem::Sized,
+        if self.sess.opts.unstable_opts.experimental_default_bounds {
+            &[
                 LangItem::DefaultTrait1,
                 LangItem::DefaultTrait2,
                 LangItem::DefaultTrait3,
                 LangItem::DefaultTrait4,
-            ],
-            false => &[LangItem::Sized],
+            ]
+        } else {
+            &[]
         }
     }
 
@@ -2538,17 +2542,17 @@ impl<'tcx> TyCtxt<'tcx> {
 // this type just holds a pointer to it, but it still effectively owns it. It
 // impls `Borrow` so that it can be looked up using the original
 // (non-arena-memory-owning) types.
-struct InternedInSet<'tcx, T: ?Sized>(&'tcx T);
+struct InternedInSet<'tcx, T: ?Sized + PointeeSized>(&'tcx T);
 
-impl<'tcx, T: 'tcx + ?Sized> Clone for InternedInSet<'tcx, T> {
+impl<'tcx, T: 'tcx + ?Sized + PointeeSized> Clone for InternedInSet<'tcx, T> {
     fn clone(&self) -> Self {
         InternedInSet(self.0)
     }
 }
 
-impl<'tcx, T: 'tcx + ?Sized> Copy for InternedInSet<'tcx, T> {}
+impl<'tcx, T: 'tcx + ?Sized + PointeeSized> Copy for InternedInSet<'tcx, T> {}
 
-impl<'tcx, T: 'tcx + ?Sized> IntoPointer for InternedInSet<'tcx, T> {
+impl<'tcx, T: 'tcx + ?Sized + PointeeSized> IntoPointer for InternedInSet<'tcx, T> {
     fn into_pointer(&self) -> *const () {
         self.0 as *const _ as *const ()
     }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 0402d098822..97408e31854 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -60,6 +60,7 @@ pub use rustc_type_ir::fast_reject::DeepRejectCtxt;
 )]
 use rustc_type_ir::inherent;
 pub use rustc_type_ir::relate::VarianceDiagInfo;
+pub use rustc_type_ir::solve::SizedTraitKind;
 pub use rustc_type_ir::*;
 #[allow(hidden_glob_reexports, unused_imports)]
 use rustc_type_ir::{InferCtxtLike, Interner};
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 673a89a8134..c10277c75a7 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1069,24 +1069,35 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
 
         let mut traits = FxIndexMap::default();
         let mut fn_traits = FxIndexMap::default();
+        let mut lifetimes = SmallVec::<[ty::Region<'tcx>; 1]>::new();
+
         let mut has_sized_bound = false;
         let mut has_negative_sized_bound = false;
-        let mut lifetimes = SmallVec::<[ty::Region<'tcx>; 1]>::new();
+        let mut has_meta_sized_bound = false;
 
         for (predicate, _) in bounds.iter_instantiated_copied(tcx, args) {
             let bound_predicate = predicate.kind();
 
             match bound_predicate.skip_binder() {
                 ty::ClauseKind::Trait(pred) => {
-                    // Don't print `+ Sized`, but rather `+ ?Sized` if absent.
-                    if tcx.is_lang_item(pred.def_id(), LangItem::Sized) {
-                        match pred.polarity {
+                    // With `feature(sized_hierarchy)`, don't print `?Sized` as an alias for
+                    // `MetaSized`, and skip sizedness bounds to be added at the end.
+                    match tcx.as_lang_item(pred.def_id()) {
+                        Some(LangItem::Sized) => match pred.polarity {
                             ty::PredicatePolarity::Positive => {
                                 has_sized_bound = true;
                                 continue;
                             }
                             ty::PredicatePolarity::Negative => has_negative_sized_bound = true,
+                        },
+                        Some(LangItem::MetaSized) => {
+                            has_meta_sized_bound = true;
+                            continue;
+                        }
+                        Some(LangItem::PointeeSized) => {
+                            bug!("`PointeeSized` is removed during lowering");
                         }
+                        _ => (),
                     }
 
                     self.insert_trait_and_projection(
@@ -1255,8 +1266,13 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
             })?;
         }
 
+        let using_sized_hierarchy = self.tcx().features().sized_hierarchy();
         let add_sized = has_sized_bound && (first || has_negative_sized_bound);
-        let add_maybe_sized = !has_sized_bound && !has_negative_sized_bound;
+        let add_maybe_sized =
+            has_meta_sized_bound && !has_negative_sized_bound && !using_sized_hierarchy;
+        // Set `has_pointee_sized_bound` if there were no `Sized` or `MetaSized` bounds.
+        let has_pointee_sized_bound =
+            !has_sized_bound && !has_meta_sized_bound && !has_negative_sized_bound;
         if add_sized || add_maybe_sized {
             if !first {
                 write!(self, " + ")?;
@@ -1265,6 +1281,16 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                 write!(self, "?")?;
             }
             write!(self, "Sized")?;
+        } else if has_meta_sized_bound && using_sized_hierarchy {
+            if !first {
+                write!(self, " + ")?;
+            }
+            write!(self, "MetaSized")?;
+        } else if has_pointee_sized_bound && using_sized_hierarchy {
+            if !first {
+                write!(self, " + ")?;
+            }
+            write!(self, "PointeeSized")?;
         }
 
         if !with_forced_trimmed_paths() {
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index cbf545c01c5..58829f72a72 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -15,6 +15,7 @@ use rustc_hir::def_id::DefId;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, extension};
 use rustc_span::{DUMMY_SP, Span, Symbol, sym};
 use rustc_type_ir::TyKind::*;
+use rustc_type_ir::solve::SizedTraitKind;
 use rustc_type_ir::walk::TypeWalker;
 use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind, TypeVisitableExt, elaborate};
 use tracing::instrument;
@@ -1677,7 +1678,7 @@ impl<'tcx> Ty<'tcx> {
         let Some(pointee_ty) = self.builtin_deref(true) else {
             bug!("Type {self:?} is not a pointer or reference type")
         };
-        if pointee_ty.is_trivially_sized(tcx) {
+        if pointee_ty.has_trivial_sizedness(tcx, SizedTraitKind::Sized) {
             tcx.types.unit
         } else {
             match pointee_ty.ptr_metadata_ty_or_tail(tcx, |x| x) {
@@ -1778,17 +1779,17 @@ impl<'tcx> Ty<'tcx> {
         }
     }
 
-    /// Fast path helper for testing if a type is `Sized`.
+    /// Fast path helper for testing if a type is `Sized` or `MetaSized`.
     ///
-    /// Returning true means the type is known to implement `Sized`. Returning `false` means
-    /// nothing -- could be sized, might not be.
+    /// Returning true means the type is known to implement the sizedness trait. Returning `false`
+    /// means nothing -- could be sized, might not be.
     ///
     /// Note that we could never rely on the fact that a type such as `[_]` is trivially `!Sized`
     /// because we could be in a type environment with a bound such as `[_]: Copy`. A function with
     /// such a bound obviously never can be called, but that doesn't mean it shouldn't typecheck.
     /// This is why this method doesn't return `Option<bool>`.
     #[instrument(skip(tcx), level = "debug")]
-    pub fn is_trivially_sized(self, tcx: TyCtxt<'tcx>) -> bool {
+    pub fn has_trivial_sizedness(self, tcx: TyCtxt<'tcx>, sizedness: SizedTraitKind) -> bool {
         match self.kind() {
             ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
             | ty::Uint(_)
@@ -1811,13 +1812,20 @@ impl<'tcx> Ty<'tcx> {
             | ty::Error(_)
             | ty::Dynamic(_, _, ty::DynStar) => true,
 
-            ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => false,
+            ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) => match sizedness {
+                SizedTraitKind::Sized => false,
+                SizedTraitKind::MetaSized => true,
+            },
+
+            ty::Foreign(..) => match sizedness {
+                SizedTraitKind::Sized | SizedTraitKind::MetaSized => false,
+            },
 
-            ty::Tuple(tys) => tys.last().is_none_or(|ty| ty.is_trivially_sized(tcx)),
+            ty::Tuple(tys) => tys.last().is_none_or(|ty| ty.has_trivial_sizedness(tcx, sizedness)),
 
             ty::Adt(def, args) => def
-                .sized_constraint(tcx)
-                .is_none_or(|ty| ty.instantiate(tcx, args).is_trivially_sized(tcx)),
+                .sizedness_constraint(tcx, sizedness)
+                .is_none_or(|ty| ty.instantiate(tcx, args).has_trivial_sizedness(tcx, sizedness)),
 
             ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) | ty::Bound(..) => false,
 
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 461d92f8006..51f57e71ce9 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -16,6 +16,7 @@ use rustc_index::bit_set::GrowableBitSet;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension};
 use rustc_session::Limit;
 use rustc_span::sym;
+use rustc_type_ir::solve::SizedTraitKind;
 use smallvec::{SmallVec, smallvec};
 use tracing::{debug, instrument};
 
@@ -1132,7 +1133,8 @@ impl<'tcx> Ty<'tcx> {
     /// strange rules like `<T as Foo<'static>>::Bar: Sized` that
     /// actually carry lifetime requirements.
     pub fn is_sized(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool {
-        self.is_trivially_sized(tcx) || tcx.is_sized_raw(typing_env.as_query_input(self))
+        self.has_trivial_sizedness(tcx, SizedTraitKind::Sized)
+            || tcx.is_sized_raw(typing_env.as_query_input(self))
     }
 
     /// Checks whether values of this type `T` implement the `Freeze`
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index 8f88228d9bb..a54e548ad70 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -74,7 +74,11 @@ impl SimplifyCfg {
 }
 
 pub(super) fn simplify_cfg<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-    CfgSimplifier::new(tcx, body).simplify();
+    if CfgSimplifier::new(tcx, body).simplify() {
+        // `simplify` returns that it changed something. We must invalidate the CFG caches as they
+        // are not consistent with the modified CFG any more.
+        body.basic_blocks.invalidate_cfg_cache();
+    }
     remove_dead_blocks(body);
 
     // FIXME: Should probably be moved into some kind of pass manager
@@ -121,12 +125,16 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
         // Preserve `SwitchInt` reads on built and analysis MIR, or if `-Zmir-preserve-ub`.
         let preserve_switch_reads = matches!(body.phase, MirPhase::Built | MirPhase::Analysis(_))
             || tcx.sess.opts.unstable_opts.mir_preserve_ub;
-        let basic_blocks = body.basic_blocks_mut();
+        // Do not clear caches yet. The caller to `simplify` will do it if anything changed.
+        let basic_blocks = body.basic_blocks.as_mut_preserves_cfg();
 
         CfgSimplifier { preserve_switch_reads, basic_blocks, pred_count }
     }
 
-    fn simplify(mut self) {
+    /// Returns whether we actually simplified anything. In that case, the caller *must* invalidate
+    /// the CFG caches of the MIR body.
+    #[must_use]
+    fn simplify(mut self) -> bool {
         self.strip_nops();
 
         // Vec of the blocks that should be merged. We store the indices here, instead of the
@@ -134,6 +142,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
         // We do not push the statements directly into the target block (`bb`) as that is slower
         // due to additional reallocations
         let mut merged_blocks = Vec::new();
+        let mut outer_changed = false;
         loop {
             let mut changed = false;
 
@@ -177,7 +186,11 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
             if !changed {
                 break;
             }
+
+            outer_changed = true;
         }
+
+        outer_changed
     }
 
     /// This function will return `None` if
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index 0c267feefbe..a300558c0c9 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -8,6 +8,7 @@ use std::ops::ControlFlow;
 use derive_where::derive_where;
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
+use rustc_type_ir::solve::SizedTraitKind;
 use rustc_type_ir::{
     self as ty, Interner, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt as _,
     TypeVisitor, TypingMode, Upcast as _, elaborate,
@@ -203,13 +204,15 @@ where
         goal: Goal<I, Self>,
     ) -> Result<Candidate<I>, NoSolution>;
 
-    /// A type is `Sized` if its tail component is `Sized`.
+    /// A type is `Sized` if its tail component is `Sized` and a type is `MetaSized` if its tail
+    /// component is `MetaSized`.
     ///
     /// These components are given by built-in rules from
-    /// [`structural_traits::instantiate_constituent_tys_for_sized_trait`].
-    fn consider_builtin_sized_candidate(
+    /// [`structural_traits::instantiate_constituent_tys_for_sizedness_trait`].
+    fn consider_builtin_sizedness_candidates(
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, Self>,
+        sizedness: SizedTraitKind,
     ) -> Result<Candidate<I>, NoSolution>;
 
     /// A type is `Copy` or `Clone` if its components are `Copy` or `Clone`.
@@ -466,7 +469,15 @@ where
             G::consider_trait_alias_candidate(self, goal)
         } else {
             match cx.as_lang_item(trait_def_id) {
-                Some(TraitSolverLangItem::Sized) => G::consider_builtin_sized_candidate(self, goal),
+                Some(TraitSolverLangItem::Sized) => {
+                    G::consider_builtin_sizedness_candidates(self, goal, SizedTraitKind::Sized)
+                }
+                Some(TraitSolverLangItem::MetaSized) => {
+                    G::consider_builtin_sizedness_candidates(self, goal, SizedTraitKind::MetaSized)
+                }
+                Some(TraitSolverLangItem::PointeeSized) => {
+                    unreachable!("`PointeeSized` is removed during lowering");
+                }
                 Some(TraitSolverLangItem::Copy | TraitSolverLangItem::Clone) => {
                     G::consider_builtin_copy_clone_candidate(self, goal)
                 }
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
index 4a2a7761f7f..f39d3226009 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
@@ -5,6 +5,7 @@ use derive_where::derive_where;
 use rustc_type_ir::data_structures::HashMap;
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
+use rustc_type_ir::solve::SizedTraitKind;
 use rustc_type_ir::solve::inspect::ProbeKind;
 use rustc_type_ir::{
     self as ty, FallibleTypeFolder, Interner, Movability, Mutability, TypeFoldable,
@@ -104,8 +105,9 @@ where
 }
 
 #[instrument(level = "trace", skip(ecx), ret)]
-pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<D, I>(
+pub(in crate::solve) fn instantiate_constituent_tys_for_sizedness_trait<D, I>(
     ecx: &EvalCtxt<'_, D>,
+    sizedness: SizedTraitKind,
     ty: I::Ty,
 ) -> Result<ty::Binder<I, Vec<I::Ty>>, NoSolution>
 where
@@ -113,8 +115,9 @@ where
     I: Interner,
 {
     match ty.kind() {
-        // impl Sized for u*, i*, bool, f*, FnDef, FnPtr, *(const/mut) T, char, &mut? T, [T; N], dyn* Trait, !
-        // impl Sized for Coroutine, CoroutineWitness, Closure, CoroutineClosure
+        // impl {Meta,}Sized for u*, i*, bool, f*, FnDef, FnPtr, *(const/mut) T, char
+        // impl {Meta,}Sized for &mut? T, [T; N], dyn* Trait, !, Coroutine, CoroutineWitness
+        // impl {Meta,}Sized for Closure, CoroutineClosure
         ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
         | ty::Uint(_)
         | ty::Int(_)
@@ -135,13 +138,16 @@ where
         | ty::Dynamic(_, _, ty::DynStar)
         | ty::Error(_) => Ok(ty::Binder::dummy(vec![])),
 
-        ty::Str
-        | ty::Slice(_)
-        | ty::Dynamic(..)
-        | ty::Foreign(..)
-        | ty::Alias(..)
-        | ty::Param(_)
-        | ty::Placeholder(..) => Err(NoSolution),
+        // impl {Meta,}Sized for str, [T], dyn Trait
+        ty::Str | ty::Slice(_) | ty::Dynamic(..) => match sizedness {
+            SizedTraitKind::Sized => Err(NoSolution),
+            SizedTraitKind::MetaSized => Ok(ty::Binder::dummy(vec![])),
+        },
+
+        // impl {} for extern type
+        ty::Foreign(..) => Err(NoSolution),
+
+        ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => Err(NoSolution),
 
         ty::Bound(..)
         | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
@@ -150,22 +156,27 @@ where
 
         ty::UnsafeBinder(bound_ty) => Ok(bound_ty.map_bound(|ty| vec![ty])),
 
-        // impl Sized for ()
-        // impl Sized for (T1, T2, .., Tn) where Tn: Sized if n >= 1
+        // impl {Meta,}Sized for ()
+        // impl {Meta,}Sized for (T1, T2, .., Tn) where Tn: {Meta,}Sized if n >= 1
         ty::Tuple(tys) => Ok(ty::Binder::dummy(tys.last().map_or_else(Vec::new, |ty| vec![ty]))),
 
-        // impl Sized for Adt<Args...> where sized_constraint(Adt)<Args...>: Sized
-        //   `sized_constraint(Adt)` is the deepest struct trail that can be determined
-        //   by the definition of `Adt`, independent of the generic args.
-        // impl Sized for Adt<Args...> if sized_constraint(Adt) == None
-        //   As a performance optimization, `sized_constraint(Adt)` can return `None`
-        //   if the ADTs definition implies that it is sized by for all possible args.
+        // impl {Meta,}Sized for Adt<Args...>
+        //   where {meta,pointee,}sized_constraint(Adt)<Args...>: {Meta,}Sized
+        //
+        //   `{meta,pointee,}sized_constraint(Adt)` is the deepest struct trail that can be
+        //   determined by the definition of `Adt`, independent of the generic args.
+        //
+        // impl {Meta,}Sized for Adt<Args...>
+        //   if {meta,pointee,}sized_constraint(Adt) == None
+        //
+        //   As a performance optimization, `{meta,pointee,}sized_constraint(Adt)` can return `None`
+        //   if the ADTs definition implies that it is {meta,}sized by for all possible args.
         //   In this case, the builtin impl will have no nested subgoals. This is a
-        //   "best effort" optimization and `sized_constraint` may return `Some`, even
-        //   if the ADT is sized for all possible args.
+        //   "best effort" optimization and `{meta,pointee,}sized_constraint` may return `Some`,
+        //   even if the ADT is {meta,pointee,}sized for all possible args.
         ty::Adt(def, args) => {
-            if let Some(sized_crit) = def.sized_constraint(ecx.cx()) {
-                Ok(ty::Binder::dummy(vec![sized_crit.instantiate(ecx.cx(), args)]))
+            if let Some(crit) = def.sizedness_constraint(ecx.cx(), sizedness) {
+                Ok(ty::Binder::dummy(vec![crit.instantiate(ecx.cx(), args)]))
             } else {
                 Ok(ty::Binder::dummy(vec![]))
             }
diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
index 8413c2abbb9..1690c908d12 100644
--- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
@@ -4,6 +4,7 @@
 use rustc_type_ir::fast_reject::DeepRejectCtxt;
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
+use rustc_type_ir::solve::SizedTraitKind;
 use rustc_type_ir::solve::inspect::ProbeKind;
 use rustc_type_ir::{self as ty, Interner, elaborate};
 use tracing::instrument;
@@ -198,11 +199,12 @@ where
         unreachable!("trait aliases are never const")
     }
 
-    fn consider_builtin_sized_candidate(
+    fn consider_builtin_sizedness_candidates(
         _ecx: &mut EvalCtxt<'_, D>,
         _goal: Goal<I, Self>,
+        _sizedness: SizedTraitKind,
     ) -> Result<Candidate<I>, NoSolution> {
-        unreachable!("Sized is never const")
+        unreachable!("Sized/MetaSized is never const")
     }
 
     fn consider_builtin_copy_clone_candidate(
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
index 2fddc0044cb..d51c87fe68e 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
@@ -6,6 +6,7 @@ mod opaque_types;
 use rustc_type_ir::fast_reject::DeepRejectCtxt;
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
+use rustc_type_ir::solve::SizedTraitKind;
 use rustc_type_ir::{self as ty, Interner, NormalizesTo, PredicateKind, Upcast as _};
 use tracing::instrument;
 
@@ -413,11 +414,12 @@ where
         panic!("trait aliases do not have associated types: {:?}", goal);
     }
 
-    fn consider_builtin_sized_candidate(
+    fn consider_builtin_sizedness_candidates(
         _ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, Self>,
+        _sizedness: SizedTraitKind,
     ) -> Result<Candidate<I>, NoSolution> {
-        panic!("`Sized` does not have an associated type: {:?}", goal);
+        panic!("`Sized`/`MetaSized` does not have an associated type: {:?}", goal);
     }
 
     fn consider_builtin_copy_clone_candidate(
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index 110c67a8e21..8ee116b090d 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -4,9 +4,9 @@ use rustc_type_ir::data_structures::IndexSet;
 use rustc_type_ir::fast_reject::DeepRejectCtxt;
 use rustc_type_ir::inherent::*;
 use rustc_type_ir::lang_items::TraitSolverLangItem;
-use rustc_type_ir::solve::CanonicalResponse;
+use rustc_type_ir::solve::{CanonicalResponse, SizedTraitKind};
 use rustc_type_ir::{
-    self as ty, Interner, Movability, TraitPredicate, TypeVisitableExt as _, TypingMode,
+    self as ty, Interner, Movability, TraitPredicate, TraitRef, TypeVisitableExt as _, TypingMode,
     Upcast as _, elaborate,
 };
 use tracing::{debug, instrument, trace};
@@ -131,9 +131,11 @@ where
         assumption: I::Clause,
     ) -> Result<(), NoSolution> {
         if let Some(trait_clause) = assumption.as_trait_clause() {
-            if trait_clause.def_id() == goal.predicate.def_id()
-                && trait_clause.polarity() == goal.predicate.polarity
-            {
+            if trait_clause.polarity() != goal.predicate.polarity {
+                return Err(NoSolution);
+            }
+
+            if trait_clause.def_id() == goal.predicate.def_id() {
                 if DeepRejectCtxt::relate_rigid_rigid(ecx.cx()).args_may_unify(
                     goal.predicate.trait_ref.args,
                     trait_clause.skip_binder().trait_ref.args,
@@ -141,6 +143,17 @@ where
                     return Ok(());
                 }
             }
+
+            // PERF(sized-hierarchy): Sizedness supertraits aren't elaborated to improve perf, so
+            // check for a `Sized` subtrait when looking for `MetaSized`. `PointeeSized` bounds
+            // are syntactic sugar for a lack of bounds so don't need this.
+            if ecx.cx().is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::MetaSized)
+                && ecx.cx().is_lang_item(trait_clause.def_id(), TraitSolverLangItem::Sized)
+            {
+                let meta_sized_clause =
+                    trait_predicate_with_def_id(ecx.cx(), trait_clause, goal.predicate.def_id());
+                return Self::fast_reject_assumption(ecx, goal, meta_sized_clause);
+            }
         }
 
         Err(NoSolution)
@@ -154,6 +167,17 @@ where
     ) -> QueryResult<I> {
         let trait_clause = assumption.as_trait_clause().unwrap();
 
+        // PERF(sized-hierarchy): Sizedness supertraits aren't elaborated to improve perf, so
+        // check for a `Sized` subtrait when looking for `MetaSized`. `PointeeSized` bounds
+        // are syntactic sugar for a lack of bounds so don't need this.
+        if ecx.cx().is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::MetaSized)
+            && ecx.cx().is_lang_item(trait_clause.def_id(), TraitSolverLangItem::Sized)
+        {
+            let meta_sized_clause =
+                trait_predicate_with_def_id(ecx.cx(), trait_clause, goal.predicate.def_id());
+            return Self::match_assumption(ecx, goal, meta_sized_clause, then);
+        }
+
         let assumption_trait_pred = ecx.instantiate_binder_with_infer(trait_clause);
         ecx.eq(goal.param_env, goal.predicate.trait_ref, assumption_trait_pred.trait_ref)?;
 
@@ -245,9 +269,10 @@ where
         })
     }
 
-    fn consider_builtin_sized_candidate(
+    fn consider_builtin_sizedness_candidates(
         ecx: &mut EvalCtxt<'_, D>,
         goal: Goal<I, Self>,
+        sizedness: SizedTraitKind,
     ) -> Result<Candidate<I>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
             return Err(NoSolution);
@@ -256,7 +281,11 @@ where
         ecx.probe_and_evaluate_goal_for_constituent_tys(
             CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial),
             goal,
-            structural_traits::instantiate_constituent_tys_for_sized_trait,
+            |ecx, ty| {
+                structural_traits::instantiate_constituent_tys_for_sizedness_trait(
+                    ecx, sizedness, ty,
+                )
+            },
         )
     }
 
@@ -812,6 +841,25 @@ where
     }
 }
 
+/// Small helper function to change the `def_id` of a trait predicate - this is not normally
+/// something that you want to do, as different traits will require different args and so making
+/// it easy to change the trait is something of a footgun, but it is useful in the narrow
+/// circumstance of changing from `MetaSized` to `Sized`, which happens as part of the lazy
+/// elaboration of sizedness candidates.
+#[inline(always)]
+fn trait_predicate_with_def_id<I: Interner>(
+    cx: I,
+    clause: ty::Binder<I, ty::TraitPredicate<I>>,
+    did: I::DefId,
+) -> I::Clause {
+    clause
+        .map_bound(|c| TraitPredicate {
+            trait_ref: TraitRef::new_from_args(cx, did, c.trait_ref.args),
+            polarity: c.polarity,
+        })
+        .upcast(cx)
+}
+
 impl<D, I> EvalCtxt<'_, D>
 where
     D: SolverDelegate<Interner = I>,
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index b49a13ce584..a64bb424117 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -686,23 +686,34 @@ impl<'a> Parser<'a> {
         }
 
         if let token::DocComment(kind, style, _) = self.token.kind {
-            // We have something like `expr //!val` where the user likely meant `expr // !val`
-            let pos = self.token.span.lo() + BytePos(2);
-            let span = self.token.span.with_lo(pos).with_hi(pos);
-            err.span_suggestion_verbose(
-                span,
-                format!(
-                    "add a space before {} to write a regular comment",
-                    match (kind, style) {
-                        (token::CommentKind::Line, ast::AttrStyle::Inner) => "`!`",
-                        (token::CommentKind::Block, ast::AttrStyle::Inner) => "`!`",
-                        (token::CommentKind::Line, ast::AttrStyle::Outer) => "the last `/`",
-                        (token::CommentKind::Block, ast::AttrStyle::Outer) => "the last `*`",
-                    },
-                ),
-                " ".to_string(),
-                Applicability::MachineApplicable,
-            );
+            // This is to avoid suggesting converting a doc comment to a regular comment
+            // when missing a comma before the doc comment in lists (#142311):
+            //
+            // ```
+            // enum Foo{
+            //     A /// xxxxxxx
+            //     B,
+            // }
+            // ```
+            if !expected.contains(&TokenType::Comma) {
+                // We have something like `expr //!val` where the user likely meant `expr // !val`
+                let pos = self.token.span.lo() + BytePos(2);
+                let span = self.token.span.with_lo(pos).with_hi(pos);
+                err.span_suggestion_verbose(
+                    span,
+                    format!(
+                        "add a space before {} to write a regular comment",
+                        match (kind, style) {
+                            (token::CommentKind::Line, ast::AttrStyle::Inner) => "`!`",
+                            (token::CommentKind::Block, ast::AttrStyle::Inner) => "`!`",
+                            (token::CommentKind::Line, ast::AttrStyle::Outer) => "the last `/`",
+                            (token::CommentKind::Block, ast::AttrStyle::Outer) => "the last `*`",
+                        },
+                    ),
+                    " ".to_string(),
+                    Applicability::MaybeIncorrect,
+                );
+            }
         }
 
         let sp = if self.token == token::Eof {
@@ -2273,23 +2284,18 @@ impl<'a> Parser<'a> {
                     ),
                     // Also catches `fn foo(&a)`.
                     PatKind::Ref(ref inner_pat, mutab)
-                        if matches!(inner_pat.clone().kind, PatKind::Ident(..)) =>
+                        if let PatKind::Ident(_, ident, _) = inner_pat.clone().kind =>
                     {
-                        match inner_pat.clone().kind {
-                            PatKind::Ident(_, ident, _) => {
-                                let mutab = mutab.prefix_str();
-                                (
-                                    ident,
-                                    "self: ",
-                                    format!("{ident}: &{mutab}TypeName"),
-                                    "_: ",
-                                    pat.span.shrink_to_lo(),
-                                    pat.span,
-                                    pat.span.shrink_to_lo(),
-                                )
-                            }
-                            _ => unreachable!(),
-                        }
+                        let mutab = mutab.prefix_str();
+                        (
+                            ident,
+                            "self: ",
+                            format!("{ident}: &{mutab}TypeName"),
+                            "_: ",
+                            pat.span.shrink_to_lo(),
+                            pat.span,
+                            pat.span.shrink_to_lo(),
+                        )
                     }
                     _ => {
                         // Otherwise, try to get a type and emit a suggestion.
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 93489aa8ee9..93c76c47f06 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -4087,7 +4087,7 @@ impl<'a> CondChecker<'a> {
 }
 
 impl MutVisitor for CondChecker<'_> {
-    fn visit_expr(&mut self, e: &mut P<Expr>) {
+    fn visit_expr(&mut self, e: &mut Expr) {
         self.depth += 1;
         use ForbiddenLetReason::*;
 
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 7a226136e23..64653ee2a04 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -1094,7 +1094,7 @@ impl<'a> Parser<'a> {
     fn make_all_value_bindings_mutable(pat: &mut P<Pat>) -> bool {
         struct AddMut(bool);
         impl MutVisitor for AddMut {
-            fn visit_pat(&mut self, pat: &mut P<Pat>) {
+            fn visit_pat(&mut self, pat: &mut Pat) {
                 if let PatKind::Ident(BindingMode(ByRef::No, m @ Mutability::Not), ..) =
                     &mut pat.kind
                 {
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 555ab3cdb2b..b3096e46b09 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -282,11 +282,22 @@ fn emit_malformed_attribute(
     name: Symbol,
     template: AttributeTemplate,
 ) {
+    // attrs with new parsers are locally validated so excluded here
+    if matches!(
+        name,
+        sym::inline
+            | sym::rustc_force_inline
+            | sym::rustc_confusables
+            | sym::repr
+            | sym::deprecated
+    ) {
+        return;
+    }
+
     // Some of previously accepted forms were used in practice,
     // report them as warnings for now.
-    let should_warn = |name| {
-        matches!(name, sym::doc | sym::ignore | sym::inline | sym::link | sym::test | sym::bench)
-    };
+    let should_warn =
+        |name| matches!(name, sym::doc | sym::ignore | sym::link | sym::test | sym::bench);
 
     let error_msg = format!("malformed `{name}` attribute input");
     let mut suggestions = vec![];
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 4e2be8ff0b8..5ce803aa1f8 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -10,7 +10,7 @@ use std::collections::hash_map::Entry;
 
 use rustc_abi::{Align, ExternAbi, Size};
 use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast};
-use rustc_attr_data_structures::{AttributeKind, ReprAttr, find_attr};
+use rustc_attr_data_structures::{AttributeKind, InlineAttr, 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};
@@ -124,6 +124,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     AttributeKind::Stability { span, .. }
                     | AttributeKind::ConstStability { span, .. },
                 ) => self.check_stability_promotable(*span, target),
+                Attribute::Parsed(AttributeKind::Inline(InlineAttr::Force { .. }, ..)) => {} // handled separately below
+                Attribute::Parsed(AttributeKind::Inline(kind, attr_span)) => {
+                    self.check_inline(hir_id, *attr_span, span, kind, target)
+                }
                 Attribute::Parsed(AttributeKind::AllowInternalUnstable(syms)) => self
                     .check_allow_internal_unstable(
                         hir_id,
@@ -147,6 +151,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     | AttributeKind::ConstStabilityIndirect
                     | AttributeKind::MacroTransparency(_),
                 ) => { /* do nothing  */ }
+                Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => {
+                    self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target)
+                }
                 Attribute::Unparsed(_) => {
                     match attr.path().as_slice() {
                         [sym::diagnostic, sym::do_not_recommend, ..] => {
@@ -155,7 +162,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         [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, ..] => {
@@ -188,26 +194,23 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                             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_no_implicit_autorefs, ..] => {
-                            self.check_applied_to_fn_or_method(hir_id, attr, span, target)
+                            self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
                         }
                         [sym::rustc_never_returns_null_ptr, ..] => {
-                            self.check_applied_to_fn_or_method(hir_id, attr, span, target)
+                            self.check_applied_to_fn_or_method(hir_id, attr.span(), 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)
+                            self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
                         }
                         [sym::rustc_lint_untracked_query_information, ..] => {
-                            self.check_applied_to_fn_or_method(hir_id, attr, span, target)
+                            self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
                         }
                         [sym::rustc_lint_diagnostics, ..] => {
-                            self.check_applied_to_fn_or_method(hir_id, attr, span, target)
+                            self.check_applied_to_fn_or_method(hir_id, attr.span(), span, target)
                         }
                         [sym::rustc_lint_opt_ty, ..] => self.check_rustc_lint_opt_ty(attr, span, target),
                         [sym::rustc_lint_opt_deny_field_access, ..] => {
@@ -367,11 +370,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         self.check_rustc_force_inline(hir_id, attrs, span, target);
     }
 
-    fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) {
+    fn inline_attr_str_error_with_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::IgnoredAttrWithMacro { sym },
         );
     }
@@ -431,7 +434,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
     }
 
     /// Checks if an `#[inline]` is applied to a function or a closure.
-    fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
+    fn check_inline(
+        &self,
+        hir_id: HirId,
+        attr_span: Span,
+        defn_span: Span,
+        kind: &InlineAttr,
+        target: Target,
+    ) {
         match target {
             Target::Fn
             | Target::Closure
@@ -440,7 +450,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 self.tcx.emit_node_span_lint(
                     UNUSED_ATTRIBUTES,
                     hir_id,
-                    attr.span(),
+                    attr_span,
                     errors::IgnoredInlineAttrFnProto,
                 )
             }
@@ -451,25 +461,22 @@ 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
             Target::Field | Target::Arm | Target::MacroDef => {
-                self.inline_attr_str_error_with_macro_def(hir_id, attr, "inline")
+                self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "inline")
             }
             _ => {
-                self.dcx().emit_err(errors::InlineNotFnOrClosure {
-                    attr_span: attr.span(),
-                    defn_span: span,
-                });
+                self.dcx().emit_err(errors::InlineNotFnOrClosure { attr_span, defn_span });
             }
         }
 
         // `#[inline]` is ignored if the symbol must be codegened upstream because it's exported.
         if let Some(did) = hir_id.as_owner()
             && self.tcx.def_kind(did).has_codegen_attrs()
-            && !matches!(attr.meta_item_list().as_deref(), Some([item]) if item.has_name(sym::never))
+            && kind != &InlineAttr::Never
         {
             let attrs = self.tcx.codegen_fn_attrs(did);
             // Not checking naked as `#[inline]` is forbidden for naked functions anyways.
@@ -477,7 +484,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 self.tcx.emit_node_span_lint(
                     UNUSED_ATTRIBUTES,
                     hir_id,
-                    attr.span(),
+                    attr_span,
                     errors::InlineIgnoredForExported {},
                 );
             }
@@ -676,6 +683,16 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                         ) => {
                             continue;
                         }
+                        Attribute::Parsed(AttributeKind::Inline(.., span)) => {
+                            self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute {
+                                span: *span,
+                                naked_span: attr.span(),
+                                attr: sym::inline.to_string(),
+                            });
+
+                            return;
+                        }
+                        // FIXME(jdonszelmann): make exhaustive
                         _ => {}
                     }
 
@@ -787,7 +804,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
                 for attr in attrs {
-                    self.inline_attr_str_error_with_macro_def(hir_id, attr, "track_caller");
+                    self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "track_caller");
                 }
             }
             _ => {
@@ -830,7 +847,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
-                self.inline_attr_str_error_with_macro_def(hir_id, attr, "non_exhaustive");
+                self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "non_exhaustive");
             }
             _ => {
                 self.dcx().emit_err(errors::NonExhaustiveWrongLocation {
@@ -850,7 +867,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
-                self.inline_attr_str_error_with_macro_def(hir_id, attr, "marker");
+                self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "marker");
             }
             _ => {
                 self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait {
@@ -904,7 +921,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
-                self.inline_attr_str_error_with_macro_def(hir_id, attr, "target_feature");
+                self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "target_feature");
             }
             _ => {
                 self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
@@ -1619,7 +1636,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
-                self.inline_attr_str_error_with_macro_def(hir_id, attr, "cold");
+                self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "cold");
             }
             _ => {
                 // FIXME: #[cold] was previously allowed on non-functions and some crates used
@@ -1661,7 +1678,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
-                self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_name");
+                self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "link_name");
             }
             _ => {
                 // FIXME: #[cold] was previously allowed on non-functions/statics and some crates
@@ -1695,7 +1712,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
-                self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_link");
+                self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "no_link");
             }
             _ => {
                 self.dcx().emit_err(errors::NoLink { attr_span: attr.span(), span });
@@ -1717,7 +1734,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
-                self.inline_attr_str_error_with_macro_def(hir_id, attr, "export_name");
+                self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "export_name");
             }
             _ => {
                 self.dcx().emit_err(errors::ExportName { attr_span: attr.span(), span });
@@ -1825,15 +1842,15 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
     fn check_applied_to_fn_or_method(
         &self,
         hir_id: HirId,
-        attr: &Attribute,
-        span: Span,
+        attr_span: Span,
+        defn_span: Span,
         target: Target,
     ) {
         let is_function = matches!(target, Target::Fn | Target::Method(..));
         if !is_function {
             self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
-                attr_span: attr.span(),
-                defn_span: span,
+                attr_span,
+                defn_span,
                 on_crate: hir_id == CRATE_HIR_ID,
             });
         }
@@ -1891,7 +1908,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
-                self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_section");
+                self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "link_section");
             }
             _ => {
                 // FIXME: #[link_section] was previously allowed on non-functions/statics and some
@@ -1916,7 +1933,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             // erroneously allowed it and some crates used it accidentally, to be compatible
             // with crates depending on them, we can't throw an error here.
             Target::Field | Target::Arm | Target::MacroDef => {
-                self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_mangle");
+                self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "no_mangle");
             }
             // FIXME: #[no_mangle] was previously allowed on non-functions/statics, this should be an error
             // The error should specify that the item that is wrong is specifically a *foreign* fn/static
@@ -2263,9 +2280,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
             // `#[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 | Target::MacroDef => {
-                self.inline_attr_str_error_with_macro_def(hir_id, attr, "allow_internal_unstable")
-            }
+            Target::Field | Target::Arm | Target::MacroDef => self
+                .inline_attr_str_error_with_macro_def(
+                    hir_id,
+                    attr.span(),
+                    "allow_internal_unstable",
+                ),
             _ => {
                 self.tcx
                     .dcx()
@@ -2638,8 +2658,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         span: Span,
         target: Target,
     ) {
-        let force_inline_attr = attrs.iter().find(|attr| attr.has_name(sym::rustc_force_inline));
-        match (target, force_inline_attr) {
+        match (
+            target,
+            find_attr!(attrs, AttributeKind::Inline(InlineAttr::Force { attr_span, .. }, _) => *attr_span),
+        ) {
             (Target::Closure, None) => {
                 let is_coro = matches!(
                     self.tcx.hir_expect_expr(hir_id).kind,
@@ -2651,20 +2673,19 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 );
                 let parent_did = self.tcx.hir_get_parent_item(hir_id).to_def_id();
                 let parent_span = self.tcx.def_span(parent_did);
-                let parent_force_inline_attr =
-                    self.tcx.get_attr(parent_did, sym::rustc_force_inline);
-                if let Some(attr) = parent_force_inline_attr
-                    && is_coro
+
+                if let Some(attr_span) = find_attr!(
+                    self.tcx.get_all_attrs(parent_did),
+                    AttributeKind::Inline(InlineAttr::Force { attr_span, .. }, _) => *attr_span
+                ) && is_coro
                 {
-                    self.dcx().emit_err(errors::RustcForceInlineCoro {
-                        attr_span: attr.span(),
-                        span: parent_span,
-                    });
+                    self.dcx()
+                        .emit_err(errors::RustcForceInlineCoro { attr_span, span: parent_span });
                 }
             }
             (Target::Fn, _) => (),
-            (_, Some(attr)) => {
-                self.dcx().emit_err(errors::RustcForceInline { attr_span: attr.span(), span });
+            (_, Some(attr_span)) => {
+                self.dcx().emit_err(errors::RustcForceInline { attr_span, span });
             }
             (_, None) => (),
         }
@@ -2885,10 +2906,9 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
 fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) {
     let attrs = tcx.hir_attrs(item.hir_id());
 
-    for attr in attrs {
-        if attr.has_name(sym::inline) {
-            tcx.dcx().emit_err(errors::NonExportedMacroInvalidAttrs { attr_span: attr.span() });
-        }
+    if let Some(attr_span) = find_attr!(attrs, AttributeKind::Inline(i, span) if !matches!(i, InlineAttr::Force{..}) => *span)
+    {
+        tcx.dcx().emit_err(errors::NonExportedMacroInvalidAttrs { attr_span });
     }
 }
 
@@ -2908,6 +2928,7 @@ pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers { check_mod_attrs, ..*providers };
 }
 
+// FIXME(jdonszelmann): remove, check during parsing
 fn check_duplicates(
     tcx: TyCtxt<'_>,
     attr: &Attribute,
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index fa4b024c422..338d9edcd22 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -415,24 +415,24 @@ pub(crate) enum AliasPossibility {
 }
 
 #[derive(Copy, Clone, Debug)]
-pub(crate) enum PathSource<'a, 'c> {
+pub(crate) enum PathSource<'a, 'ast, 'ra> {
     /// Type paths `Path`.
     Type,
     /// Trait paths in bounds or impls.
     Trait(AliasPossibility),
     /// Expression paths `path`, with optional parent context.
-    Expr(Option<&'a Expr>),
+    Expr(Option<&'ast Expr>),
     /// Paths in path patterns `Path`.
     Pat,
     /// Paths in struct expressions and patterns `Path { .. }`.
     Struct,
     /// Paths in tuple struct patterns `Path(..)`.
-    TupleStruct(Span, &'a [Span]),
+    TupleStruct(Span, &'ra [Span]),
     /// `m::A::B` in `<T as m::A>::B::C`.
     ///
     /// Second field holds the "cause" of this one, i.e. the context within
     /// which the trait item is resolved. Used for diagnostics.
-    TraitItem(Namespace, &'c PathSource<'a, 'c>),
+    TraitItem(Namespace, &'a PathSource<'a, 'ast, 'ra>),
     /// Paths in delegation item
     Delegation,
     /// An arg in a `use<'a, N>` precise-capturing bound.
@@ -443,7 +443,7 @@ pub(crate) enum PathSource<'a, 'c> {
     DefineOpaques,
 }
 
-impl<'a> PathSource<'a, '_> {
+impl PathSource<'_, '_, '_> {
     fn namespace(self) -> Namespace {
         match self {
             PathSource::Type
@@ -773,7 +773,7 @@ struct LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
 }
 
 /// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
-impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
+impl<'ast, 'ra, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn visit_attribute(&mut self, _: &'ast Attribute) {
         // We do not want to resolve expressions that appear in attributes,
         // as they do not correspond to actual code.
@@ -1462,7 +1462,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
     }
 }
 
-impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
+impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
     fn new(resolver: &'a mut Resolver<'ra, 'tcx>) -> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         // During late resolution we only track the module component of the parent scope,
         // although it may be useful to track other components as well for diagnostics.
@@ -2010,7 +2010,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         &mut self,
         partial_res: PartialRes,
         path: &[Segment],
-        source: PathSource<'_, '_>,
+        source: PathSource<'_, '_, '_>,
         path_span: Span,
     ) {
         let proj_start = path.len() - partial_res.unresolved_segments();
@@ -4161,7 +4161,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         id: NodeId,
         qself: &Option<P<QSelf>>,
         path: &Path,
-        source: PathSource<'ast, '_>,
+        source: PathSource<'_, 'ast, '_>,
     ) {
         self.smart_resolve_path_fragment(
             qself,
@@ -4178,7 +4178,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         &mut self,
         qself: &Option<P<QSelf>>,
         path: &[Segment],
-        source: PathSource<'ast, '_>,
+        source: PathSource<'_, 'ast, '_>,
         finalize: Finalize,
         record_partial_res: RecordPartialRes,
         parent_qself: Option<&QSelf>,
@@ -4482,7 +4482,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         span: Span,
         defer_to_typeck: bool,
         finalize: Finalize,
-        source: PathSource<'ast, '_>,
+        source: PathSource<'_, 'ast, '_>,
     ) -> Result<Option<PartialRes>, Spanned<ResolutionError<'ra>>> {
         let mut fin_res = None;
 
@@ -4525,7 +4525,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
         path: &[Segment],
         ns: Namespace,
         finalize: Finalize,
-        source: PathSource<'ast, '_>,
+        source: PathSource<'_, 'ast, '_>,
     ) -> Result<Option<PartialRes>, Spanned<ResolutionError<'ra>>> {
         debug!(
             "resolve_qpath(qself={:?}, path={:?}, ns={:?}, finalize={:?})",
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 2f6aed35f25..d5dd3bdb6cd 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -170,12 +170,12 @@ impl TypoCandidate {
     }
 }
 
-impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
+impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn make_base_error(
         &mut self,
         path: &[Segment],
         span: Span,
-        source: PathSource<'_, '_>,
+        source: PathSource<'_, '_, '_>,
         res: Option<Res>,
     ) -> BaseError {
         // Make the base error.
@@ -421,7 +421,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
         path: &[Segment],
         following_seg: Option<&Segment>,
         span: Span,
-        source: PathSource<'_, '_>,
+        source: PathSource<'_, '_, '_>,
         res: Option<Res>,
         qself: Option<&QSelf>,
     ) -> (Diag<'tcx>, Vec<ImportSuggestion>) {
@@ -539,7 +539,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
         path: &[Segment],
         following_seg: Option<&Segment>,
         span: Span,
-        source: PathSource<'_, '_>,
+        source: PathSource<'_, '_, '_>,
         res: Option<Res>,
         qself: Option<&QSelf>,
     ) {
@@ -650,7 +650,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn try_lookup_name_relaxed(
         &mut self,
         err: &mut Diag<'_>,
-        source: PathSource<'_, '_>,
+        source: PathSource<'_, '_, '_>,
         path: &[Segment],
         following_seg: Option<&Segment>,
         span: Span,
@@ -940,7 +940,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn suggest_trait_and_bounds(
         &mut self,
         err: &mut Diag<'_>,
-        source: PathSource<'_, '_>,
+        source: PathSource<'_, '_, '_>,
         res: Option<Res>,
         span: Span,
         base_error: &BaseError,
@@ -1017,7 +1017,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn suggest_typo(
         &mut self,
         err: &mut Diag<'_>,
-        source: PathSource<'_, '_>,
+        source: PathSource<'_, '_, '_>,
         path: &[Segment],
         following_seg: Option<&Segment>,
         span: Span,
@@ -1063,7 +1063,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn suggest_shadowed(
         &mut self,
         err: &mut Diag<'_>,
-        source: PathSource<'_, '_>,
+        source: PathSource<'_, '_, '_>,
         path: &[Segment],
         following_seg: Option<&Segment>,
         span: Span,
@@ -1096,7 +1096,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn err_code_special_cases(
         &mut self,
         err: &mut Diag<'_>,
-        source: PathSource<'_, '_>,
+        source: PathSource<'_, '_, '_>,
         path: &[Segment],
         span: Span,
     ) {
@@ -1141,7 +1141,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn suggest_self_ty(
         &mut self,
         err: &mut Diag<'_>,
-        source: PathSource<'_, '_>,
+        source: PathSource<'_, '_, '_>,
         path: &[Segment],
         span: Span,
     ) -> bool {
@@ -1164,7 +1164,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn suggest_self_value(
         &mut self,
         err: &mut Diag<'_>,
-        source: PathSource<'_, '_>,
+        source: PathSource<'_, '_, '_>,
         path: &[Segment],
         span: Span,
     ) -> bool {
@@ -1332,7 +1332,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn suggest_swapping_misplaced_self_ty_and_trait(
         &mut self,
         err: &mut Diag<'_>,
-        source: PathSource<'_, '_>,
+        source: PathSource<'_, '_, '_>,
         res: Option<Res>,
         span: Span,
     ) {
@@ -1361,7 +1361,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
         &mut self,
         err: &mut Diag<'_>,
         res: Option<Res>,
-        source: PathSource<'_, '_>,
+        source: PathSource<'_, '_, '_>,
     ) {
         let PathSource::TupleStruct(_, _) = source else { return };
         let Some(Res::Def(DefKind::Fn, _)) = res else { return };
@@ -1373,7 +1373,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
         &mut self,
         err: &mut Diag<'_>,
         res: Option<Res>,
-        source: PathSource<'_, '_>,
+        source: PathSource<'_, '_, '_>,
         span: Span,
     ) {
         let PathSource::Trait(_) = source else { return };
@@ -1422,7 +1422,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn suggest_pattern_match_with_let(
         &mut self,
         err: &mut Diag<'_>,
-        source: PathSource<'_, '_>,
+        source: PathSource<'_, '_, '_>,
         span: Span,
     ) -> bool {
         if let PathSource::Expr(_) = source
@@ -1448,7 +1448,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn get_single_associated_item(
         &mut self,
         path: &[Segment],
-        source: &PathSource<'_, '_>,
+        source: &PathSource<'_, '_, '_>,
         filter_fn: &impl Fn(Res) -> bool,
     ) -> Option<TypoSuggestion> {
         if let crate::PathSource::TraitItem(_, _) = source {
@@ -1556,7 +1556,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
 
     /// Check if the source is call expression and the first argument is `self`. If true,
     /// return the span of whole call and the span for all arguments expect the first one (`self`).
-    fn call_has_self_arg(&self, source: PathSource<'_, '_>) -> Option<(Span, Option<Span>)> {
+    fn call_has_self_arg(&self, source: PathSource<'_, '_, '_>) -> Option<(Span, Option<Span>)> {
         let mut has_self_arg = None;
         if let PathSource::Expr(Some(parent)) = source
             && let ExprKind::Call(_, args) = &parent.kind
@@ -1614,7 +1614,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
         &mut self,
         err: &mut Diag<'_>,
         span: Span,
-        source: PathSource<'_, '_>,
+        source: PathSource<'_, '_, '_>,
         path: &[Segment],
         res: Res,
         path_str: &str,
@@ -1666,7 +1666,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
             }
         };
 
-        let find_span = |source: &PathSource<'_, '_>, err: &mut Diag<'_>| {
+        let find_span = |source: &PathSource<'_, '_, '_>, err: &mut Diag<'_>| {
             match source {
                 PathSource::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. }))
                 | PathSource::TupleStruct(span, _) => {
@@ -2699,7 +2699,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     fn suggest_using_enum_variant(
         &mut self,
         err: &mut Diag<'_>,
-        source: PathSource<'_, '_>,
+        source: PathSource<'_, '_, '_>,
         def_id: DefId,
         span: Span,
     ) {
@@ -2877,7 +2877,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
     pub(crate) fn suggest_adding_generic_parameter(
         &self,
         path: &[Segment],
-        source: PathSource<'_, '_>,
+        source: PathSource<'_, '_, '_>,
     ) -> Option<(Span, &'static str, String, Applicability)> {
         let (ident, span) = match path {
             [segment]
diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs
index 34be35e36ac..656ecfcab36 100644
--- a/compiler/rustc_serialize/src/lib.rs
+++ b/compiler/rustc_serialize/src/lib.rs
@@ -3,6 +3,7 @@
 // tidy-alphabetical-start
 #![allow(internal_features)]
 #![allow(rustc::internal)]
+#![cfg_attr(not(bootstrap), feature(sized_hierarchy))]
 #![cfg_attr(test, feature(test))]
 #![doc(
     html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
@@ -27,3 +28,19 @@ mod serialize;
 pub mod int_overflow;
 pub mod leb128;
 pub mod opaque;
+
+// This has nothing to do with `rustc_serialize` but it is convenient to define it in one place
+// for the rest of the compiler so that `cfg(bootstrap)` doesn't need to be littered throughout
+// the compiler wherever `PointeeSized` would be used. `rustc_serialize` happens to be the deepest
+// crate in the crate graph which uses `PointeeSized`.
+//
+// When bootstrap bumps, remove both the `cfg(not(bootstrap))` and `cfg(bootstrap)` lines below
+// and just import `std::marker::PointeeSized` whereever this item was used.
+
+#[cfg(not(bootstrap))]
+pub use std::marker::PointeeSized;
+
+#[cfg(bootstrap)]
+pub trait PointeeSized {}
+#[cfg(bootstrap)]
+impl<T: ?Sized> PointeeSized for T {}
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index 1eefd76f92b..8940d10696d 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -142,7 +142,7 @@ pub trait Decoder {
 ///   `rustc_metadata::rmeta::Lazy`.
 /// * `TyEncodable` should be used for types that are only serialized in crate
 ///   metadata or the incremental cache. This is most types in `rustc_middle`.
-pub trait Encodable<S: Encoder> {
+pub trait Encodable<S: Encoder>: crate::PointeeSized {
     fn encode(&self, s: &mut S);
 }
 
@@ -198,7 +198,7 @@ direct_serialize_impls! {
     char emit_char read_char
 }
 
-impl<S: Encoder, T: ?Sized> Encodable<S> for &T
+impl<S: Encoder, T: ?Sized + crate::PointeeSized> Encodable<S> for &T
 where
     T: Encodable<S>,
 {
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 406a6bd335a..04ca0b75c31 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -3118,6 +3118,7 @@ pub(crate) mod dep_tracking {
     }
 
     impl_dep_tracking_hash_via_hash!(
+        (),
         AutoDiff,
         bool,
         usize,
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index f76f258d00d..9ca405333f4 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -802,6 +802,7 @@ mod desc {
         "either a boolean (`yes`, `no`, `on`, `off`, etc), or a non-negative number";
     pub(crate) const parse_llvm_module_flag: &str = "<key>:<type>:<value>:<behavior>. Type must currently be `u32`. Behavior should be one of (`error`, `warning`, `require`, `override`, `append`, `appendunique`, `max`, `min`)";
     pub(crate) const parse_function_return: &str = "`keep` or `thunk-extern`";
+    pub(crate) const parse_wasm_c_abi: &str = "`spec`";
     pub(crate) const parse_mir_include_spans: &str =
         "either a boolean (`yes`, `no`, `on`, `off`, etc), or `nll` (default: `nll`)";
     pub(crate) const parse_align: &str = "a number that is a power of 2 between 1 and 2^29";
@@ -1897,6 +1898,10 @@ pub mod parse {
         true
     }
 
+    pub(crate) fn parse_wasm_c_abi(_slot: &mut (), v: Option<&str>) -> bool {
+        v == Some("spec")
+    }
+
     pub(crate) fn parse_mir_include_spans(slot: &mut MirIncludeSpans, v: Option<&str>) -> bool {
         *slot = match v {
             Some("on" | "yes" | "y" | "true") | None => MirIncludeSpans::On,
@@ -2631,6 +2636,11 @@ written to standard error output)"),
         Requires `-Clto[=[fat,yes]]`"),
     wasi_exec_model: Option<WasiExecModel> = (None, parse_wasi_exec_model, [TRACKED],
         "whether to build a wasi command or reactor"),
+    // This option only still exists to provide a more gradual transition path for people who need
+    // the spec-complaint C ABI to be used.
+    // FIXME remove this after a couple releases
+    wasm_c_abi: () = ((), parse_wasm_c_abi, [TRACKED],
+        "use spec-compliant C ABI for `wasm32-unknown-unknown` (deprecated, always enabled)"),
     write_long_types_to_disk: bool = (true, parse_bool, [UNTRACKED],
         "whether long type names should be written to files instead of being printed in errors"),
     // tidy-alphabetical-end
diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs
index 771ff98d58d..63623cfad72 100644
--- a/compiler/rustc_smir/src/lib.rs
+++ b/compiler/rustc_smir/src/lib.rs
@@ -9,6 +9,7 @@
 // tidy-alphabetical-start
 #![allow(internal_features)]
 #![allow(rustc::usage_of_ty_tykind)]
+#![cfg_attr(not(bootstrap), feature(sized_hierarchy))]
 #![doc(
     html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
     test(attr(allow(unused_variables), deny(warnings)))
diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs
index ef8c88355f6..baa4c0681e8 100644
--- a/compiler/rustc_smir/src/rustc_smir/context.rs
+++ b/compiler/rustc_smir/src/rustc_smir/context.rs
@@ -12,7 +12,8 @@ use rustc_middle::ty::layout::{
 };
 use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths};
 use rustc_middle::ty::{
-    GenericPredicates, Instance, List, ScalarInt, TyCtxt, TypeVisitableExt, ValTree,
+    CoroutineArgsExt, GenericPredicates, Instance, List, ScalarInt, TyCtxt, TypeVisitableExt,
+    ValTree,
 };
 use rustc_middle::{mir, ty};
 use rustc_span::def_id::LOCAL_CRATE;
@@ -22,9 +23,9 @@ use stable_mir::mir::mono::{InstanceDef, StaticDef};
 use stable_mir::mir::{BinOp, Body, Place, UnOp};
 use stable_mir::target::{MachineInfo, MachineSize};
 use stable_mir::ty::{
-    AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, FieldDef, FnDef, ForeignDef,
-    ForeignItemKind, GenericArgs, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy, Span, Ty,
-    TyConst, TyKind, UintTy, VariantDef,
+    AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, CoroutineDef, Discr, FieldDef, FnDef,
+    ForeignDef, ForeignItemKind, GenericArgs, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy,
+    Span, Ty, TyConst, TyKind, UintTy, VariantDef, VariantIdx,
 };
 use stable_mir::{Crate, CrateDef, CrateItem, CrateNum, DefId, Error, Filename, ItemKind, Symbol};
 
@@ -447,6 +448,30 @@ impl<'tcx> SmirCtxt<'tcx> {
         def.internal(&mut *tables, tcx).variants().len()
     }
 
+    /// Discriminant for a given variant index of AdtDef
+    pub fn adt_discr_for_variant(&self, adt: AdtDef, variant: VariantIdx) -> Discr {
+        let mut tables = self.0.borrow_mut();
+        let tcx = tables.tcx;
+        let adt = adt.internal(&mut *tables, tcx);
+        let variant = variant.internal(&mut *tables, tcx);
+        adt.discriminant_for_variant(tcx, variant).stable(&mut *tables)
+    }
+
+    /// Discriminant for a given variand index and args of a coroutine
+    pub fn coroutine_discr_for_variant(
+        &self,
+        coroutine: CoroutineDef,
+        args: &GenericArgs,
+        variant: VariantIdx,
+    ) -> Discr {
+        let mut tables = self.0.borrow_mut();
+        let tcx = tables.tcx;
+        let coroutine = coroutine.def_id().internal(&mut *tables, tcx);
+        let args = args.internal(&mut *tables, tcx);
+        let variant = variant.internal(&mut *tables, tcx);
+        args.as_coroutine().discriminant_for_variant(coroutine, tcx, variant).stable(&mut *tables)
+    }
+
     /// The name of a variant.
     pub fn variant_name(&self, def: VariantDef) -> Symbol {
         let mut tables = self.0.borrow_mut();
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index 6a26f5f7997..b4239ddd896 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -960,3 +960,11 @@ impl<'tcx> Stable<'tcx> for ty::ImplTraitInTraitData {
         }
     }
 }
+
+impl<'tcx> Stable<'tcx> for rustc_middle::ty::util::Discr<'tcx> {
+    type T = stable_mir::ty::Discr;
+
+    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+        stable_mir::ty::Discr { val: self.val, ty: self.ty.stable(tables) }
+    }
+}
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index b5003baaf63..64fe181c26d 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -9,6 +9,7 @@
 
 use std::ops::RangeInclusive;
 
+use rustc_data_structures::PointeeSized;
 use rustc_hir::def::DefKind;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::AllocId;
@@ -158,7 +159,7 @@ pub(crate) fn new_item_kind(kind: DefKind) -> ItemKind {
 }
 
 /// Trait used to convert between an internal MIR type to a Stable MIR type.
-pub trait Stable<'cx> {
+pub trait Stable<'cx>: PointeeSized {
     /// The stable representation of the type implementing Stable.
     type T;
     /// Converts an object to the equivalent Stable MIR representation.
diff --git a/compiler/rustc_smir/src/stable_mir/compiler_interface.rs b/compiler/rustc_smir/src/stable_mir/compiler_interface.rs
index 3967ad13eeb..2668fba9f4f 100644
--- a/compiler/rustc_smir/src/stable_mir/compiler_interface.rs
+++ b/compiler/rustc_smir/src/stable_mir/compiler_interface.rs
@@ -13,10 +13,10 @@ use stable_mir::mir::mono::{Instance, InstanceDef, StaticDef};
 use stable_mir::mir::{BinOp, Body, Place, UnOp};
 use stable_mir::target::MachineInfo;
 use stable_mir::ty::{
-    AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, FieldDef, FnDef, ForeignDef,
-    ForeignItemKind, ForeignModule, ForeignModuleDef, GenericArgs, GenericPredicates, Generics,
-    ImplDef, ImplTrait, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy, Span, TraitDecl,
-    TraitDef, Ty, TyConst, TyConstId, TyKind, UintTy, VariantDef,
+    AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, CoroutineDef, Discr, FieldDef, FnDef,
+    ForeignDef, ForeignItemKind, ForeignModule, ForeignModuleDef, GenericArgs, GenericPredicates,
+    Generics, ImplDef, ImplTrait, IntrinsicDef, LineInfo, MirConst, PolyFnSig, RigidTy, Span,
+    TraitDecl, TraitDef, Ty, TyConst, TyConstId, TyKind, UintTy, VariantDef, VariantIdx,
 };
 use stable_mir::{
     AssocItems, Crate, CrateItem, CrateItems, CrateNum, DefId, Error, Filename, ImplTraitDecls,
@@ -230,6 +230,21 @@ impl<'tcx> SmirInterface<'tcx> {
         self.cx.adt_variants_len(def)
     }
 
+    /// Discriminant for a given variant index of AdtDef
+    pub(crate) fn adt_discr_for_variant(&self, adt: AdtDef, variant: VariantIdx) -> Discr {
+        self.cx.adt_discr_for_variant(adt, variant)
+    }
+
+    /// Discriminant for a given variand index and args of a coroutine
+    pub(crate) fn coroutine_discr_for_variant(
+        &self,
+        coroutine: CoroutineDef,
+        args: &GenericArgs,
+        variant: VariantIdx,
+    ) -> Discr {
+        self.cx.coroutine_discr_for_variant(coroutine, args, variant)
+    }
+
     /// The name of a variant.
     pub(crate) fn variant_name(&self, def: VariantDef) -> Symbol {
         self.cx.variant_name(def)
diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs
index 2934af31cd5..4415cd6e2e3 100644
--- a/compiler/rustc_smir/src/stable_mir/ty.rs
+++ b/compiler/rustc_smir/src/stable_mir/ty.rs
@@ -756,6 +756,12 @@ crate_def! {
     pub CoroutineDef;
 }
 
+impl CoroutineDef {
+    pub fn discriminant_for_variant(&self, args: &GenericArgs, idx: VariantIdx) -> Discr {
+        with(|cx| cx.coroutine_discr_for_variant(*self, args, idx))
+    }
+}
+
 crate_def! {
     #[derive(Serialize)]
     pub CoroutineClosureDef;
@@ -831,6 +837,15 @@ impl AdtDef {
     pub fn repr(&self) -> ReprOptions {
         with(|cx| cx.adt_repr(*self))
     }
+
+    pub fn discriminant_for_variant(&self, idx: VariantIdx) -> Discr {
+        with(|cx| cx.adt_discr_for_variant(*self, idx))
+    }
+}
+
+pub struct Discr {
+    pub val: u128,
+    pub ty: Ty,
 }
 
 /// Definition of a variant, which can be either a struct / union field or an enum variant.
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index cb9ccf4cc3f..baadff16120 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1355,6 +1355,7 @@ symbols! {
         memtag,
         message,
         meta,
+        meta_sized,
         metadata_type,
         min_const_fn,
         min_const_generics,
@@ -1613,6 +1614,7 @@ symbols! {
         plugin_registrar,
         plugins,
         pointee,
+        pointee_sized,
         pointee_trait,
         pointer,
         pointer_like,
@@ -2016,6 +2018,7 @@ symbols! {
         size_of,
         size_of_val,
         sized,
+        sized_hierarchy,
         skip,
         slice,
         slice_from_raw_parts,
diff --git a/compiler/rustc_target/src/callconv/mips64.rs b/compiler/rustc_target/src/callconv/mips64.rs
index 89f324bc313..77c0cf06fc1 100644
--- a/compiler/rustc_target/src/callconv/mips64.rs
+++ b/compiler/rustc_target/src/callconv/mips64.rs
@@ -2,9 +2,7 @@ use rustc_abi::{
     BackendRepr, FieldsShape, Float, HasDataLayout, Primitive, Reg, Size, TyAbiInterface,
 };
 
-use crate::callconv::{
-    ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, PassMode, Uniform,
-};
+use crate::callconv::{ArgAbi, ArgExtension, CastTarget, FnAbi, PassMode, Uniform};
 
 fn extend_integer_width_mips<Ty>(arg: &mut ArgAbi<'_, Ty>, bits: u64) {
     // Always sign extend u32 values on 64-bit mips
@@ -140,16 +138,7 @@ where
 
     // Extract first 8 chunks as the prefix
     let rest_size = size - Size::from_bytes(8) * prefix_index as u64;
-    arg.cast_to(CastTarget {
-        prefix,
-        rest: Uniform::new(Reg::i64(), rest_size),
-        attrs: ArgAttributes {
-            regular: ArgAttribute::default(),
-            arg_ext: ArgExtension::None,
-            pointee_size: Size::ZERO,
-            pointee_align: None,
-        },
-    });
+    arg.cast_to(CastTarget::prefixed(prefix, Uniform::new(Reg::i64(), rest_size)));
 }
 
 pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs
index 2ff7a71ca82..71cc2a45563 100644
--- a/compiler/rustc_target/src/callconv/mod.rs
+++ b/compiler/rustc_target/src/callconv/mod.rs
@@ -197,6 +197,17 @@ impl ArgAttributes {
     }
 }
 
+impl From<ArgAttribute> for ArgAttributes {
+    fn from(value: ArgAttribute) -> Self {
+        Self {
+            regular: value,
+            arg_ext: ArgExtension::None,
+            pointee_size: Size::ZERO,
+            pointee_align: None,
+        }
+    }
+}
+
 /// An argument passed entirely registers with the
 /// same kind (e.g., HFA / HVA on PPC64 and AArch64).
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
@@ -251,6 +262,9 @@ impl Uniform {
 #[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
 pub struct CastTarget {
     pub prefix: [Option<Reg>; 8],
+    /// The offset of `rest` from the start of the value. Currently only implemented for a `Reg`
+    /// pair created by the `offset_pair` method.
+    pub rest_offset: Option<Size>,
     pub rest: Uniform,
     pub attrs: ArgAttributes,
 }
@@ -263,42 +277,45 @@ impl From<Reg> for CastTarget {
 
 impl From<Uniform> for CastTarget {
     fn from(uniform: Uniform) -> CastTarget {
-        CastTarget {
-            prefix: [None; 8],
-            rest: uniform,
-            attrs: ArgAttributes {
-                regular: ArgAttribute::default(),
-                arg_ext: ArgExtension::None,
-                pointee_size: Size::ZERO,
-                pointee_align: None,
-            },
-        }
+        Self::prefixed([None; 8], uniform)
     }
 }
 
 impl CastTarget {
-    pub fn pair(a: Reg, b: Reg) -> CastTarget {
-        CastTarget {
+    pub fn prefixed(prefix: [Option<Reg>; 8], rest: Uniform) -> Self {
+        Self { prefix, rest_offset: None, rest, attrs: ArgAttributes::new() }
+    }
+
+    pub fn offset_pair(a: Reg, offset_from_start: Size, b: Reg) -> Self {
+        Self {
             prefix: [Some(a), None, None, None, None, None, None, None],
-            rest: Uniform::from(b),
-            attrs: ArgAttributes {
-                regular: ArgAttribute::default(),
-                arg_ext: ArgExtension::None,
-                pointee_size: Size::ZERO,
-                pointee_align: None,
-            },
+            rest_offset: Some(offset_from_start),
+            rest: b.into(),
+            attrs: ArgAttributes::new(),
         }
     }
 
+    pub fn with_attrs(mut self, attrs: ArgAttributes) -> Self {
+        self.attrs = attrs;
+        self
+    }
+
+    pub fn pair(a: Reg, b: Reg) -> CastTarget {
+        Self::prefixed([Some(a), None, None, None, None, None, None, None], Uniform::from(b))
+    }
+
     /// When you only access the range containing valid data, you can use this unaligned size;
     /// otherwise, use the safer `size` method.
     pub fn unaligned_size<C: HasDataLayout>(&self, _cx: &C) -> Size {
         // Prefix arguments are passed in specific designated registers
-        let prefix_size = self
-            .prefix
-            .iter()
-            .filter_map(|x| x.map(|reg| reg.size))
-            .fold(Size::ZERO, |acc, size| acc + size);
+        let prefix_size = if let Some(offset_from_start) = self.rest_offset {
+            offset_from_start
+        } else {
+            self.prefix
+                .iter()
+                .filter_map(|x| x.map(|reg| reg.size))
+                .fold(Size::ZERO, |acc, size| acc + size)
+        };
         // Remaining arguments are passed in chunks of the unit size
         let rest_size =
             self.rest.unit.size * self.rest.total.bytes().div_ceil(self.rest.unit.size.bytes());
@@ -322,9 +339,22 @@ impl CastTarget {
     /// Checks if these two `CastTarget` are equal enough to be considered "the same for all
     /// function call ABIs".
     pub fn eq_abi(&self, other: &Self) -> bool {
-        let CastTarget { prefix: prefix_l, rest: rest_l, attrs: attrs_l } = self;
-        let CastTarget { prefix: prefix_r, rest: rest_r, attrs: attrs_r } = other;
-        prefix_l == prefix_r && rest_l == rest_r && attrs_l.eq_abi(attrs_r)
+        let CastTarget {
+            prefix: prefix_l,
+            rest_offset: rest_offset_l,
+            rest: rest_l,
+            attrs: attrs_l,
+        } = self;
+        let CastTarget {
+            prefix: prefix_r,
+            rest_offset: rest_offset_r,
+            rest: rest_r,
+            attrs: attrs_r,
+        } = other;
+        prefix_l == prefix_r
+            && rest_offset_l == rest_offset_r
+            && rest_l == rest_r
+            && attrs_l.eq_abi(attrs_r)
     }
 }
 
diff --git a/compiler/rustc_target/src/callconv/nvptx64.rs b/compiler/rustc_target/src/callconv/nvptx64.rs
index a26e7dac5ba..44977de7fcb 100644
--- a/compiler/rustc_target/src/callconv/nvptx64.rs
+++ b/compiler/rustc_target/src/callconv/nvptx64.rs
@@ -1,6 +1,6 @@
 use rustc_abi::{HasDataLayout, Reg, Size, TyAbiInterface};
 
-use super::{ArgAttribute, ArgAttributes, ArgExtension, CastTarget};
+use super::CastTarget;
 use crate::callconv::{ArgAbi, FnAbi, Uniform};
 
 fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
@@ -34,16 +34,10 @@ fn classify_aggregate<Ty>(arg: &mut ArgAbi<'_, Ty>) {
     };
 
     if align_bytes == size.bytes() {
-        arg.cast_to(CastTarget {
-            prefix: [Some(reg), None, None, None, None, None, None, None],
-            rest: Uniform::new(Reg::i8(), Size::from_bytes(0)),
-            attrs: ArgAttributes {
-                regular: ArgAttribute::default(),
-                arg_ext: ArgExtension::None,
-                pointee_size: Size::ZERO,
-                pointee_align: None,
-            },
-        });
+        arg.cast_to(CastTarget::prefixed(
+            [Some(reg), None, None, None, None, None, None, None],
+            Uniform::new(Reg::i8(), Size::ZERO),
+        ));
     } else {
         arg.cast_to(Uniform::new(reg, size));
     }
@@ -78,11 +72,10 @@ where
     };
     if arg.layout.size.bytes() / align_bytes == 1 {
         // Make sure we pass the struct as array at the LLVM IR level and not as a single integer.
-        arg.cast_to(CastTarget {
-            prefix: [Some(unit), None, None, None, None, None, None, None],
-            rest: Uniform::new(unit, Size::ZERO),
-            attrs: ArgAttributes::new(),
-        });
+        arg.cast_to(CastTarget::prefixed(
+            [Some(unit), None, None, None, None, None, None, None],
+            Uniform::new(unit, Size::ZERO),
+        ));
     } else {
         arg.cast_to(Uniform::new(unit, arg.layout.size));
     }
diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs
index cd1d3cd1eee..6a2038f9381 100644
--- a/compiler/rustc_target/src/callconv/riscv.rs
+++ b/compiler/rustc_target/src/callconv/riscv.rs
@@ -14,16 +14,16 @@ use crate::spec::HasTargetSpec;
 
 #[derive(Copy, Clone)]
 enum RegPassKind {
-    Float(Reg),
-    Integer(Reg),
+    Float { offset_from_start: Size, ty: Reg },
+    Integer { offset_from_start: Size, ty: Reg },
     Unknown,
 }
 
 #[derive(Copy, Clone)]
 enum FloatConv {
-    FloatPair(Reg, Reg),
+    FloatPair { first_ty: Reg, second_ty_offset_from_start: Size, second_ty: Reg },
     Float(Reg),
-    MixedPair(Reg, Reg),
+    MixedPair { first_ty: Reg, second_ty_offset_from_start: Size, second_ty: Reg },
 }
 
 #[derive(Copy, Clone)]
@@ -43,6 +43,7 @@ fn should_use_fp_conv_helper<'a, Ty, C>(
     flen: u64,
     field1_kind: &mut RegPassKind,
     field2_kind: &mut RegPassKind,
+    offset_from_start: Size,
 ) -> Result<(), CannotUseFpConv>
 where
     Ty: TyAbiInterface<'a, C> + Copy,
@@ -55,16 +56,16 @@ where
                 }
                 match (*field1_kind, *field2_kind) {
                     (RegPassKind::Unknown, _) => {
-                        *field1_kind = RegPassKind::Integer(Reg {
-                            kind: RegKind::Integer,
-                            size: arg_layout.size,
-                        });
+                        *field1_kind = RegPassKind::Integer {
+                            offset_from_start,
+                            ty: Reg { kind: RegKind::Integer, size: arg_layout.size },
+                        };
                     }
-                    (RegPassKind::Float(_), RegPassKind::Unknown) => {
-                        *field2_kind = RegPassKind::Integer(Reg {
-                            kind: RegKind::Integer,
-                            size: arg_layout.size,
-                        });
+                    (RegPassKind::Float { .. }, RegPassKind::Unknown) => {
+                        *field2_kind = RegPassKind::Integer {
+                            offset_from_start,
+                            ty: Reg { kind: RegKind::Integer, size: arg_layout.size },
+                        };
                     }
                     _ => return Err(CannotUseFpConv),
                 }
@@ -75,12 +76,16 @@ where
                 }
                 match (*field1_kind, *field2_kind) {
                     (RegPassKind::Unknown, _) => {
-                        *field1_kind =
-                            RegPassKind::Float(Reg { kind: RegKind::Float, size: arg_layout.size });
+                        *field1_kind = RegPassKind::Float {
+                            offset_from_start,
+                            ty: Reg { kind: RegKind::Float, size: arg_layout.size },
+                        };
                     }
                     (_, RegPassKind::Unknown) => {
-                        *field2_kind =
-                            RegPassKind::Float(Reg { kind: RegKind::Float, size: arg_layout.size });
+                        *field2_kind = RegPassKind::Float {
+                            offset_from_start,
+                            ty: Reg { kind: RegKind::Float, size: arg_layout.size },
+                        };
                     }
                     _ => return Err(CannotUseFpConv),
                 }
@@ -102,13 +107,14 @@ where
                             flen,
                             field1_kind,
                             field2_kind,
+                            offset_from_start,
                         );
                     }
                     return Err(CannotUseFpConv);
                 }
             }
             FieldsShape::Array { count, .. } => {
-                for _ in 0..count {
+                for i in 0..count {
                     let elem_layout = arg_layout.field(cx, 0);
                     should_use_fp_conv_helper(
                         cx,
@@ -117,6 +123,7 @@ where
                         flen,
                         field1_kind,
                         field2_kind,
+                        offset_from_start + elem_layout.size * i,
                     )?;
                 }
             }
@@ -127,7 +134,15 @@ where
                 }
                 for i in arg_layout.fields.index_by_increasing_offset() {
                     let field = arg_layout.field(cx, i);
-                    should_use_fp_conv_helper(cx, &field, xlen, flen, field1_kind, field2_kind)?;
+                    should_use_fp_conv_helper(
+                        cx,
+                        &field,
+                        xlen,
+                        flen,
+                        field1_kind,
+                        field2_kind,
+                        offset_from_start + arg_layout.fields.offset(i),
+                    )?;
                 }
             }
         },
@@ -146,14 +161,52 @@ where
 {
     let mut field1_kind = RegPassKind::Unknown;
     let mut field2_kind = RegPassKind::Unknown;
-    if should_use_fp_conv_helper(cx, arg, xlen, flen, &mut field1_kind, &mut field2_kind).is_err() {
+    if should_use_fp_conv_helper(
+        cx,
+        arg,
+        xlen,
+        flen,
+        &mut field1_kind,
+        &mut field2_kind,
+        Size::ZERO,
+    )
+    .is_err()
+    {
         return None;
     }
     match (field1_kind, field2_kind) {
-        (RegPassKind::Integer(l), RegPassKind::Float(r)) => Some(FloatConv::MixedPair(l, r)),
-        (RegPassKind::Float(l), RegPassKind::Integer(r)) => Some(FloatConv::MixedPair(l, r)),
-        (RegPassKind::Float(l), RegPassKind::Float(r)) => Some(FloatConv::FloatPair(l, r)),
-        (RegPassKind::Float(f), RegPassKind::Unknown) => Some(FloatConv::Float(f)),
+        (
+            RegPassKind::Integer { offset_from_start, .. }
+            | RegPassKind::Float { offset_from_start, .. },
+            _,
+        ) if offset_from_start != Size::ZERO => {
+            panic!("type {:?} has a first field with non-zero offset {offset_from_start:?}", arg.ty)
+        }
+        (
+            RegPassKind::Integer { ty: first_ty, .. },
+            RegPassKind::Float { offset_from_start, ty: second_ty },
+        ) => Some(FloatConv::MixedPair {
+            first_ty,
+            second_ty_offset_from_start: offset_from_start,
+            second_ty,
+        }),
+        (
+            RegPassKind::Float { ty: first_ty, .. },
+            RegPassKind::Integer { offset_from_start, ty: second_ty },
+        ) => Some(FloatConv::MixedPair {
+            first_ty,
+            second_ty_offset_from_start: offset_from_start,
+            second_ty,
+        }),
+        (
+            RegPassKind::Float { ty: first_ty, .. },
+            RegPassKind::Float { offset_from_start, ty: second_ty },
+        ) => Some(FloatConv::FloatPair {
+            first_ty,
+            second_ty_offset_from_start: offset_from_start,
+            second_ty,
+        }),
+        (RegPassKind::Float { ty, .. }, RegPassKind::Unknown) => Some(FloatConv::Float(ty)),
         _ => None,
     }
 }
@@ -171,11 +224,19 @@ where
             FloatConv::Float(f) => {
                 arg.cast_to(f);
             }
-            FloatConv::FloatPair(l, r) => {
-                arg.cast_to(CastTarget::pair(l, r));
+            FloatConv::FloatPair { first_ty, second_ty_offset_from_start, second_ty } => {
+                arg.cast_to(CastTarget::offset_pair(
+                    first_ty,
+                    second_ty_offset_from_start,
+                    second_ty,
+                ));
             }
-            FloatConv::MixedPair(l, r) => {
-                arg.cast_to(CastTarget::pair(l, r));
+            FloatConv::MixedPair { first_ty, second_ty_offset_from_start, second_ty } => {
+                arg.cast_to(CastTarget::offset_pair(
+                    first_ty,
+                    second_ty_offset_from_start,
+                    second_ty,
+                ));
             }
         }
         return false;
@@ -239,15 +300,27 @@ fn classify_arg<'a, Ty, C>(
                 arg.cast_to(f);
                 return;
             }
-            Some(FloatConv::FloatPair(l, r)) if *avail_fprs >= 2 => {
+            Some(FloatConv::FloatPair { first_ty, second_ty_offset_from_start, second_ty })
+                if *avail_fprs >= 2 =>
+            {
                 *avail_fprs -= 2;
-                arg.cast_to(CastTarget::pair(l, r));
+                arg.cast_to(CastTarget::offset_pair(
+                    first_ty,
+                    second_ty_offset_from_start,
+                    second_ty,
+                ));
                 return;
             }
-            Some(FloatConv::MixedPair(l, r)) if *avail_fprs >= 1 && *avail_gprs >= 1 => {
+            Some(FloatConv::MixedPair { first_ty, second_ty_offset_from_start, second_ty })
+                if *avail_fprs >= 1 && *avail_gprs >= 1 =>
+            {
                 *avail_gprs -= 1;
                 *avail_fprs -= 1;
-                arg.cast_to(CastTarget::pair(l, r));
+                arg.cast_to(CastTarget::offset_pair(
+                    first_ty,
+                    second_ty_offset_from_start,
+                    second_ty,
+                ));
                 return;
             }
             _ => (),
diff --git a/compiler/rustc_target/src/callconv/sparc64.rs b/compiler/rustc_target/src/callconv/sparc64.rs
index 7ca0031fc59..186826c08fc 100644
--- a/compiler/rustc_target/src/callconv/sparc64.rs
+++ b/compiler/rustc_target/src/callconv/sparc64.rs
@@ -5,9 +5,7 @@ use rustc_abi::{
     TyAndLayout,
 };
 
-use crate::callconv::{
-    ArgAbi, ArgAttribute, ArgAttributes, ArgExtension, CastTarget, FnAbi, Uniform,
-};
+use crate::callconv::{ArgAbi, ArgAttribute, CastTarget, FnAbi, Uniform};
 use crate::spec::HasTargetSpec;
 
 #[derive(Clone, Debug)]
@@ -197,16 +195,10 @@ where
                     rest_size = rest_size - Reg::i32().size;
                 }
 
-                arg.cast_to(CastTarget {
-                    prefix: data.prefix,
-                    rest: Uniform::new(Reg::i64(), rest_size),
-                    attrs: ArgAttributes {
-                        regular: data.arg_attribute,
-                        arg_ext: ArgExtension::None,
-                        pointee_size: Size::ZERO,
-                        pointee_align: None,
-                    },
-                });
+                arg.cast_to(
+                    CastTarget::prefixed(data.prefix, Uniform::new(Reg::i64(), rest_size))
+                        .with_attrs(data.arg_attribute.into()),
+                );
                 return;
             }
         }
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 010355abd78..7a49f004072 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -6,33 +6,36 @@
 //! to a new platform, and allows for an unprecedented level of control over how
 //! the compiler works.
 //!
-//! # Using custom targets
+//! # Using targets and target.json
 //!
-//! A target tuple, as passed via `rustc --target=TUPLE`, will first be
-//! compared against the list of built-in targets. This is to ease distributing
-//! rustc (no need for configuration files) and also to hold these built-in
-//! targets as immutable and sacred. If `TUPLE` is not one of the built-in
-//! targets, rustc will check if a file named `TUPLE` exists. If it does, it
-//! will be loaded as the target configuration. If the file does not exist,
-//! rustc will search each directory in the environment variable
-//! `RUST_TARGET_PATH` for a file named `TUPLE.json`. The first one found will
-//! be loaded. If no file is found in any of those directories, a fatal error
-//! will be given.
+//! Invoking "rustc --target=${TUPLE}" will result in rustc initiating the [`Target::search`] by
+//! - checking if "$TUPLE" is a complete path to a json (ending with ".json") and loading if so
+//! - checking builtin targets for "${TUPLE}"
+//! - checking directories in "${RUST_TARGET_PATH}" for "${TUPLE}.json"
+//! - checking for "${RUSTC_SYSROOT}/lib/rustlib/${TUPLE}/target.json"
 //!
-//! Projects defining their own targets should use
-//! `--target=path/to/my-awesome-platform.json` instead of adding to
-//! `RUST_TARGET_PATH`.
+//! Code will then be compiled using the first discovered target spec.
 //!
 //! # Defining a new target
 //!
-//! Targets are defined using [JSON](https://json.org/). The `Target` struct in
-//! this module defines the format the JSON file should take, though each
-//! underscore in the field names should be replaced with a hyphen (`-`) in the
-//! JSON file. Some fields are required in every target specification, such as
-//! `llvm-target`, `target-endian`, `target-pointer-width`, `data-layout`,
-//! `arch`, and `os`. In general, options passed to rustc with `-C` override
-//! the target's settings, though `target-feature` and `link-args` will *add*
-//! to the list specified by the target, rather than replace.
+//! Targets are defined using a struct which additionally has serialization to and from [JSON].
+//! The `Target` struct in this module loosely corresponds with the format the JSON takes.
+//! We usually try to make the fields equivalent but we have given up on a 1:1 correspondence
+//! between the JSON and the actual structure itself.
+//!
+//! Some fields are required in every target spec, and they should be embedded in Target directly.
+//! Optional keys are in TargetOptions, but Target derefs to it, for no practical difference.
+//! Most notable is the "data-layout" field which specifies Rust's notion of sizes and alignments
+//! for several key types, such as f64, pointers, and so on.
+//!
+//! At one point we felt `-C` options should override the target's settings, like in C compilers,
+//! but that was an essentially-unmarked route for making code incorrect and Rust unsound.
+//! Confronted with programmers who prefer a compiler with a good UX instead of a lethal weapon,
+//! we have almost-entirely recanted that notion, though we hope "target modifiers" will offer
+//! a way to have a decent UX yet still extend the necessary compiler controls, without
+//! requiring a new target spec for each and every single possible target micro-variant.
+//!
+//! [JSON]: https://json.org
 
 use std::borrow::Cow;
 use std::collections::BTreeMap;
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs
index dba45776c94..66733d5d4b8 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_freebsd.rs
@@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.llvm_abiname = "elfv2".into();
 
     Target {
         llvm_target: "powerpc64-unknown-freebsd".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs
index 1f67bc7f3c2..ecf68ddff8c 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_gnu.rs
@@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.llvm_abiname = "elfv1".into();
 
     Target {
         llvm_target: "powerpc64-unknown-linux-gnu".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
index 49413d27a45..e205aef8285 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_linux_musl.rs
@@ -12,6 +12,7 @@ pub(crate) fn target() -> Target {
     base.stack_probes = StackProbeType::Inline;
     // FIXME(compiler-team#422): musl targets should be dynamically linked by default.
     base.crt_static_default = true;
+    base.llvm_abiname = "elfv2".into();
 
     Target {
         llvm_target: "powerpc64-unknown-linux-musl".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs
index f5ca54291c6..bcb328020ee 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_unknown_openbsd.rs
@@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.llvm_abiname = "elfv2".into();
 
     Target {
         llvm_target: "powerpc64-unknown-openbsd".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs
index 3e4a58f568a..37c888ba514 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64_wrs_vxworks.rs
@@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.llvm_abiname = "elfv1".into();
 
     Target {
         llvm_target: "powerpc64-unknown-linux-gnu".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs
index 4640d537e8e..3096c4d14ad 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_freebsd.rs
@@ -8,6 +8,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.llvm_abiname = "elfv2".into();
 
     Target {
         llvm_target: "powerpc64le-unknown-freebsd".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs
index dd3f660d81e..9e406af53b5 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_gnu.rs
@@ -8,6 +8,7 @@ pub(crate) fn target() -> Target {
     base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
     base.max_atomic_width = Some(64);
     base.stack_probes = StackProbeType::Inline;
+    base.llvm_abiname = "elfv2".into();
 
     Target {
         llvm_target: "powerpc64le-unknown-linux-gnu".into(),
diff --git a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs
index 9e2bfe2c56f..f145c5b8c14 100644
--- a/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/targets/powerpc64le_unknown_linux_musl.rs
@@ -10,6 +10,7 @@ pub(crate) fn target() -> Target {
     base.stack_probes = StackProbeType::Inline;
     // FIXME(compiler-team#422): musl targets should be dynamically linked by default.
     base.crt_static_default = true;
+    base.llvm_abiname = "elfv2".into();
 
     Target {
         llvm_target: "powerpc64le-unknown-linux-musl".into(),
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
index 275b580d794..39f115ce0cd 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
@@ -199,7 +199,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 // avoid inundating the user with unnecessary errors, but we now
                 // check upstream for type errors and don't add the obligations to
                 // begin with in those cases.
-                if self.tcx.is_lang_item(trait_pred.def_id(), LangItem::Sized) {
+                if matches!(
+                    self.tcx.as_lang_item(trait_pred.def_id()),
+                    Some(LangItem::Sized | LangItem::MetaSized)
+                ) {
                     match self.tainted_by_errors() {
                         None => {
                             let err = self.emit_inference_failure_err(
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
index 78f9287b407..d4cc1ceb280 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
@@ -13,7 +13,7 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
 use rustc_errors::{Applicability, Diag, E0038, E0276, MultiSpan, struct_span_code_err};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
-use rustc_hir::{self as hir, AmbigArg, LangItem};
+use rustc_hir::{self as hir, AmbigArg};
 use rustc_infer::traits::solve::Goal;
 use rustc_infer::traits::{
     DynCompatibilityViolation, Obligation, ObligationCause, ObligationCauseCode,
@@ -160,17 +160,24 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             })
             .collect();
 
-        // Ensure `T: Sized` and `T: WF` obligations come last. This lets us display diagnostics
-        // with more relevant type information and hide redundant E0282 errors.
-        errors.sort_by_key(|e| match e.obligation.predicate.kind().skip_binder() {
-            ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))
-                if self.tcx.is_lang_item(pred.def_id(), LangItem::Sized) =>
-            {
-                1
+        // Ensure `T: Sized`, `T: MetaSized`, `T: PointeeSized` and `T: WF` obligations come last.
+        // This lets us display diagnostics with more relevant type information and hide redundant
+        // E0282 errors.
+        errors.sort_by_key(|e| {
+            let maybe_sizedness_did = match e.obligation.predicate.kind().skip_binder() {
+                ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => Some(pred.def_id()),
+                ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(pred)) => Some(pred.def_id()),
+                _ => None,
+            };
+
+            match e.obligation.predicate.kind().skip_binder() {
+                _ if maybe_sizedness_did == self.tcx.lang_items().sized_trait() => 1,
+                _ if maybe_sizedness_did == self.tcx.lang_items().meta_sized_trait() => 2,
+                _ if maybe_sizedness_did == self.tcx.lang_items().pointee_sized_trait() => 3,
+                ty::PredicateKind::Coerce(_) => 4,
+                ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 5,
+                _ => 0,
             }
-            ty::PredicateKind::Coerce(_) => 2,
-            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3,
-            _ => 0,
         });
 
         for (index, error) in errors.iter().enumerate() {
@@ -327,19 +334,26 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti
     let trait_ref = tcx.impl_trait_ref(impl_def_id)?.instantiate_identity();
     let mut w = "impl".to_owned();
 
-    let args = ty::GenericArgs::identity_for_item(tcx, impl_def_id);
+    #[derive(Debug, Default)]
+    struct SizednessFound {
+        sized: bool,
+        meta_sized: bool,
+    }
 
-    // FIXME: Currently only handles ?Sized.
-    //        Needs to support ?Move and ?DynSized when they are implemented.
-    let mut types_without_default_bounds = FxIndexSet::default();
-    let sized_trait = tcx.lang_items().sized_trait();
+    let mut types_with_sizedness_bounds = FxIndexMap::<_, SizednessFound>::default();
+
+    let args = ty::GenericArgs::identity_for_item(tcx, impl_def_id);
 
     let arg_names = args.iter().map(|k| k.to_string()).filter(|k| k != "'_").collect::<Vec<_>>();
     if !arg_names.is_empty() {
-        types_without_default_bounds.extend(args.types());
         w.push('<');
         w.push_str(&arg_names.join(", "));
         w.push('>');
+
+        for ty in args.types() {
+            // `PointeeSized` params might have no predicates.
+            types_with_sizedness_bounds.insert(ty, SizednessFound::default());
+        }
     }
 
     write!(
@@ -351,24 +365,47 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti
     )
     .unwrap();
 
-    // The predicates will contain default bounds like `T: Sized`. We need to
-    // remove these bounds, and add `T: ?Sized` to any untouched type parameters.
     let predicates = tcx.predicates_of(impl_def_id).predicates;
-    let mut pretty_predicates =
-        Vec::with_capacity(predicates.len() + types_without_default_bounds.len());
+    let mut pretty_predicates = Vec::with_capacity(predicates.len());
+
+    let sized_trait = tcx.lang_items().sized_trait();
+    let meta_sized_trait = tcx.lang_items().meta_sized_trait();
 
     for (p, _) in predicates {
-        if let Some(poly_trait_ref) = p.as_trait_clause() {
-            if Some(poly_trait_ref.def_id()) == sized_trait {
-                // FIXME(#120456) - is `swap_remove` correct?
-                types_without_default_bounds.swap_remove(&poly_trait_ref.self_ty().skip_binder());
+        // Accumulate the sizedness bounds for each self ty.
+        if let Some(trait_clause) = p.as_trait_clause() {
+            let self_ty = trait_clause.self_ty().skip_binder();
+            let sizedness_of = types_with_sizedness_bounds.entry(self_ty).or_default();
+            if Some(trait_clause.def_id()) == sized_trait {
+                sizedness_of.sized = true;
+                continue;
+            } else if Some(trait_clause.def_id()) == meta_sized_trait {
+                sizedness_of.meta_sized = true;
                 continue;
             }
         }
+
         pretty_predicates.push(p.to_string());
     }
 
-    pretty_predicates.extend(types_without_default_bounds.iter().map(|ty| format!("{ty}: ?Sized")));
+    for (ty, sizedness) in types_with_sizedness_bounds {
+        if !tcx.features().sized_hierarchy() {
+            if sizedness.sized {
+                // Maybe a default bound, don't write anything.
+            } else {
+                pretty_predicates.push(format!("{ty}: ?Sized"));
+            }
+        } else {
+            if sizedness.sized {
+                // Maybe a default bound, don't write anything.
+                pretty_predicates.push(format!("{ty}: Sized"));
+            } else if sizedness.meta_sized {
+                pretty_predicates.push(format!("{ty}: MetaSized"));
+            } else {
+                pretty_predicates.push(format!("{ty}: PointeeSized"));
+            }
+        }
+    }
 
     if !pretty_predicates.is_empty() {
         write!(w, "\n  where {}", pretty_predicates.join(", ")).unwrap();
@@ -519,7 +556,7 @@ fn attempt_dyn_to_enum_suggestion(
             let Some(impl_type) = tcx.type_of(*impl_id).no_bound_vars() else { return None };
 
             // Obviously unsized impl types won't be usable in an enum.
-            // Note: this doesn't use `Ty::is_trivially_sized` because that function
+            // Note: this doesn't use `Ty::has_trivial_sizedness` because that function
             // defaults to assuming that things are *not* sized, whereas we want to
             // fall back to assuming that things may be sized.
             match impl_type.kind() {
diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs
index 69a0c0809b5..b247c2c2968 100644
--- a/compiler/rustc_trait_selection/src/solve/delegate.rs
+++ b/compiler/rustc_trait_selection/src/solve/delegate.rs
@@ -12,7 +12,7 @@ use rustc_infer::traits::solve::Goal;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::solve::Certainty;
 use rustc_middle::ty::{
-    self, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitableExt as _, TypingMode,
+    self, SizedTraitKind, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeVisitableExt as _, TypingMode,
 };
 use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
 
@@ -79,7 +79,14 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
                     Some(LangItem::Sized)
                         if self
                             .resolve_vars_if_possible(trait_pred.self_ty().skip_binder())
-                            .is_trivially_sized(self.0.tcx) =>
+                            .has_trivial_sizedness(self.0.tcx, SizedTraitKind::Sized) =>
+                    {
+                        return Some(Certainty::Yes);
+                    }
+                    Some(LangItem::MetaSized)
+                        if self
+                            .resolve_vars_if_possible(trait_pred.self_ty().skip_binder())
+                            .has_trivial_sizedness(self.0.tcx, SizedTraitKind::MetaSized) =>
                     {
                         return Some(Certainty::Yes);
                     }
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 93c7dae9c5b..81893cdcc7e 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -462,6 +462,7 @@ fn impl_intersection_has_negative_obligation(
     let param_env = infcx.resolve_vars_if_possible(param_env);
 
     util::elaborate(tcx, tcx.predicates_of(impl2_def_id).instantiate(tcx, impl2_header.impl_args))
+        .elaborate_sized()
         .any(|(clause, _)| try_prove_negated_where_clause(infcx, clause, param_env))
 }
 
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index 47d207e8d41..ee30956295a 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -7,15 +7,15 @@
 use std::ops::ControlFlow;
 
 use rustc_errors::FatalError;
-use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
+use rustc_hir::{self as hir, LangItem};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{
     self, EarlyBinder, GenericArgs, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
     TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Upcast,
     elaborate,
 };
-use rustc_span::Span;
+use rustc_span::{DUMMY_SP, Span};
 use smallvec::SmallVec;
 use tracing::{debug, instrument};
 
@@ -543,11 +543,11 @@ fn receiver_for_self_ty<'tcx>(
 /// 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.
 /// 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`.
+/// `Self: Unsize<U>` and `U: Trait + MetaSized`, and use `U` in place of `dyn Trait`.
 ///
 /// Written as a chalk-style query:
 /// ```ignore (not-rust)
-/// forall (U: Trait + ?Sized) {
+/// forall (U: Trait + MetaSized) {
 ///     if (Self: Unsize<U>) {
 ///         Receiver: DispatchFromDyn<Receiver[Self => U]>
 ///     }
@@ -567,9 +567,10 @@ fn receiver_is_dispatchable<'tcx>(
 ) -> bool {
     debug!("receiver_is_dispatchable: method = {:?}, receiver_ty = {:?}", method, receiver_ty);
 
-    let traits = (tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait());
-    let (Some(unsize_did), Some(dispatch_from_dyn_did)) = traits else {
-        debug!("receiver_is_dispatchable: Missing Unsize or DispatchFromDyn traits");
+    let (Some(unsize_did), Some(dispatch_from_dyn_did)) =
+        (tcx.lang_items().unsize_trait(), tcx.lang_items().dispatch_from_dyn_trait())
+    else {
+        debug!("receiver_is_dispatchable: Missing `Unsize` or `DispatchFromDyn` traits");
         return false;
     };
 
@@ -583,7 +584,7 @@ fn receiver_is_dispatchable<'tcx>(
         receiver_for_self_ty(tcx, receiver_ty, unsized_self_ty, method.def_id);
 
     // create a modified param env, with `Self: Unsize<U>` and `U: Trait` (and all of
-    // its supertraits) added to caller bounds. `U: ?Sized` is already implied here.
+    // its supertraits) added to caller bounds. `U: MetaSized` is already implied here.
     let param_env = {
         // N.B. We generally want to emulate the construction of the `unnormalized_param_env`
         // in the param-env query here. The fact that we don't just start with the clauses
@@ -612,6 +613,12 @@ fn receiver_is_dispatchable<'tcx>(
         let trait_predicate = ty::TraitRef::new_from_args(tcx, trait_def_id, args);
         predicates.push(trait_predicate.upcast(tcx));
 
+        let meta_sized_predicate = {
+            let meta_sized_did = tcx.require_lang_item(LangItem::MetaSized, DUMMY_SP);
+            ty::TraitRef::new(tcx, meta_sized_did, [unsized_self_ty]).upcast(tcx)
+        };
+        predicates.push(meta_sized_predicate);
+
         normalize_param_env_or_error(
             tcx,
             ty::ParamEnv::new(tcx.mk_clauses(&predicates)),
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 97ecf9702e6..81ce58a93fa 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -14,7 +14,7 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
 use rustc_hir::{self as hir, CoroutineDesugaring, CoroutineKind};
 use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError};
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
-use rustc_middle::ty::{self, Ty, TypeVisitableExt, TypingMode, elaborate};
+use rustc_middle::ty::{self, SizedTraitKind, Ty, TypeVisitableExt, TypingMode, elaborate};
 use rustc_middle::{bug, span_bug};
 use tracing::{debug, instrument, trace};
 
@@ -87,7 +87,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     candidates.vec.push(BuiltinCandidate { has_nested: false });
                 }
                 Some(LangItem::Sized) => {
-                    self.assemble_builtin_sized_candidate(obligation, &mut candidates);
+                    self.assemble_builtin_sized_candidate(
+                        obligation,
+                        &mut candidates,
+                        SizedTraitKind::Sized,
+                    );
+                }
+                Some(LangItem::MetaSized) => {
+                    self.assemble_builtin_sized_candidate(
+                        obligation,
+                        &mut candidates,
+                        SizedTraitKind::MetaSized,
+                    );
+                }
+                Some(LangItem::PointeeSized) => {
+                    bug!("`PointeeSized` is removed during lowering");
                 }
                 Some(LangItem::Unsize) => {
                     self.assemble_candidates_for_unsizing(obligation, &mut candidates);
@@ -201,6 +215,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     }
 
                     selcx.infcx.probe(|_| {
+                        let bound = util::lazily_elaborate_sizedness_candidate(
+                            selcx.infcx,
+                            obligation,
+                            bound,
+                        );
+
                         // We checked the polarity already
                         match selcx.match_normalize_trait_ref(
                             obligation,
@@ -245,14 +265,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             .caller_bounds()
             .iter()
             .filter_map(|p| p.as_trait_clause())
-            // Micro-optimization: filter out predicates relating to different traits.
-            .filter(|p| p.def_id() == stack.obligation.predicate.def_id())
+            // Micro-optimization: filter out predicates with different polarities.
             .filter(|p| p.polarity() == stack.obligation.predicate.polarity());
 
         let drcx = DeepRejectCtxt::relate_rigid_rigid(self.tcx());
         let obligation_args = stack.obligation.predicate.skip_binder().trait_ref.args;
         // Keep only those bounds which may apply, and propagate overflow if it occurs.
         for bound in bounds {
+            let bound =
+                util::lazily_elaborate_sizedness_candidate(self.infcx, stack.obligation, bound);
+
+            // Micro-optimization: filter out predicates relating to different traits.
+            if bound.def_id() != stack.obligation.predicate.def_id() {
+                continue;
+            }
+
             let bound_trait_ref = bound.map_bound(|t| t.trait_ref);
             if !drcx.args_may_unify(obligation_args, bound_trait_ref.skip_binder().args) {
                 continue;
@@ -1086,15 +1113,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
     }
 
-    /// Assembles the trait which are built-in to the language itself:
-    /// `Copy`, `Clone` and `Sized`.
+    /// Assembles the `Sized` and `MetaSized` traits which are built-in to the language itself.
     #[instrument(level = "debug", skip(self, candidates))]
     fn assemble_builtin_sized_candidate(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
         candidates: &mut SelectionCandidateSet<'tcx>,
+        sizedness: SizedTraitKind,
     ) {
-        match self.sized_conditions(obligation) {
+        match self.sizedness_conditions(obligation, sizedness) {
             BuiltinImplConditions::Where(nested) => {
                 candidates
                     .vec
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 786afd7cf48..80f71c78993 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -14,7 +14,9 @@ use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::{DefineOpaqueTypes, HigherRankedType, InferOk};
 use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
-use rustc_middle::ty::{self, GenericArgsRef, Region, Ty, TyCtxt, Upcast, elaborate};
+use rustc_middle::ty::{
+    self, GenericArgsRef, Region, SizedTraitKind, Ty, TyCtxt, Upcast, elaborate,
+};
 use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::DefId;
 use thin_vec::thin_vec;
@@ -164,10 +166,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             )
             .break_value()
             .expect("expected to index into clause that exists");
-        let candidate = candidate_predicate
+        let candidate_predicate = candidate_predicate
             .as_trait_clause()
-            .expect("projection candidate is not a trait predicate")
-            .map_bound(|t| t.trait_ref);
+            .expect("projection candidate is not a trait predicate");
+        let candidate_predicate =
+            util::lazily_elaborate_sizedness_candidate(self.infcx, obligation, candidate_predicate);
+
+        let candidate = candidate_predicate.map_bound(|t| t.trait_ref);
 
         let candidate = self.infcx.instantiate_binder_with_fresh_vars(
             obligation.cause.span,
@@ -224,6 +229,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     ) -> PredicateObligations<'tcx> {
         debug!(?obligation, ?param, "confirm_param_candidate");
 
+        let param = util::lazily_elaborate_sizedness_candidate(
+            self.infcx,
+            obligation,
+            param.upcast(self.infcx.tcx),
+        )
+        .map_bound(|p| p.trait_ref);
+
         // During evaluation, we already checked that this
         // where-clause trait-ref could be unified with the obligation
         // trait-ref. Repeat that unification now without any
@@ -251,7 +263,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         let obligations = if has_nested {
             let trait_def = obligation.predicate.def_id();
             let conditions = match tcx.as_lang_item(trait_def) {
-                Some(LangItem::Sized) => self.sized_conditions(obligation),
+                Some(LangItem::Sized) => {
+                    self.sizedness_conditions(obligation, SizedTraitKind::Sized)
+                }
+                Some(LangItem::MetaSized) => {
+                    self.sizedness_conditions(obligation, SizedTraitKind::MetaSized)
+                }
+                Some(LangItem::PointeeSized) => {
+                    bug!("`PointeeSized` is removing during lowering");
+                }
                 Some(LangItem::Copy | LangItem::Clone) => self.copy_clone_conditions(obligation),
                 Some(LangItem::FusedIterator) => self.fused_iterator_conditions(obligation),
                 other => bug!("unexpected builtin trait {trait_def:?} ({other:?})"),
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 1b9b68fa980..9c0ccb26e53 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -27,8 +27,8 @@ use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::TypeErrorToStringExt;
 use rustc_middle::ty::print::{PrintTraitRefExt as _, with_no_trimmed_paths};
 use rustc_middle::ty::{
-    self, DeepRejectCtxt, GenericArgsRef, PolyProjectionPredicate, Ty, TyCtxt, TypeFoldable,
-    TypeVisitableExt, TypingMode, Upcast, elaborate,
+    self, DeepRejectCtxt, GenericArgsRef, PolyProjectionPredicate, SizedTraitKind, Ty, TyCtxt,
+    TypeFoldable, TypeVisitableExt, TypingMode, Upcast, elaborate,
 };
 use rustc_span::{Symbol, sym};
 use tracing::{debug, instrument, trace};
@@ -2094,9 +2094,10 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
 }
 
 impl<'tcx> SelectionContext<'_, 'tcx> {
-    fn sized_conditions(
+    fn sizedness_conditions(
         &mut self,
         obligation: &PolyTraitObligation<'tcx>,
+        sizedness: SizedTraitKind,
     ) -> BuiltinImplConditions<'tcx> {
         use self::BuiltinImplConditions::{Ambiguous, None, Where};
 
@@ -2126,7 +2127,12 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 Where(ty::Binder::dummy(Vec::new()))
             }
 
-            ty::Str | ty::Slice(_) | ty::Dynamic(..) | ty::Foreign(..) => None,
+            ty::Str | ty::Slice(_) | ty::Dynamic(..) => match sizedness {
+                SizedTraitKind::Sized => None,
+                SizedTraitKind::MetaSized => Where(ty::Binder::dummy(Vec::new())),
+            },
+
+            ty::Foreign(..) => None,
 
             ty::Tuple(tys) => Where(
                 obligation.predicate.rebind(tys.last().map_or_else(Vec::new, |&last| vec![last])),
@@ -2135,11 +2141,9 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
             ty::Pat(ty, _) => Where(obligation.predicate.rebind(vec![*ty])),
 
             ty::Adt(def, args) => {
-                if let Some(sized_crit) = def.sized_constraint(self.tcx()) {
+                if let Some(crit) = def.sizedness_constraint(self.tcx(), sizedness) {
                     // (*) binder moved here
-                    Where(
-                        obligation.predicate.rebind(vec![sized_crit.instantiate(self.tcx(), args)]),
-                    )
+                    Where(obligation.predicate.rebind(vec![crit.instantiate(self.tcx(), args)]))
                 } else {
                     Where(ty::Binder::dummy(Vec::new()))
                 }
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 0723aebd5d2..a05bae53566 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -4,10 +4,13 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_hir::LangItem;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::InferCtxt;
+use rustc_infer::traits::PolyTraitObligation;
 pub use rustc_infer::traits::util::*;
 use rustc_middle::bug;
+use rustc_middle::ty::fast_reject::DeepRejectCtxt;
 use rustc_middle::ty::{
-    self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
+    self, PolyTraitPredicate, SizedTraitKind, TraitPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
+    TypeFolder, TypeSuperFoldable, TypeVisitableExt,
 };
 pub use rustc_next_trait_solver::placeholder::BoundVarReplacer;
 use rustc_span::Span;
@@ -362,15 +365,19 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for PlaceholderReplacer<'_, 'tcx> {
 }
 
 pub fn sizedness_fast_path<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>) -> bool {
-    // Proving `Sized` very often on "obviously sized" types like `&T`, accounts for about 60%
-    // percentage of the predicates we have to prove. No need to canonicalize and all that for
-    // such cases.
+    // Proving `Sized`/`MetaSized`, very often on "obviously sized" types like
+    // `&T`, accounts for about 60% percentage of the predicates we have to prove. No need to
+    // canonicalize and all that for such cases.
     if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) =
         predicate.kind().skip_binder()
     {
-        if tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized)
-            && trait_ref.self_ty().is_trivially_sized(tcx)
-        {
+        let sizedness = match tcx.as_lang_item(trait_ref.def_id()) {
+            Some(LangItem::Sized) => SizedTraitKind::Sized,
+            Some(LangItem::MetaSized) => SizedTraitKind::MetaSized,
+            _ => return false,
+        };
+
+        if trait_ref.self_ty().has_trivial_sizedness(tcx, sizedness) {
             debug!("fast path -- trivial sizedness");
             return true;
         }
@@ -378,3 +385,39 @@ pub fn sizedness_fast_path<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
 
     false
 }
+
+/// To improve performance, sizedness traits are not elaborated and so special-casing is required
+/// in the trait solver to find a `Sized` candidate for a `MetaSized` obligation. Returns the
+/// predicate to used in the candidate for such a `obligation`, given a `candidate`.
+pub(crate) fn lazily_elaborate_sizedness_candidate<'tcx>(
+    infcx: &InferCtxt<'tcx>,
+    obligation: &PolyTraitObligation<'tcx>,
+    candidate: PolyTraitPredicate<'tcx>,
+) -> PolyTraitPredicate<'tcx> {
+    if !infcx.tcx.is_lang_item(obligation.predicate.def_id(), LangItem::MetaSized)
+        || !infcx.tcx.is_lang_item(candidate.def_id(), LangItem::Sized)
+    {
+        return candidate;
+    }
+
+    if obligation.predicate.polarity() != candidate.polarity() {
+        return candidate;
+    }
+
+    let drcx = DeepRejectCtxt::relate_rigid_rigid(infcx.tcx);
+    if !drcx.args_may_unify(
+        obligation.predicate.skip_binder().trait_ref.args,
+        candidate.skip_binder().trait_ref.args,
+    ) {
+        return candidate;
+    }
+
+    candidate.map_bound(|c| TraitPredicate {
+        trait_ref: TraitRef::new_from_args(
+            infcx.tcx,
+            obligation.predicate.def_id(),
+            c.trait_ref.args,
+        ),
+        polarity: c.polarity,
+    })
+}
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 416865e861e..d4e6a23f0eb 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -567,6 +567,14 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
         def_id: DefId,
         args: GenericArgsRef<'tcx>,
     ) -> PredicateObligations<'tcx> {
+        // PERF: `Sized`'s predicates include `MetaSized`, but both are compiler implemented marker
+        // traits, so `MetaSized` will always be WF if `Sized` is WF and vice-versa. Determining
+        // the nominal obligations of `Sized` would in-effect just elaborate `MetaSized` and make
+        // the compiler do a bunch of work needlessly.
+        if self.tcx().is_lang_item(def_id, LangItem::Sized) {
+            return Default::default();
+        }
+
         let predicates = self.tcx().predicates_of(def_id);
         let mut origins = vec![def_id; predicates.predicates.len()];
         let mut head = predicates;
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 11becea998c..d996ee2b60a 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -1,23 +1,29 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
-use rustc_hir::LangItem;
 use rustc_hir::def::DefKind;
 use rustc_index::bit_set::DenseBitSet;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{
-    self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast, fold_regions,
+    self, SizedTraitKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast,
+    fold_regions,
 };
 use rustc_span::DUMMY_SP;
 use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId};
 use rustc_trait_selection::traits;
 use tracing::instrument;
 
+/// If `ty` implements the given `sizedness` trait, returns `None`. Otherwise, returns the type
+/// that must implement the given `sizedness` for `ty` to implement it.
 #[instrument(level = "debug", skip(tcx), ret)]
-fn sized_constraint_for_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
+fn sizedness_constraint_for_ty<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    sizedness: SizedTraitKind,
+    ty: Ty<'tcx>,
+) -> Option<Ty<'tcx>> {
     match ty.kind() {
-        // these are always sized
+        // Always `Sized` or `MetaSized`
         ty::Bool
         | ty::Char
         | ty::Int(..)
@@ -35,31 +41,40 @@ fn sized_constraint_for_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'
         | ty::Never
         | ty::Dynamic(_, _, ty::DynStar) => None,
 
-        // these are never sized
-        ty::Str | ty::Slice(..) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => Some(ty),
-
-        ty::Pat(ty, _) => sized_constraint_for_ty(tcx, *ty),
-
-        ty::Tuple(tys) => tys.last().and_then(|&ty| sized_constraint_for_ty(tcx, ty)),
-
-        // recursive case
-        ty::Adt(adt, args) => adt.sized_constraint(tcx).and_then(|intermediate| {
-            let ty = intermediate.instantiate(tcx, args);
-            sized_constraint_for_ty(tcx, ty)
-        }),
+        ty::Str | ty::Slice(..) | ty::Dynamic(_, _, ty::Dyn) => match sizedness {
+            // Never `Sized`
+            SizedTraitKind::Sized => Some(ty),
+            // Always `MetaSized`
+            SizedTraitKind::MetaSized => None,
+        },
 
-        // these can be sized or unsized.
+        // Maybe `Sized` or `MetaSized`
         ty::Param(..) | ty::Alias(..) | ty::Error(_) => Some(ty),
 
         // We cannot instantiate the binder, so just return the *original* type back,
         // but only if the inner type has a sized constraint. Thus we skip the binder,
         // but don't actually use the result from `sized_constraint_for_ty`.
         ty::UnsafeBinder(inner_ty) => {
-            sized_constraint_for_ty(tcx, inner_ty.skip_binder()).map(|_| ty)
+            sizedness_constraint_for_ty(tcx, sizedness, inner_ty.skip_binder()).map(|_| ty)
+        }
+
+        // Never `MetaSized` or `Sized`
+        ty::Foreign(..) => Some(ty),
+
+        // Recursive cases
+        ty::Pat(ty, _) => sizedness_constraint_for_ty(tcx, sizedness, *ty),
+
+        ty::Tuple(tys) => {
+            tys.last().and_then(|&ty| sizedness_constraint_for_ty(tcx, sizedness, ty))
         }
 
+        ty::Adt(adt, args) => adt.sizedness_constraint(tcx, sizedness).and_then(|intermediate| {
+            let ty = intermediate.instantiate(tcx, args);
+            sizedness_constraint_for_ty(tcx, sizedness, ty)
+        }),
+
         ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) => {
-            bug!("unexpected type `{ty:?}` in sized_constraint_for_ty")
+            bug!("unexpected type `{ty:?}` in `sizedness_constraint_for_ty`")
         }
     }
 }
@@ -75,15 +90,22 @@ fn defaultness(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::Defaultness {
     }
 }
 
-/// Calculates the `Sized` constraint.
+/// Returns the type of the last field of a struct ("the constraint") which must implement the
+/// `sizedness` trait for the whole ADT to be considered to implement that `sizedness` trait.
+/// `def_id` is assumed to be the `AdtDef` of a struct and will panic otherwise.
+///
+/// For `Sized`, there are only a few options for the types in the constraint:
+///     - an meta-sized type (str, slices, trait objects, etc)
+///     - an pointee-sized type (extern types)
+///     - a type parameter or projection whose sizedness can't be known
 ///
-/// In fact, there are only a few options for the types in the constraint:
-///     - an obviously-unsized type
+/// For `MetaSized`, there are only a few options for the types in the constraint:
+///     - an pointee-sized type (extern types)
 ///     - a type parameter or projection whose sizedness can't be known
 #[instrument(level = "debug", skip(tcx), ret)]
-fn adt_sized_constraint<'tcx>(
+fn adt_sizedness_constraint<'tcx>(
     tcx: TyCtxt<'tcx>,
-    def_id: DefId,
+    (def_id, sizedness): (DefId, SizedTraitKind),
 ) -> Option<ty::EarlyBinder<'tcx, Ty<'tcx>>> {
     if let Some(def_id) = def_id.as_local() {
         if let ty::Representability::Infinite(_) = tcx.representability(def_id) {
@@ -93,21 +115,21 @@ fn adt_sized_constraint<'tcx>(
     let def = tcx.adt_def(def_id);
 
     if !def.is_struct() {
-        bug!("`adt_sized_constraint` called on non-struct type: {def:?}");
+        bug!("`adt_sizedness_constraint` called on non-struct type: {def:?}");
     }
 
     let tail_def = def.non_enum_variant().tail_opt()?;
     let tail_ty = tcx.type_of(tail_def.did).instantiate_identity();
 
-    let constraint_ty = sized_constraint_for_ty(tcx, tail_ty)?;
+    let constraint_ty = sizedness_constraint_for_ty(tcx, sizedness, tail_ty)?;
 
-    // perf hack: if there is a `constraint_ty: Sized` bound, then we know
+    // perf hack: if there is a `constraint_ty: {Meta,}Sized` bound, then we know
     // that the type is sized and do not need to check it on the impl.
-    let sized_trait_def_id = tcx.require_lang_item(LangItem::Sized, DUMMY_SP);
+    let sizedness_trait_def_id = sizedness.require_lang_item(tcx);
     let predicates = tcx.predicates_of(def.did()).predicates;
     if predicates.iter().any(|(p, _)| {
         p.as_trait_clause().is_some_and(|trait_pred| {
-            trait_pred.def_id() == sized_trait_def_id
+            trait_pred.def_id() == sizedness_trait_def_id
                 && trait_pred.self_ty().skip_binder() == constraint_ty
         })
     }) {
@@ -369,7 +391,7 @@ fn impl_self_is_guaranteed_unsized<'tcx>(tcx: TyCtxt<'tcx>, impl_def_id: DefId)
 pub(crate) fn provide(providers: &mut Providers) {
     *providers = Providers {
         asyncness,
-        adt_sized_constraint,
+        adt_sizedness_constraint,
         param_env,
         typing_env_normalized_for_post_analysis,
         defaultness,
diff --git a/compiler/rustc_type_ir/src/elaborate.rs b/compiler/rustc_type_ir/src/elaborate.rs
index b11bcff1d8b..852949d707b 100644
--- a/compiler/rustc_type_ir/src/elaborate.rs
+++ b/compiler/rustc_type_ir/src/elaborate.rs
@@ -4,6 +4,7 @@ use smallvec::smallvec;
 
 use crate::data_structures::HashSet;
 use crate::inherent::*;
+use crate::lang_items::TraitSolverLangItem;
 use crate::outlives::{Component, push_outlives_components};
 use crate::{self as ty, Interner, Upcast as _};
 
@@ -18,6 +19,7 @@ pub struct Elaborator<I: Interner, O> {
     stack: Vec<O>,
     visited: HashSet<ty::Binder<I, ty::PredicateKind<I>>>,
     mode: Filter,
+    elaborate_sized: ElaborateSized,
 }
 
 enum Filter {
@@ -25,6 +27,12 @@ enum Filter {
     OnlySelf,
 }
 
+#[derive(Eq, PartialEq)]
+enum ElaborateSized {
+    Yes,
+    No,
+}
+
 /// Describes how to elaborate an obligation into a sub-obligation.
 pub trait Elaboratable<I: Interner> {
     fn predicate(&self) -> I::Predicate;
@@ -77,13 +85,19 @@ pub fn elaborate<I: Interner, O: Elaboratable<I>>(
     cx: I,
     obligations: impl IntoIterator<Item = O>,
 ) -> Elaborator<I, O> {
-    let mut elaborator =
-        Elaborator { cx, stack: Vec::new(), visited: HashSet::default(), mode: Filter::All };
+    let mut elaborator = Elaborator {
+        cx,
+        stack: Vec::new(),
+        visited: HashSet::default(),
+        mode: Filter::All,
+        elaborate_sized: ElaborateSized::No,
+    };
     elaborator.extend_deduped(obligations);
     elaborator
 }
 
 impl<I: Interner, O: Elaboratable<I>> Elaborator<I, O> {
+    /// Adds `obligations` to the stack.
     fn extend_deduped(&mut self, obligations: impl IntoIterator<Item = O>) {
         // Only keep those bounds that we haven't already seen.
         // This is necessary to prevent infinite recursion in some
@@ -103,6 +117,13 @@ impl<I: Interner, O: Elaboratable<I>> Elaborator<I, O> {
         self
     }
 
+    /// Start elaborating `Sized` - reqd during coherence checking, normally skipped to improve
+    /// compiler performance.
+    pub fn elaborate_sized(mut self) -> Self {
+        self.elaborate_sized = ElaborateSized::Yes;
+        self
+    }
+
     fn elaborate(&mut self, elaboratable: &O) {
         let cx = self.cx;
 
@@ -111,6 +132,19 @@ impl<I: Interner, O: Elaboratable<I>> Elaborator<I, O> {
             return;
         };
 
+        // PERF(sized-hierarchy): To avoid iterating over sizedness supertraits in
+        // parameter environments, as an optimisation, sizedness supertraits aren't
+        // elaborated, so check if a `Sized` obligation is being elaborated to a
+        // `MetaSized` obligation and emit it. Candidate assembly and confirmation
+        // are modified to check for the `Sized` subtrait when a `MetaSized` obligation
+        // is present.
+        if self.elaborate_sized == ElaborateSized::No
+            && let Some(did) = clause.as_trait_clause().map(|c| c.def_id())
+            && self.cx.is_lang_item(did, TraitSolverLangItem::Sized)
+        {
+            return;
+        }
+
         let bound_clause = clause.kind();
         match bound_clause.skip_binder() {
             ty::ClauseKind::Trait(data) => {
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index 436ab9f80b6..608efc7515c 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -11,7 +11,7 @@ use rustc_ast_ir::Mutability;
 use crate::elaborate::Elaboratable;
 use crate::fold::{TypeFoldable, TypeSuperFoldable};
 use crate::relate::Relate;
-use crate::solve::AdtDestructorKind;
+use crate::solve::{AdtDestructorKind, SizedTraitKind};
 use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
 use crate::{self as ty, CollectAndApply, Interner, UpcastFrom};
 
@@ -571,7 +571,11 @@ pub trait AdtDef<I: Interner>: Copy + Debug + Hash + Eq {
     // FIXME: perhaps use `all_fields` and expose `FieldDef`.
     fn all_field_tys(self, interner: I) -> ty::EarlyBinder<I, impl IntoIterator<Item = I::Ty>>;
 
-    fn sized_constraint(self, interner: I) -> Option<ty::EarlyBinder<I, I::Ty>>;
+    fn sizedness_constraint(
+        self,
+        interner: I,
+        sizedness: SizedTraitKind,
+    ) -> Option<ty::EarlyBinder<I, I::Ty>>;
 
     fn is_fundamental(self) -> bool;
 
diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs
index 699dd82fb22..3ee6e07b7a5 100644
--- a/compiler/rustc_type_ir/src/lang_items.rs
+++ b/compiler/rustc_type_ir/src/lang_items.rs
@@ -30,7 +30,9 @@ pub enum TraitSolverLangItem {
     FutureOutput,
     Iterator,
     Metadata,
+    MetaSized,
     Option,
+    PointeeSized,
     PointeeTrait,
     Poll,
     Sized,
diff --git a/compiler/rustc_type_ir/src/search_graph/mod.rs b/compiler/rustc_type_ir/src/search_graph/mod.rs
index f0eb96b47b1..b59b4f92854 100644
--- a/compiler/rustc_type_ir/src/search_graph/mod.rs
+++ b/compiler/rustc_type_ir/src/search_graph/mod.rs
@@ -842,9 +842,8 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
     /// evaluating this entry would not have ended up depending on either a goal
     /// already on the stack or a provisional cache entry.
     fn candidate_is_applicable(
-        stack: &Stack<X>,
+        &self,
         step_kind_from_parent: PathKind,
-        provisional_cache: &HashMap<X::Input, Vec<ProvisionalCacheEntry<X>>>,
         nested_goals: &NestedGoals<X>,
     ) -> bool {
         // If the global cache entry didn't depend on any nested goals, it always
@@ -855,7 +854,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
 
         // If a nested goal of the global cache entry is on the stack, we would
         // definitely encounter a cycle.
-        if stack.iter().any(|e| nested_goals.contains(e.input)) {
+        if self.stack.iter().any(|e| nested_goals.contains(e.input)) {
             debug!("cache entry not applicable due to stack");
             return false;
         }
@@ -864,7 +863,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
         // would apply for any of its nested goals.
         #[allow(rustc::potential_query_instability)]
         for (input, path_from_global_entry) in nested_goals.iter() {
-            let Some(entries) = provisional_cache.get(&input) else {
+            let Some(entries) = self.provisional_cache.get(&input) else {
                 continue;
             };
 
@@ -890,7 +889,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
                 // We check if any of the paths taken while computing the global goal
                 // would end up with an applicable provisional cache entry.
                 let head = heads.highest_cycle_head();
-                let head_to_curr = Self::cycle_path_kind(stack, step_kind_from_parent, head);
+                let head_to_curr = Self::cycle_path_kind(&self.stack, step_kind_from_parent, head);
                 let full_paths = path_from_global_entry.extend_with(head_to_curr);
                 if full_paths.contains(head_to_provisional.into()) {
                     debug!(
@@ -918,12 +917,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
         cx.with_global_cache(|cache| {
             cache
                 .get(cx, input, available_depth, |nested_goals| {
-                    Self::candidate_is_applicable(
-                        &self.stack,
-                        step_kind_from_parent,
-                        &self.provisional_cache,
-                        nested_goals,
-                    )
+                    self.candidate_is_applicable(step_kind_from_parent, nested_goals)
                 })
                 .map(|c| c.result)
         })
@@ -942,12 +936,7 @@ impl<D: Delegate<Cx = X>, X: Cx> SearchGraph<D> {
         cx.with_global_cache(|cache| {
             let CacheData { result, required_depth, encountered_overflow, nested_goals } = cache
                 .get(cx, input, available_depth, |nested_goals| {
-                    Self::candidate_is_applicable(
-                        &self.stack,
-                        step_kind_from_parent,
-                        &self.provisional_cache,
-                        nested_goals,
-                    )
+                    self.candidate_is_applicable(step_kind_from_parent, nested_goals)
                 })?;
 
             // We don't move cycle participants to the global cache, so the
diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs
index ba777c7c59a..bbbeaa29f84 100644
--- a/compiler/rustc_type_ir/src/solve/mod.rs
+++ b/compiler/rustc_type_ir/src/solve/mod.rs
@@ -8,6 +8,7 @@ use derive_where::derive_where;
 use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
 use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 
+use crate::lang_items::TraitSolverLangItem;
 use crate::search_graph::PathKind;
 use crate::{self as ty, Canonical, CanonicalVarValues, Interner, Upcast};
 
@@ -366,3 +367,24 @@ pub enum AdtDestructorKind {
     NotConst,
     Const,
 }
+
+/// Which sizedness trait - `Sized`, `MetaSized`? `PointeeSized` is omitted as it is removed during
+/// lowering.
+#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
+#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
+pub enum SizedTraitKind {
+    /// `Sized` trait
+    Sized,
+    /// `MetaSized` trait
+    MetaSized,
+}
+
+impl SizedTraitKind {
+    /// Returns `DefId` of corresponding language item.
+    pub fn require_lang_item<I: Interner>(self, cx: I) -> I::DefId {
+        cx.require_lang_item(match self {
+            SizedTraitKind::Sized => TraitSolverLangItem::Sized,
+            SizedTraitKind::MetaSized => TraitSolverLangItem::MetaSized,
+        })
+    }
+}
diff --git a/library/alloc/src/collections/linked_list/tests.rs b/library/alloc/src/collections/linked_list/tests.rs
index 812fe229a0f..410e67d3fdb 100644
--- a/library/alloc/src/collections/linked_list/tests.rs
+++ b/library/alloc/src/collections/linked_list/tests.rs
@@ -1,6 +1,4 @@
-// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
-#![allow(static_mut_refs)]
-
+use std::cell::Cell;
 use std::panic::{AssertUnwindSafe, catch_unwind};
 use std::thread;
 
@@ -58,48 +56,33 @@ fn list_from<T: Clone>(v: &[T]) -> LinkedList<T> {
     v.iter().cloned().collect()
 }
 
+/// Starting from the head of the LinkedList,
+/// follow the next links, while checking the prev links,
+/// and check that length equals the count of visited nodes.
 fn check_links<T>(list: &LinkedList<T>) {
-    unsafe {
-        let mut len = 0;
-        let mut last_ptr: Option<&Node<T>> = None;
-        let mut node_ptr: &Node<T>;
-        match list.head {
-            None => {
-                // tail node should also be None.
-                assert!(list.tail.is_none());
-                assert_eq!(0, list.len);
-                return;
-            }
-            Some(node) => node_ptr = &*node.as_ptr(),
-        }
-        loop {
-            match (last_ptr, node_ptr.prev) {
-                (None, None) => {}
-                (None, _) => panic!("prev link for head"),
-                (Some(p), Some(pptr)) => {
-                    assert_eq!(p as *const Node<T>, pptr.as_ptr() as *const Node<T>);
-                }
-                _ => panic!("prev link is none, not good"),
-            }
-            match node_ptr.next {
-                Some(next) => {
-                    last_ptr = Some(node_ptr);
-                    node_ptr = &*next.as_ptr();
-                    len += 1;
-                }
-                None => {
-                    len += 1;
-                    break;
-                }
-            }
-        }
-
-        // verify that the tail node points to the last node.
-        let tail = list.tail.as_ref().expect("some tail node").as_ref();
-        assert_eq!(tail as *const Node<T>, node_ptr as *const Node<T>);
-        // check that len matches interior links.
-        assert_eq!(len, list.len);
+    let mut node: &Node<T> = if let Some(node) = list.head {
+        // SAFETY: depends on correctness of LinkedList
+        unsafe { &*node.as_ptr() }
+    } else {
+        assert!(list.tail.is_none(), "empty list should have no tail node");
+        assert_eq!(list.len, 0, "empty list should have length 0");
+        return;
+    };
+
+    assert!(node.prev.is_none(), "head node should not have a prev link");
+    let mut prev;
+    let mut len = 1;
+    while let Some(next) = node.next {
+        prev = node;
+        // SAFETY: depends on correctness of LinkedList
+        node = unsafe { &*next.as_ptr() };
+        len += 1;
+        assert_eq!(node.prev.expect("missing prev link"), prev.into(), "bad prev link");
     }
+
+    let tail = list.tail.expect("list is non-empty, so there should be a tail node");
+    assert_eq!(tail, node.into(), "tail node points to the last node");
+    assert_eq!(len, list.len, "len matches interior links");
 }
 
 #[test]
@@ -1027,21 +1010,26 @@ fn extract_if_drop_panic_leak() {
     assert_eq!(d7.dropped(), 1);
 }
 
-#[test]
-#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
-fn extract_if_pred_panic_leak() {
-    static mut DROPS: i32 = 0;
+macro_rules! struct_with_counted_drop {
+    ($struct_name:ident$(($elt_ty:ty))?, $drop_counter:ident $(=> $drop_stmt:expr)?) => {
+        thread_local! {static $drop_counter: Cell<u32> = Cell::new(0);}
+
+        struct $struct_name$(($elt_ty))?;
 
-    #[derive(Debug)]
-    struct D(u32);
+        impl Drop for $struct_name {
+            fn drop(&mut self) {
+                $drop_counter.set($drop_counter.get() + 1);
 
-    impl Drop for D {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
+                $($drop_stmt(self))?
             }
         }
-    }
+    };
+}
+
+#[test]
+#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
+fn extract_if_pred_panic_leak() {
+    struct_with_counted_drop!(D(u32), DROPS);
 
     let mut q = LinkedList::new();
     q.push_back(D(3));
@@ -1053,26 +1041,17 @@ fn extract_if_pred_panic_leak() {
     q.push_front(D(1));
     q.push_front(D(0));
 
-    catch_unwind(AssertUnwindSafe(|| {
+    _ = catch_unwind(AssertUnwindSafe(|| {
         q.extract_if(|item| if item.0 >= 2 { panic!() } else { true }).for_each(drop)
-    }))
-    .ok();
+    }));
 
-    assert_eq!(unsafe { DROPS }, 2); // 0 and 1
+    assert_eq!(DROPS.get(), 2); // 0 and 1
     assert_eq!(q.len(), 6);
 }
 
 #[test]
 fn test_drop() {
-    static mut DROPS: i32 = 0;
-    struct Elem;
-    impl Drop for Elem {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-        }
-    }
+    struct_with_counted_drop!(Elem, DROPS);
 
     let mut ring = LinkedList::new();
     ring.push_back(Elem);
@@ -1081,20 +1060,12 @@ fn test_drop() {
     ring.push_front(Elem);
     drop(ring);
 
-    assert_eq!(unsafe { DROPS }, 4);
+    assert_eq!(DROPS.get(), 4);
 }
 
 #[test]
 fn test_drop_with_pop() {
-    static mut DROPS: i32 = 0;
-    struct Elem;
-    impl Drop for Elem {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-        }
-    }
+    struct_with_counted_drop!(Elem, DROPS);
 
     let mut ring = LinkedList::new();
     ring.push_back(Elem);
@@ -1104,23 +1075,15 @@ fn test_drop_with_pop() {
 
     drop(ring.pop_back());
     drop(ring.pop_front());
-    assert_eq!(unsafe { DROPS }, 2);
+    assert_eq!(DROPS.get(), 2);
 
     drop(ring);
-    assert_eq!(unsafe { DROPS }, 4);
+    assert_eq!(DROPS.get(), 4);
 }
 
 #[test]
 fn test_drop_clear() {
-    static mut DROPS: i32 = 0;
-    struct Elem;
-    impl Drop for Elem {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-        }
-    }
+    struct_with_counted_drop!(Elem, DROPS);
 
     let mut ring = LinkedList::new();
     ring.push_back(Elem);
@@ -1128,30 +1091,16 @@ fn test_drop_clear() {
     ring.push_back(Elem);
     ring.push_front(Elem);
     ring.clear();
-    assert_eq!(unsafe { DROPS }, 4);
+    assert_eq!(DROPS.get(), 4);
 
     drop(ring);
-    assert_eq!(unsafe { DROPS }, 4);
+    assert_eq!(DROPS.get(), 4);
 }
 
 #[test]
 #[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
 fn test_drop_panic() {
-    static mut DROPS: i32 = 0;
-
-    struct D(bool);
-
-    impl Drop for D {
-        fn drop(&mut self) {
-            unsafe {
-                DROPS += 1;
-            }
-
-            if self.0 {
-                panic!("panic in `drop`");
-            }
-        }
-    }
+    struct_with_counted_drop!(D(bool), DROPS => |this: &D| if this.0 { panic!("panic in `drop`"); } );
 
     let mut q = LinkedList::new();
     q.push_back(D(false));
@@ -1165,7 +1114,7 @@ fn test_drop_panic() {
 
     catch_unwind(move || drop(q)).ok();
 
-    assert_eq!(unsafe { DROPS }, 8);
+    assert_eq!(DROPS.get(), 8);
 }
 
 #[test]
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 37614a7ca45..7c71594c430 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -1489,10 +1489,11 @@ impl String {
         Some(ch)
     }
 
-    /// Removes a [`char`] from this `String` at a byte position and returns it.
+    /// Removes a [`char`] from this `String` at byte position `idx` and returns it.
     ///
-    /// This is an *O*(*n*) operation, as it requires copying every element in the
-    /// buffer.
+    /// Copies all bytes after the removed char to new positions.
+    ///
+    /// Note that calling this in a loop can result in quadratic behavior.
     ///
     /// # Panics
     ///
@@ -1678,10 +1679,13 @@ impl String {
         drop(guard);
     }
 
-    /// Inserts a character into this `String` at a byte position.
+    /// Inserts a character into this `String` at byte position `idx`.
+    ///
+    /// Reallocates if `self.capacity()` is insufficient, which may involve copying all
+    /// `self.capacity()` bytes. Makes space for the insertion by copying all bytes of
+    /// `&self[idx..]` to new positions.
     ///
-    /// This is an *O*(*n*) operation as it requires copying every element in the
-    /// buffer.
+    /// Note that calling this in a loop can result in quadratic behavior.
     ///
     /// # Panics
     ///
@@ -1733,10 +1737,13 @@ impl String {
         }
     }
 
-    /// Inserts a string slice into this `String` at a byte position.
+    /// Inserts a string slice into this `String` at byte position `idx`.
+    ///
+    /// Reallocates if `self.capacity()` is insufficient, which may involve copying all
+    /// `self.capacity()` bytes. Makes space for the insertion by copying all bytes of
+    /// `&self[idx..]` to new positions.
     ///
-    /// This is an *O*(*n*) operation as it requires copying every element in the
-    /// buffer.
+    /// Note that calling this in a loop can result in quadratic behavior.
     ///
     /// # Panics
     ///
diff --git a/library/backtrace b/library/backtrace
-Subproject 6c882eb11984d737f62e85f36703effaf34c245
+Subproject b65ab935fb2e0d59dba8966ffca09c9cc5a5f57
diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs
index 90f76d6d4c7..a59b2f05305 100644
--- a/library/core/src/array/iter.rs
+++ b/library/core/src/array/iter.rs
@@ -224,6 +224,13 @@ impl<T, const N: usize> IntoIter<T, N> {
     }
 }
 
+#[stable(feature = "array_value_iter_default", since = "CURRENT_RUSTC_VERSION")]
+impl<T, const N: usize> Default for IntoIter<T, N> {
+    fn default() -> Self {
+        IntoIter::empty()
+    }
+}
+
 #[stable(feature = "array_value_iter_impls", since = "1.40.0")]
 impl<T, const N: usize> Iterator for IntoIter<T, N> {
     type Item = T;
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index a4b6efe35fc..a2c1ba835f3 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -719,7 +719,7 @@ impl<T, const N: usize> Cell<[T; N]> {
 #[rustc_diagnostic_item = "RefCell"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RefCell<T: ?Sized> {
-    borrow: Cell<BorrowFlag>,
+    borrow: Cell<BorrowCounter>,
     // Stores the location of the earliest currently active borrow.
     // This gets updated whenever we go from having zero borrows
     // to having a single borrow. When a borrow occurs, this gets included
@@ -732,54 +732,48 @@ pub struct RefCell<T: ?Sized> {
 /// An error returned by [`RefCell::try_borrow`].
 #[stable(feature = "try_borrow", since = "1.13.0")]
 #[non_exhaustive]
+#[derive(Debug)]
 pub struct BorrowError {
     #[cfg(feature = "debug_refcell")]
     location: &'static crate::panic::Location<'static>,
 }
 
 #[stable(feature = "try_borrow", since = "1.13.0")]
-impl Debug for BorrowError {
+impl Display for BorrowError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut builder = f.debug_struct("BorrowError");
-
         #[cfg(feature = "debug_refcell")]
-        builder.field("location", self.location);
+        let res = write!(
+            f,
+            "RefCell already mutably borrowed; a previous borrow was at {}",
+            self.location
+        );
 
-        builder.finish()
-    }
-}
+        #[cfg(not(feature = "debug_refcell"))]
+        let res = Display::fmt("RefCell already mutably borrowed", f);
 
-#[stable(feature = "try_borrow", since = "1.13.0")]
-impl Display for BorrowError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        Display::fmt("already mutably borrowed", f)
+        res
     }
 }
 
 /// An error returned by [`RefCell::try_borrow_mut`].
 #[stable(feature = "try_borrow", since = "1.13.0")]
 #[non_exhaustive]
+#[derive(Debug)]
 pub struct BorrowMutError {
     #[cfg(feature = "debug_refcell")]
     location: &'static crate::panic::Location<'static>,
 }
 
 #[stable(feature = "try_borrow", since = "1.13.0")]
-impl Debug for BorrowMutError {
+impl Display for BorrowMutError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let mut builder = f.debug_struct("BorrowMutError");
-
         #[cfg(feature = "debug_refcell")]
-        builder.field("location", self.location);
+        let res = write!(f, "RefCell already borrowed; a previous borrow was at {}", self.location);
 
-        builder.finish()
-    }
-}
+        #[cfg(not(feature = "debug_refcell"))]
+        let res = Display::fmt("RefCell already borrowed", f);
 
-#[stable(feature = "try_borrow", since = "1.13.0")]
-impl Display for BorrowMutError {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        Display::fmt("already borrowed", f)
+        res
     }
 }
 
@@ -788,7 +782,7 @@ impl Display for BorrowMutError {
 #[track_caller]
 #[cold]
 fn panic_already_borrowed(err: BorrowMutError) -> ! {
-    panic!("already borrowed: {:?}", err)
+    panic!("{err}")
 }
 
 // This ensures the panicking code is outlined from `borrow` for `RefCell`.
@@ -796,7 +790,7 @@ fn panic_already_borrowed(err: BorrowMutError) -> ! {
 #[track_caller]
 #[cold]
 fn panic_already_mutably_borrowed(err: BorrowError) -> ! {
-    panic!("already mutably borrowed: {:?}", err)
+    panic!("{err}")
 }
 
 // Positive values represent the number of `Ref` active. Negative values
@@ -806,22 +800,22 @@ fn panic_already_mutably_borrowed(err: BorrowError) -> ! {
 //
 // `Ref` and `RefMut` are both two words in size, and so there will likely never
 // be enough `Ref`s or `RefMut`s in existence to overflow half of the `usize`
-// range. Thus, a `BorrowFlag` will probably never overflow or underflow.
+// range. Thus, a `BorrowCounter` will probably never overflow or underflow.
 // However, this is not a guarantee, as a pathological program could repeatedly
 // create and then mem::forget `Ref`s or `RefMut`s. Thus, all code must
 // explicitly check for overflow and underflow in order to avoid unsafety, or at
 // least behave correctly in the event that overflow or underflow happens (e.g.,
 // see BorrowRef::new).
-type BorrowFlag = isize;
-const UNUSED: BorrowFlag = 0;
+type BorrowCounter = isize;
+const UNUSED: BorrowCounter = 0;
 
 #[inline(always)]
-fn is_writing(x: BorrowFlag) -> bool {
+fn is_writing(x: BorrowCounter) -> bool {
     x < UNUSED
 }
 
 #[inline(always)]
-fn is_reading(x: BorrowFlag) -> bool {
+fn is_reading(x: BorrowCounter) -> bool {
     x > UNUSED
 }
 
@@ -1401,12 +1395,12 @@ impl<T> From<T> for RefCell<T> {
 impl<T: CoerceUnsized<U>, U> CoerceUnsized<RefCell<U>> for RefCell<T> {}
 
 struct BorrowRef<'b> {
-    borrow: &'b Cell<BorrowFlag>,
+    borrow: &'b Cell<BorrowCounter>,
 }
 
 impl<'b> BorrowRef<'b> {
     #[inline]
-    fn new(borrow: &'b Cell<BorrowFlag>) -> Option<BorrowRef<'b>> {
+    fn new(borrow: &'b Cell<BorrowCounter>) -> Option<BorrowRef<'b>> {
         let b = borrow.get().wrapping_add(1);
         if !is_reading(b) {
             // Incrementing borrow can result in a non-reading value (<= 0) in these cases:
@@ -1447,7 +1441,7 @@ impl Clone for BorrowRef<'_> {
         debug_assert!(is_reading(borrow));
         // Prevent the borrow counter from overflowing into
         // a writing borrow.
-        assert!(borrow != BorrowFlag::MAX);
+        assert!(borrow != BorrowCounter::MAX);
         self.borrow.set(borrow + 1);
         BorrowRef { borrow: self.borrow }
     }
@@ -1795,7 +1789,7 @@ impl<'b, T: ?Sized> RefMut<'b, T> {
 }
 
 struct BorrowRefMut<'b> {
-    borrow: &'b Cell<BorrowFlag>,
+    borrow: &'b Cell<BorrowCounter>,
 }
 
 impl Drop for BorrowRefMut<'_> {
@@ -1809,7 +1803,7 @@ impl Drop for BorrowRefMut<'_> {
 
 impl<'b> BorrowRefMut<'b> {
     #[inline]
-    fn new(borrow: &'b Cell<BorrowFlag>) -> Option<BorrowRefMut<'b>> {
+    fn new(borrow: &'b Cell<BorrowCounter>) -> Option<BorrowRefMut<'b>> {
         // NOTE: Unlike BorrowRefMut::clone, new is called to create the initial
         // mutable reference, and so there must currently be no existing
         // references. Thus, while clone increments the mutable refcount, here
@@ -1833,7 +1827,7 @@ impl<'b> BorrowRefMut<'b> {
         let borrow = self.borrow.get();
         debug_assert!(is_writing(borrow));
         // Prevent the borrow counter from underflowing.
-        assert!(borrow != BorrowFlag::MIN);
+        assert!(borrow != BorrowCounter::MIN);
         self.borrow.set(borrow - 1);
         BorrowRefMut { borrow: self.borrow }
     }
diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs
index 2c0662c9629..57de507a73e 100644
--- a/library/core/src/clone.rs
+++ b/library/core/src/clone.rs
@@ -36,6 +36,8 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+use crate::marker::PointeeSized;
+
 mod uninit;
 
 /// A common trait that allows explicit creation of a duplicate value.
@@ -283,7 +285,7 @@ impl_use_cloned! {
     reason = "deriving hack, should not be public",
     issue = "none"
 )]
-pub struct AssertParamIsClone<T: Clone + ?Sized> {
+pub struct AssertParamIsClone<T: Clone + PointeeSized> {
     _field: crate::marker::PhantomData<T>,
 }
 #[doc(hidden)]
@@ -293,7 +295,7 @@ pub struct AssertParamIsClone<T: Clone + ?Sized> {
     reason = "deriving hack, should not be public",
     issue = "none"
 )]
-pub struct AssertParamIsCopy<T: Copy + ?Sized> {
+pub struct AssertParamIsCopy<T: Copy + PointeeSized> {
     _field: crate::marker::PhantomData<T>,
 }
 
@@ -530,6 +532,8 @@ unsafe impl CloneToUninit for crate::bstr::ByteStr {
 /// are implemented in `traits::SelectionContext::copy_clone_conditions()`
 /// in `rustc_trait_selection`.
 mod impls {
+    use crate::marker::PointeeSized;
+
     macro_rules! impl_clone {
         ($($t:ty)*) => {
             $(
@@ -560,7 +564,7 @@ mod impls {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<T: ?Sized> Clone for *const T {
+    impl<T: PointeeSized> Clone for *const T {
         #[inline(always)]
         fn clone(&self) -> Self {
             *self
@@ -568,7 +572,7 @@ mod impls {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<T: ?Sized> Clone for *mut T {
+    impl<T: PointeeSized> Clone for *mut T {
         #[inline(always)]
         fn clone(&self) -> Self {
             *self
@@ -577,7 +581,7 @@ mod impls {
 
     /// Shared references can be cloned, but mutable references *cannot*!
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<T: ?Sized> Clone for &T {
+    impl<T: PointeeSized> Clone for &T {
         #[inline(always)]
         #[rustc_diagnostic_item = "noop_method_clone"]
         fn clone(&self) -> Self {
@@ -587,5 +591,5 @@ mod impls {
 
     /// Shared references can be cloned, but mutable references *cannot*!
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<T: ?Sized> !Clone for &mut T {}
+    impl<T: PointeeSized> !Clone for &mut T {}
 }
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index c315131f413..5cb1a148477 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -29,6 +29,7 @@ mod bytewise;
 pub(crate) use bytewise::BytewiseEq;
 
 use self::Ordering::*;
+use crate::marker::PointeeSized;
 use crate::ops::ControlFlow;
 
 /// Trait for comparisons using the equality operator.
@@ -246,7 +247,7 @@ use crate::ops::ControlFlow;
     append_const_msg
 )]
 #[rustc_diagnostic_item = "PartialEq"]
-pub trait PartialEq<Rhs: ?Sized = Self> {
+pub trait PartialEq<Rhs: PointeeSized = Self>: PointeeSized {
     /// Tests for `self` and `other` values to be equal, and is used by `==`.
     #[must_use]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -332,7 +333,7 @@ pub macro PartialEq($item:item) {
 #[doc(alias = "!=")]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "Eq"]
-pub trait Eq: PartialEq<Self> {
+pub trait Eq: PartialEq<Self> + PointeeSized {
     // this method is used solely by `impl Eq or #[derive(Eq)]` to assert that every component of a
     // type implements `Eq` itself. The current deriving infrastructure means doing this assertion
     // without using a method on this trait is nearly impossible.
@@ -361,7 +362,7 @@ pub macro Eq($item:item) {
 #[doc(hidden)]
 #[allow(missing_debug_implementations)]
 #[unstable(feature = "derive_eq", reason = "deriving hack, should not be public", issue = "none")]
-pub struct AssertParamIsEq<T: Eq + ?Sized> {
+pub struct AssertParamIsEq<T: Eq + PointeeSized> {
     _field: crate::marker::PhantomData<T>,
 }
 
@@ -954,7 +955,7 @@ impl<T: Clone> Clone for Reverse<T> {
 #[doc(alias = ">=")]
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "Ord"]
-pub trait Ord: Eq + PartialOrd<Self> {
+pub trait Ord: Eq + PartialOrd<Self> + PointeeSized {
     /// This method returns an [`Ordering`] between `self` and `other`.
     ///
     /// By convention, `self.cmp(&other)` returns the ordering matching the expression
@@ -1337,7 +1338,8 @@ pub macro Ord($item:item) {
     append_const_msg
 )]
 #[rustc_diagnostic_item = "PartialOrd"]
-pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
+#[allow(multiple_supertrait_upcastable)] // FIXME(sized_hierarchy): remove this
+pub trait PartialOrd<Rhs: PointeeSized = Self>: PartialEq<Rhs> + PointeeSized {
     /// This method returns an ordering between `self` and `other` values if one exists.
     ///
     /// # Examples
@@ -1481,7 +1483,7 @@ pub trait PartialOrd<Rhs: ?Sized = Self>: PartialEq<Rhs> {
     }
 }
 
-fn default_chaining_impl<T: ?Sized, U: ?Sized>(
+fn default_chaining_impl<T: PointeeSized, U: PointeeSized>(
     lhs: &T,
     rhs: &U,
     p: impl FnOnce(Ordering) -> bool,
@@ -1803,6 +1805,7 @@ where
 mod impls {
     use crate::cmp::Ordering::{self, Equal, Greater, Less};
     use crate::hint::unreachable_unchecked;
+    use crate::marker::PointeeSized;
     use crate::ops::ControlFlow::{self, Break, Continue};
 
     macro_rules! partial_eq_impl {
@@ -2015,7 +2018,7 @@ mod impls {
     // & pointers
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: ?Sized, B: ?Sized> PartialEq<&B> for &A
+    impl<A: PointeeSized, B: PointeeSized> PartialEq<&B> for &A
     where
         A: PartialEq<B>,
     {
@@ -2029,7 +2032,7 @@ mod impls {
         }
     }
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: ?Sized, B: ?Sized> PartialOrd<&B> for &A
+    impl<A: PointeeSized, B: PointeeSized> PartialOrd<&B> for &A
     where
         A: PartialOrd<B>,
     {
@@ -2071,7 +2074,7 @@ mod impls {
         }
     }
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: ?Sized> Ord for &A
+    impl<A: PointeeSized> Ord for &A
     where
         A: Ord,
     {
@@ -2081,12 +2084,12 @@ mod impls {
         }
     }
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: ?Sized> Eq for &A where A: Eq {}
+    impl<A: PointeeSized> Eq for &A where A: Eq {}
 
     // &mut pointers
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: ?Sized, B: ?Sized> PartialEq<&mut B> for &mut A
+    impl<A: PointeeSized, B: PointeeSized> PartialEq<&mut B> for &mut A
     where
         A: PartialEq<B>,
     {
@@ -2100,7 +2103,7 @@ mod impls {
         }
     }
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: ?Sized, B: ?Sized> PartialOrd<&mut B> for &mut A
+    impl<A: PointeeSized, B: PointeeSized> PartialOrd<&mut B> for &mut A
     where
         A: PartialOrd<B>,
     {
@@ -2142,7 +2145,7 @@ mod impls {
         }
     }
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: ?Sized> Ord for &mut A
+    impl<A: PointeeSized> Ord for &mut A
     where
         A: Ord,
     {
@@ -2152,10 +2155,10 @@ mod impls {
         }
     }
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: ?Sized> Eq for &mut A where A: Eq {}
+    impl<A: PointeeSized> Eq for &mut A where A: Eq {}
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: ?Sized, B: ?Sized> PartialEq<&mut B> for &A
+    impl<A: PointeeSized, B: PointeeSized> PartialEq<&mut B> for &A
     where
         A: PartialEq<B>,
     {
@@ -2170,7 +2173,7 @@ mod impls {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<A: ?Sized, B: ?Sized> PartialEq<&B> for &mut A
+    impl<A: PointeeSized, B: PointeeSized> PartialEq<&B> for &mut A
     where
         A: PartialEq<B>,
     {
diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs
index d86dc24fb57..7132e712ec5 100644
--- a/library/core/src/convert/mod.rs
+++ b/library/core/src/convert/mod.rs
@@ -38,6 +38,7 @@
 use crate::error::Error;
 use crate::fmt;
 use crate::hash::{Hash, Hasher};
+use crate::marker::PointeeSized;
 
 mod num;
 
@@ -215,7 +216,7 @@ pub const fn identity<T>(x: T) -> T {
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "AsRef"]
-pub trait AsRef<T: ?Sized> {
+pub trait AsRef<T: PointeeSized>: PointeeSized {
     /// Converts this type into a shared reference of the (usually inferred) input type.
     #[stable(feature = "rust1", since = "1.0.0")]
     fn as_ref(&self) -> &T;
@@ -366,7 +367,7 @@ pub trait AsRef<T: ?Sized> {
 /// `&mut Vec<u8>`, for example, is the better choice (callers need to pass the correct type then).
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "AsMut"]
-pub trait AsMut<T: ?Sized> {
+pub trait AsMut<T: PointeeSized>: PointeeSized {
     /// Converts this type into a mutable reference of the (usually inferred) input type.
     #[stable(feature = "rust1", since = "1.0.0")]
     fn as_mut(&mut self) -> &mut T;
@@ -701,7 +702,7 @@ pub trait TryFrom<T>: Sized {
 
 // As lifts over &
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized, U: ?Sized> AsRef<U> for &T
+impl<T: PointeeSized, U: PointeeSized> AsRef<U> for &T
 where
     T: AsRef<U>,
 {
@@ -713,7 +714,7 @@ where
 
 // As lifts over &mut
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized, U: ?Sized> AsRef<U> for &mut T
+impl<T: PointeeSized, U: PointeeSized> AsRef<U> for &mut T
 where
     T: AsRef<U>,
 {
@@ -733,7 +734,7 @@ where
 
 // AsMut lifts over &mut
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized, U: ?Sized> AsMut<U> for &mut T
+impl<T: PointeeSized, U: PointeeSized> AsMut<U> for &mut T
 where
     T: AsMut<U>,
 {
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 145e581d1fb..c20b3d4817f 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -4,7 +4,7 @@
 
 use crate::cell::{Cell, Ref, RefCell, RefMut, SyncUnsafeCell, UnsafeCell};
 use crate::char::{EscapeDebugExtArgs, MAX_LEN_UTF8};
-use crate::marker::PhantomData;
+use crate::marker::{PhantomData, PointeeSized};
 use crate::num::fmt as numfmt;
 use crate::ops::Deref;
 use crate::{iter, result, str};
@@ -864,7 +864,7 @@ impl Display for Arguments<'_> {
 #[doc(alias = "{:?}")]
 #[rustc_diagnostic_item = "Debug"]
 #[rustc_trivial_field_reads]
-pub trait Debug {
+pub trait Debug: PointeeSized {
     #[doc = include_str!("fmt_trait_method_doc.md")]
     ///
     /// # Examples
@@ -995,7 +995,7 @@ pub use macros::Debug;
 #[doc(alias = "{}")]
 #[rustc_diagnostic_item = "Display"]
 #[stable(feature = "rust1", since = "1.0.0")]
-pub trait Display {
+pub trait Display: PointeeSized {
     #[doc = include_str!("fmt_trait_method_doc.md")]
     ///
     /// # Examples
@@ -1071,7 +1071,7 @@ pub trait Display {
 /// assert_eq!(format!("l as octal is: {l:#06o}"), "l as octal is: 0o0011");
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-pub trait Octal {
+pub trait Octal: PointeeSized {
     #[doc = include_str!("fmt_trait_method_doc.md")]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn fmt(&self, f: &mut Formatter<'_>) -> Result;
@@ -1130,7 +1130,7 @@ pub trait Octal {
 /// );
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-pub trait Binary {
+pub trait Binary: PointeeSized {
     #[doc = include_str!("fmt_trait_method_doc.md")]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn fmt(&self, f: &mut Formatter<'_>) -> Result;
@@ -1185,7 +1185,7 @@ pub trait Binary {
 /// assert_eq!(format!("l as hex is: {l:#010x}"), "l as hex is: 0x00000009");
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-pub trait LowerHex {
+pub trait LowerHex: PointeeSized {
     #[doc = include_str!("fmt_trait_method_doc.md")]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn fmt(&self, f: &mut Formatter<'_>) -> Result;
@@ -1240,7 +1240,7 @@ pub trait LowerHex {
 /// assert_eq!(format!("l as hex is: {l:#010X}"), "l as hex is: 0x7FFFFFFF");
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-pub trait UpperHex {
+pub trait UpperHex: PointeeSized {
     #[doc = include_str!("fmt_trait_method_doc.md")]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn fmt(&self, f: &mut Formatter<'_>) -> Result;
@@ -1299,7 +1299,7 @@ pub trait UpperHex {
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "Pointer"]
-pub trait Pointer {
+pub trait Pointer: PointeeSized {
     #[doc = include_str!("fmt_trait_method_doc.md")]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn fmt(&self, f: &mut Formatter<'_>) -> Result;
@@ -1350,7 +1350,7 @@ pub trait Pointer {
 /// );
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-pub trait LowerExp {
+pub trait LowerExp: PointeeSized {
     #[doc = include_str!("fmt_trait_method_doc.md")]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn fmt(&self, f: &mut Formatter<'_>) -> Result;
@@ -1401,7 +1401,7 @@ pub trait LowerExp {
 /// );
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
-pub trait UpperExp {
+pub trait UpperExp: PointeeSized {
     #[doc = include_str!("fmt_trait_method_doc.md")]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn fmt(&self, f: &mut Formatter<'_>) -> Result;
@@ -2646,11 +2646,11 @@ macro_rules! fmt_refs {
     ($($tr:ident),*) => {
         $(
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl<T: ?Sized + $tr> $tr for &T {
+        impl<T: PointeeSized + $tr> $tr for &T {
             fn fmt(&self, f: &mut Formatter<'_>) -> Result { $tr::fmt(&**self, f) }
         }
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl<T: ?Sized + $tr> $tr for &mut T {
+        impl<T: PointeeSized + $tr> $tr for &mut T {
             fn fmt(&self, f: &mut Formatter<'_>) -> Result { $tr::fmt(&**self, f) }
         }
         )*
@@ -2772,7 +2772,7 @@ impl Display for char {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> Pointer for *const T {
+impl<T: PointeeSized> Pointer for *const T {
     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
         if <<T as core::ptr::Pointee>::Metadata as core::unit::IsUnit>::is_unit() {
             pointer_fmt_inner(self.expose_provenance(), f)
@@ -2817,21 +2817,21 @@ pub(crate) fn pointer_fmt_inner(ptr_addr: usize, f: &mut Formatter<'_>) -> Resul
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> Pointer for *mut T {
+impl<T: PointeeSized> Pointer for *mut T {
     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
         Pointer::fmt(&(*self as *const T), f)
     }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> Pointer for &T {
+impl<T: PointeeSized> Pointer for &T {
     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
         Pointer::fmt(&(*self as *const T), f)
     }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> Pointer for &mut T {
+impl<T: PointeeSized> Pointer for &mut T {
     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
         Pointer::fmt(&(&**self as *const T), f)
     }
@@ -2840,13 +2840,13 @@ impl<T: ?Sized> Pointer for &mut T {
 // Implementation of Display/Debug for various core types
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> Debug for *const T {
+impl<T: PointeeSized> Debug for *const T {
     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
         Pointer::fmt(self, f)
     }
 }
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> Debug for *mut T {
+impl<T: PointeeSized> Debug for *mut T {
     fn fmt(&self, f: &mut Formatter<'_>) -> Result {
         Pointer::fmt(self, f)
     }
diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs
index f7b874b26bb..efda64791d4 100644
--- a/library/core/src/hash/mod.rs
+++ b/library/core/src/hash/mod.rs
@@ -183,7 +183,7 @@ mod sip;
 /// [impl]: ../../std/primitive.str.html#impl-Hash-for-str
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "Hash"]
-pub trait Hash {
+pub trait Hash: marker::PointeeSized {
     /// Feeds this value into the given [`Hasher`].
     ///
     /// # Examples
@@ -941,7 +941,7 @@ mod impls {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<T: ?Sized + Hash> Hash for &T {
+    impl<T: ?Sized + marker::PointeeSized + Hash> Hash for &T {
         #[inline]
         fn hash<H: Hasher>(&self, state: &mut H) {
             (**self).hash(state);
@@ -949,7 +949,7 @@ mod impls {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<T: ?Sized + Hash> Hash for &mut T {
+    impl<T: ?Sized + marker::PointeeSized + Hash> Hash for &mut T {
         #[inline]
         fn hash<H: Hasher>(&self, state: &mut H) {
             (**self).hash(state);
@@ -957,7 +957,7 @@ mod impls {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<T: ?Sized> Hash for *const T {
+    impl<T: ?Sized + marker::PointeeSized> Hash for *const T {
         #[inline]
         fn hash<H: Hasher>(&self, state: &mut H) {
             let (address, metadata) = self.to_raw_parts();
@@ -967,7 +967,7 @@ mod impls {
     }
 
     #[stable(feature = "rust1", since = "1.0.0")]
-    impl<T: ?Sized> Hash for *mut T {
+    impl<T: ?Sized + marker::PointeeSized> Hash for *mut T {
         #[inline]
         fn hash<H: Hasher>(&self, state: &mut H) {
             let (address, metadata) = self.to_raw_parts();
diff --git a/library/core/src/intrinsics/bounds.rs b/library/core/src/intrinsics/bounds.rs
index 046e191212c..353908598d4 100644
--- a/library/core/src/intrinsics/bounds.rs
+++ b/library/core/src/intrinsics/bounds.rs
@@ -1,39 +1,41 @@
 //! Various traits used to restrict intrinsics to not-completely-wrong types.
 
+use crate::marker::PointeeSized;
+
 /// Types with a built-in dereference operator in runtime MIR,
 /// aka references and raw pointers.
 ///
 /// # Safety
 /// Must actually *be* such a type.
 pub unsafe trait BuiltinDeref: Sized {
-    type Pointee: ?Sized;
+    type Pointee: PointeeSized;
 }
 
-unsafe impl<T: ?Sized> BuiltinDeref for &mut T {
+unsafe impl<T: PointeeSized> BuiltinDeref for &mut T {
     type Pointee = T;
 }
-unsafe impl<T: ?Sized> BuiltinDeref for &T {
+unsafe impl<T: PointeeSized> BuiltinDeref for &T {
     type Pointee = T;
 }
-unsafe impl<T: ?Sized> BuiltinDeref for *mut T {
+unsafe impl<T: PointeeSized> BuiltinDeref for *mut T {
     type Pointee = T;
 }
-unsafe impl<T: ?Sized> BuiltinDeref for *const T {
+unsafe impl<T: PointeeSized> BuiltinDeref for *const T {
     type Pointee = T;
 }
 
-pub trait ChangePointee<U: ?Sized>: BuiltinDeref {
+pub trait ChangePointee<U: PointeeSized>: BuiltinDeref {
     type Output;
 }
-impl<'a, T: ?Sized + 'a, U: ?Sized + 'a> ChangePointee<U> for &'a mut T {
+impl<'a, T: PointeeSized + 'a, U: PointeeSized + 'a> ChangePointee<U> for &'a mut T {
     type Output = &'a mut U;
 }
-impl<'a, T: ?Sized + 'a, U: ?Sized + 'a> ChangePointee<U> for &'a T {
+impl<'a, T: PointeeSized + 'a, U: PointeeSized + 'a> ChangePointee<U> for &'a T {
     type Output = &'a U;
 }
-impl<T: ?Sized, U: ?Sized> ChangePointee<U> for *mut T {
+impl<T: PointeeSized, U: PointeeSized> ChangePointee<U> for *mut T {
     type Output = *mut U;
 }
-impl<T: ?Sized, U: ?Sized> ChangePointee<U> for *const T {
+impl<T: PointeeSized, U: PointeeSized> ChangePointee<U> for *const T {
     type Output = *const U;
 }
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index e0e80fc9b41..b5c3e91d046 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -54,7 +54,7 @@
 )]
 #![allow(missing_docs)]
 
-use crate::marker::{ConstParamTy, DiscriminantKind, Tuple};
+use crate::marker::{ConstParamTy, DiscriminantKind, PointeeSized, Tuple};
 use crate::ptr;
 
 mod bounds;
@@ -2740,7 +2740,7 @@ where
 #[unstable(feature = "core_intrinsics", issue = "none")]
 #[rustc_intrinsic_const_stable_indirect]
 #[rustc_intrinsic]
-pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(ptr: *const P) -> M;
+pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + PointeeSized, M>(ptr: *const P) -> M;
 
 /// This is an accidentally-stable alias to [`ptr::copy_nonoverlapping`]; use that instead.
 // Note (intentionally not in the doc comment): `ptr::copy_nonoverlapping` adds some extra
diff --git a/library/core/src/io/borrowed_buf.rs b/library/core/src/io/borrowed_buf.rs
index f86abf7f1e9..6bd9c18e00b 100644
--- a/library/core/src/io/borrowed_buf.rs
+++ b/library/core/src/io/borrowed_buf.rs
@@ -281,10 +281,10 @@ impl<'a> BorrowedCursor<'a> {
     /// Panics if there are less than `n` bytes initialized.
     #[inline]
     pub fn advance(&mut self, n: usize) -> &mut Self {
-        let filled = self.buf.filled.strict_add(n);
-        assert!(filled <= self.buf.init);
+        // The substraction cannot underflow by invariant of this type.
+        assert!(n <= self.buf.init - self.buf.filled);
 
-        self.buf.filled = filled;
+        self.buf.filled += n;
         self
     }
 
diff --git a/library/core/src/iter/sources/repeat_n.rs b/library/core/src/iter/sources/repeat_n.rs
index ada37b9af4c..c29ab24a083 100644
--- a/library/core/src/iter/sources/repeat_n.rs
+++ b/library/core/src/iter/sources/repeat_n.rs
@@ -1,8 +1,7 @@
 use crate::fmt;
 use crate::iter::{FusedIterator, TrustedLen, UncheckedIterator};
-use crate::mem::MaybeUninit;
 use crate::num::NonZero;
-use crate::ops::{NeverShortCircuit, Try};
+use crate::ops::Try;
 
 /// Creates a new iterator that repeats a single element a given number of times.
 ///
@@ -58,14 +57,20 @@ use crate::ops::{NeverShortCircuit, Try};
 #[inline]
 #[stable(feature = "iter_repeat_n", since = "1.82.0")]
 pub fn repeat_n<T: Clone>(element: T, count: usize) -> RepeatN<T> {
-    let element = if count == 0 {
-        // `element` gets dropped eagerly.
-        MaybeUninit::uninit()
-    } else {
-        MaybeUninit::new(element)
-    };
+    RepeatN { inner: RepeatNInner::new(element, count) }
+}
 
-    RepeatN { element, count }
+#[derive(Clone, Copy)]
+struct RepeatNInner<T> {
+    count: NonZero<usize>,
+    element: T,
+}
+
+impl<T> RepeatNInner<T> {
+    fn new(element: T, count: usize) -> Option<Self> {
+        let count = NonZero::<usize>::new(count)?;
+        Some(Self { element, count })
+    }
 }
 
 /// An iterator that repeats an element an exact number of times.
@@ -73,63 +78,27 @@ pub fn repeat_n<T: Clone>(element: T, count: usize) -> RepeatN<T> {
 /// This `struct` is created by the [`repeat_n()`] function.
 /// See its documentation for more.
 #[stable(feature = "iter_repeat_n", since = "1.82.0")]
+#[derive(Clone)]
 pub struct RepeatN<A> {
-    count: usize,
-    // Invariant: uninit iff count == 0.
-    element: MaybeUninit<A>,
+    inner: Option<RepeatNInner<A>>,
 }
 
 impl<A> RepeatN<A> {
-    /// Returns the element if it hasn't been dropped already.
-    fn element_ref(&self) -> Option<&A> {
-        if self.count > 0 {
-            // SAFETY: The count is non-zero, so it must be initialized.
-            Some(unsafe { self.element.assume_init_ref() })
-        } else {
-            None
-        }
-    }
     /// If we haven't already dropped the element, return it in an option.
-    ///
-    /// Clears the count so it won't be dropped again later.
     #[inline]
     fn take_element(&mut self) -> Option<A> {
-        if self.count > 0 {
-            self.count = 0;
-            // SAFETY: We just set count to zero so it won't be dropped again,
-            // and it used to be non-zero so it hasn't already been dropped.
-            let element = unsafe { self.element.assume_init_read() };
-            Some(element)
-        } else {
-            None
-        }
-    }
-}
-
-#[stable(feature = "iter_repeat_n", since = "1.82.0")]
-impl<A: Clone> Clone for RepeatN<A> {
-    fn clone(&self) -> RepeatN<A> {
-        RepeatN {
-            count: self.count,
-            element: self.element_ref().cloned().map_or_else(MaybeUninit::uninit, MaybeUninit::new),
-        }
+        self.inner.take().map(|inner| inner.element)
     }
 }
 
 #[stable(feature = "iter_repeat_n", since = "1.82.0")]
 impl<A: fmt::Debug> fmt::Debug for RepeatN<A> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_struct("RepeatN")
-            .field("count", &self.count)
-            .field("element", &self.element_ref())
-            .finish()
-    }
-}
-
-#[stable(feature = "iter_repeat_n", since = "1.82.0")]
-impl<A> Drop for RepeatN<A> {
-    fn drop(&mut self) {
-        self.take_element();
+        let (count, element) = match self.inner.as_ref() {
+            Some(inner) => (inner.count.get(), Some(&inner.element)),
+            None => (0, None),
+        };
+        f.debug_struct("RepeatN").field("count", &count).field("element", &element).finish()
     }
 }
 
@@ -139,12 +108,17 @@ impl<A: Clone> Iterator for RepeatN<A> {
 
     #[inline]
     fn next(&mut self) -> Option<A> {
-        if self.count > 0 {
-            // SAFETY: Just checked it's not empty
-            unsafe { Some(self.next_unchecked()) }
-        } else {
-            None
+        let inner = self.inner.as_mut()?;
+        let count = inner.count.get();
+
+        if let Some(decremented) = NonZero::<usize>::new(count - 1) {
+            // Order of these is important for optimization
+            let tmp = inner.element.clone();
+            inner.count = decremented;
+            return Some(tmp);
         }
+
+        return self.take_element();
     }
 
     #[inline]
@@ -155,52 +129,19 @@ impl<A: Clone> Iterator for RepeatN<A> {
 
     #[inline]
     fn advance_by(&mut self, skip: usize) -> Result<(), NonZero<usize>> {
-        let len = self.count;
+        let Some(inner) = self.inner.as_mut() else {
+            return NonZero::<usize>::new(skip).map(Err).unwrap_or(Ok(()));
+        };
 
-        if skip >= len {
-            self.take_element();
-        }
+        let len = inner.count.get();
 
-        if skip > len {
-            // SAFETY: we just checked that the difference is positive
-            Err(unsafe { NonZero::new_unchecked(skip - len) })
-        } else {
-            self.count = len - skip;
-            Ok(())
+        if let Some(new_len) = len.checked_sub(skip).and_then(NonZero::<usize>::new) {
+            inner.count = new_len;
+            return Ok(());
         }
-    }
 
-    fn try_fold<B, F, R>(&mut self, mut acc: B, mut f: F) -> R
-    where
-        F: FnMut(B, A) -> R,
-        R: Try<Output = B>,
-    {
-        if self.count > 0 {
-            while self.count > 1 {
-                self.count -= 1;
-                // SAFETY: the count was larger than 1, so the element is
-                // initialized and hasn't been dropped.
-                acc = f(acc, unsafe { self.element.assume_init_ref().clone() })?;
-            }
-
-            // We could just set the count to zero directly, but doing it this
-            // way should make it easier for the optimizer to fold this tail
-            // into the loop when `clone()` is equivalent to copying.
-            self.count -= 1;
-            // SAFETY: we just set the count to zero from one, so the element
-            // is still initialized, has not been dropped yet and will not be
-            // accessed by future calls.
-            f(acc, unsafe { self.element.assume_init_read() })
-        } else {
-            try { acc }
-        }
-    }
-
-    fn fold<B, F>(mut self, init: B, f: F) -> B
-    where
-        F: FnMut(B, A) -> B,
-    {
-        self.try_fold(init, NeverShortCircuit::wrap_mut_2(f)).0
+        self.inner = None;
+        return NonZero::<usize>::new(skip - len).map(Err).unwrap_or(Ok(()));
     }
 
     #[inline]
@@ -217,7 +158,7 @@ impl<A: Clone> Iterator for RepeatN<A> {
 #[stable(feature = "iter_repeat_n", since = "1.82.0")]
 impl<A: Clone> ExactSizeIterator for RepeatN<A> {
     fn len(&self) -> usize {
-        self.count
+        self.inner.as_ref().map(|inner| inner.count.get()).unwrap_or(0)
     }
 }
 
@@ -262,20 +203,4 @@ impl<A: Clone> FusedIterator for RepeatN<A> {}
 #[unstable(feature = "trusted_len", issue = "37572")]
 unsafe impl<A: Clone> TrustedLen for RepeatN<A> {}
 #[stable(feature = "iter_repeat_n", since = "1.82.0")]
-impl<A: Clone> UncheckedIterator for RepeatN<A> {
-    #[inline]
-    unsafe fn next_unchecked(&mut self) -> Self::Item {
-        // SAFETY: The caller promised the iterator isn't empty
-        self.count = unsafe { self.count.unchecked_sub(1) };
-        if self.count == 0 {
-            // SAFETY: the check above ensured that the count used to be non-zero,
-            // so element hasn't been dropped yet, and we just lowered the count to
-            // zero so it won't be dropped later, and thus it's okay to take it here.
-            unsafe { self.element.assume_init_read() }
-        } else {
-            // SAFETY: the count is non-zero, so it must have not been dropped yet.
-            let element = unsafe { self.element.assume_init_ref() };
-            A::clone(element)
-        }
-    }
-}
+impl<A: Clone> UncheckedIterator for RepeatN<A> {}
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 9991b76cd0a..0cc5640941a 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -93,15 +93,15 @@ pub unsafe auto trait Send {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> !Send for *const T {}
+impl<T: PointeeSized> !Send for *const T {}
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> !Send for *mut T {}
+impl<T: PointeeSized> !Send for *mut T {}
 
 // Most instances arise automatically, but this instance is needed to link up `T: Sync` with
 // `&T: Send` (and it also removes the unsound default instance `T Send` -> `&T: Send` that would
 // otherwise exist).
 #[stable(feature = "rust1", since = "1.0.0")]
-unsafe impl<T: Sync + ?Sized> Send for &T {}
+unsafe impl<T: Sync + PointeeSized> Send for &T {}
 
 /// Types with a constant size known at compile time.
 ///
@@ -151,11 +151,48 @@ unsafe impl<T: Sync + ?Sized> Send for &T {}
 #[rustc_specialization_trait]
 #[rustc_deny_explicit_impl]
 #[rustc_do_not_implement_via_object]
+// `Sized` being coinductive, despite having supertraits, is okay as there are no user-written impls,
+// and we know that the supertraits are always implemented if the subtrait is just by looking at
+// the builtin impls.
 #[rustc_coinductive]
-pub trait Sized {
+pub trait Sized: MetaSized {
     // Empty.
 }
 
+/// Types with a size that can be determined from pointer metadata.
+#[unstable(feature = "sized_hierarchy", issue = "none")]
+#[lang = "meta_sized"]
+#[diagnostic::on_unimplemented(
+    message = "the size for values of type `{Self}` cannot be known",
+    label = "doesn't have a known size"
+)]
+#[fundamental]
+#[rustc_specialization_trait]
+#[rustc_deny_explicit_impl]
+#[rustc_do_not_implement_via_object]
+// `MetaSized` being coinductive, despite having supertraits, is okay for the same reasons as
+// `Sized` above.
+#[rustc_coinductive]
+pub trait MetaSized: PointeeSized {
+    // Empty
+}
+
+/// Types that may or may not have a size.
+#[unstable(feature = "sized_hierarchy", issue = "none")]
+#[lang = "pointee_sized"]
+#[diagnostic::on_unimplemented(
+    message = "values of type `{Self}` may or may not have a size",
+    label = "may or may not have a known size"
+)]
+#[fundamental]
+#[rustc_specialization_trait]
+#[rustc_deny_explicit_impl]
+#[rustc_do_not_implement_via_object]
+#[rustc_coinductive]
+pub trait PointeeSized {
+    // Empty
+}
+
 /// Types that can be "unsized" to a dynamically-sized type.
 ///
 /// For example, the sized array type `[i8; 2]` implements `Unsize<[i8]>` and
@@ -192,7 +229,7 @@ pub trait Sized {
 #[lang = "unsize"]
 #[rustc_deny_explicit_impl]
 #[rustc_do_not_implement_via_object]
-pub trait Unsize<T: ?Sized> {
+pub trait Unsize<T: PointeeSized>: PointeeSized {
     // Empty.
 }
 
@@ -229,7 +266,7 @@ marker_impls! {
         (),
         {T, const N: usize} [T; N],
         {T} [T],
-        {T: ?Sized} &T,
+        {T: PointeeSized} &T,
 }
 
 /// Types whose values can be duplicated simply by copying bits.
@@ -442,8 +479,8 @@ marker_impls! {
         isize, i8, i16, i32, i64, i128,
         f16, f32, f64, f128,
         bool, char,
-        {T: ?Sized} *const T,
-        {T: ?Sized} *mut T,
+        {T: PointeeSized} *const T,
+        {T: PointeeSized} *mut T,
 
 }
 
@@ -452,7 +489,7 @@ impl Copy for ! {}
 
 /// Shared references can be copied, but mutable references *cannot*!
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> Copy for &T {}
+impl<T: PointeeSized> Copy for &T {}
 
 /// Marker trait for the types that are allowed in union fields and unsafe
 /// binder types.
@@ -636,9 +673,9 @@ pub unsafe auto trait Sync {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> !Sync for *const T {}
+impl<T: PointeeSized> !Sync for *const T {}
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> !Sync for *mut T {}
+impl<T: PointeeSized> !Sync for *mut T {}
 
 /// Zero-sized type used to mark things that "act like" they own a `T`.
 ///
@@ -775,57 +812,57 @@ impl<T: ?Sized> !Sync for *mut T {}
 /// [drop check]: Drop#drop-check
 #[lang = "phantom_data"]
 #[stable(feature = "rust1", since = "1.0.0")]
-pub struct PhantomData<T: ?Sized>;
+pub struct PhantomData<T: PointeeSized>;
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> Hash for PhantomData<T> {
+impl<T: PointeeSized> Hash for PhantomData<T> {
     #[inline]
     fn hash<H: Hasher>(&self, _: &mut H) {}
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> cmp::PartialEq for PhantomData<T> {
+impl<T: PointeeSized> cmp::PartialEq for PhantomData<T> {
     fn eq(&self, _other: &PhantomData<T>) -> bool {
         true
     }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> cmp::Eq for PhantomData<T> {}
+impl<T: PointeeSized> cmp::Eq for PhantomData<T> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> cmp::PartialOrd for PhantomData<T> {
+impl<T: PointeeSized> cmp::PartialOrd for PhantomData<T> {
     fn partial_cmp(&self, _other: &PhantomData<T>) -> Option<cmp::Ordering> {
         Option::Some(cmp::Ordering::Equal)
     }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> cmp::Ord for PhantomData<T> {
+impl<T: PointeeSized> cmp::Ord for PhantomData<T> {
     fn cmp(&self, _other: &PhantomData<T>) -> cmp::Ordering {
         cmp::Ordering::Equal
     }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> Copy for PhantomData<T> {}
+impl<T: PointeeSized> Copy for PhantomData<T> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> Clone for PhantomData<T> {
+impl<T: PointeeSized> Clone for PhantomData<T> {
     fn clone(&self) -> Self {
         Self
     }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> Default for PhantomData<T> {
+impl<T: PointeeSized> Default for PhantomData<T> {
     fn default() -> Self {
         Self
     }
 }
 
 #[unstable(feature = "structural_match", issue = "31434")]
-impl<T: ?Sized> StructuralPartialEq for PhantomData<T> {}
+impl<T: PointeeSized> StructuralPartialEq for PhantomData<T> {}
 
 /// Compiler-internal trait used to indicate the type of enum discriminants.
 ///
@@ -868,15 +905,15 @@ pub trait DiscriminantKind {
 pub unsafe auto trait Freeze {}
 
 #[unstable(feature = "freeze", issue = "121675")]
-impl<T: ?Sized> !Freeze for UnsafeCell<T> {}
+impl<T: PointeeSized> !Freeze for UnsafeCell<T> {}
 marker_impls! {
     #[unstable(feature = "freeze", issue = "121675")]
     unsafe Freeze for
-        {T: ?Sized} PhantomData<T>,
-        {T: ?Sized} *const T,
-        {T: ?Sized} *mut T,
-        {T: ?Sized} &T,
-        {T: ?Sized} &mut T,
+        {T: PointeeSized} PhantomData<T>,
+        {T: PointeeSized} *const T,
+        {T: PointeeSized} *mut T,
+        {T: PointeeSized} &T,
+        {T: PointeeSized} &mut T,
 }
 
 /// Used to determine whether a type contains any `UnsafePinned` (or `PhantomPinned`) internally,
@@ -991,15 +1028,15 @@ impl !UnsafeUnpin for PhantomPinned {}
 marker_impls! {
     #[stable(feature = "pin", since = "1.33.0")]
     Unpin for
-        {T: ?Sized} &T,
-        {T: ?Sized} &mut T,
+        {T: PointeeSized} &T,
+        {T: PointeeSized} &mut T,
 }
 
 marker_impls! {
     #[stable(feature = "pin_raw", since = "1.38.0")]
     Unpin for
-        {T: ?Sized} *const T,
-        {T: ?Sized} *mut T,
+        {T: PointeeSized} *const T,
+        {T: PointeeSized} *mut T,
 }
 
 /// A marker for types that can be dropped.
diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs
index e74f5443ac2..9d9d18095bc 100644
--- a/library/core/src/ops/deref.rs
+++ b/library/core/src/ops/deref.rs
@@ -1,3 +1,5 @@
+use crate::marker::PointeeSized;
+
 /// Used for immutable dereferencing operations, like `*v`.
 ///
 /// In addition to being used for explicit dereferencing operations with the
@@ -135,7 +137,7 @@
 #[rustc_diagnostic_item = "Deref"]
 #[const_trait]
 #[rustc_const_unstable(feature = "const_deref", issue = "88955")]
-pub trait Deref {
+pub trait Deref: PointeeSized {
     /// The resulting type after dereferencing.
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_diagnostic_item = "deref_target"]
@@ -267,7 +269,7 @@ impl<T: ?Sized> const Deref for &mut T {
 #[stable(feature = "rust1", since = "1.0.0")]
 #[const_trait]
 #[rustc_const_unstable(feature = "const_deref", issue = "88955")]
-pub trait DerefMut: ~const Deref {
+pub trait DerefMut: ~const Deref + PointeeSized {
     /// Mutably dereferences the value.
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_diagnostic_item = "deref_mut_method"]
@@ -293,7 +295,7 @@ impl<T: ?Sized> const DerefMut for &mut T {
 /// unchanged.
 #[unstable(feature = "deref_pure_trait", issue = "87121")]
 #[lang = "deref_pure"]
-pub unsafe trait DerefPure {}
+pub unsafe trait DerefPure: PointeeSized {}
 
 #[unstable(feature = "deref_pure_trait", issue = "87121")]
 unsafe impl<T: ?Sized> DerefPure for &T {}
@@ -366,7 +368,7 @@ unsafe impl<T: ?Sized> DerefPure for &mut T {}
 /// ```
 #[lang = "receiver"]
 #[unstable(feature = "arbitrary_self_types", issue = "44874")]
-pub trait Receiver {
+pub trait Receiver: PointeeSized {
     /// The target type on which the method may be called.
     #[rustc_diagnostic_item = "receiver_target"]
     #[lang = "receiver_target"]
@@ -393,12 +395,12 @@ where
 #[lang = "legacy_receiver"]
 #[unstable(feature = "legacy_receiver_trait", issue = "none")]
 #[doc(hidden)]
-pub trait LegacyReceiver {
+pub trait LegacyReceiver: PointeeSized {
     // Empty.
 }
 
 #[unstable(feature = "legacy_receiver_trait", issue = "none")]
-impl<T: ?Sized> LegacyReceiver for &T {}
+impl<T: PointeeSized> LegacyReceiver for &T {}
 
 #[unstable(feature = "legacy_receiver_trait", issue = "none")]
-impl<T: ?Sized> LegacyReceiver for &mut T {}
+impl<T: PointeeSized> LegacyReceiver for &mut T {}
diff --git a/library/core/src/ops/unsize.rs b/library/core/src/ops/unsize.rs
index d2a07197f6f..f0781ee01fd 100644
--- a/library/core/src/ops/unsize.rs
+++ b/library/core/src/ops/unsize.rs
@@ -1,4 +1,4 @@
-use crate::marker::Unsize;
+use crate::marker::{PointeeSized, Unsize};
 
 /// Trait that indicates that this is a pointer or a wrapper for one,
 /// where unsizing can be performed on the pointee.
@@ -33,40 +33,40 @@ use crate::marker::Unsize;
 /// [nomicon-coerce]: ../../nomicon/coercions.html
 #[unstable(feature = "coerce_unsized", issue = "18598")]
 #[lang = "coerce_unsized"]
-pub trait CoerceUnsized<T: ?Sized> {
+pub trait CoerceUnsized<T: PointeeSized> {
     // Empty.
 }
 
 // &mut T -> &mut U
 #[unstable(feature = "coerce_unsized", issue = "18598")]
-impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
+impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a mut U> for &'a mut T {}
 // &mut T -> &U
 #[unstable(feature = "coerce_unsized", issue = "18598")]
-impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {}
+impl<'a, 'b: 'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a U> for &'b mut T {}
 // &mut T -> *mut U
 #[unstable(feature = "coerce_unsized", issue = "18598")]
-impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {}
+impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*mut U> for &'a mut T {}
 // &mut T -> *const U
 #[unstable(feature = "coerce_unsized", issue = "18598")]
-impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {}
+impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*const U> for &'a mut T {}
 
 // &T -> &U
 #[unstable(feature = "coerce_unsized", issue = "18598")]
-impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
+impl<'a, 'b: 'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a U> for &'b T {}
 // &T -> *const U
 #[unstable(feature = "coerce_unsized", issue = "18598")]
-impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for &'a T {}
+impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*const U> for &'a T {}
 
 // *mut T -> *mut U
 #[unstable(feature = "coerce_unsized", issue = "18598")]
-impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
+impl<T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*mut U> for *mut T {}
 // *mut T -> *const U
 #[unstable(feature = "coerce_unsized", issue = "18598")]
-impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *mut T {}
+impl<T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*const U> for *mut T {}
 
 // *const T -> *const U
 #[unstable(feature = "coerce_unsized", issue = "18598")]
-impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
+impl<T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<*const U> for *const T {}
 
 /// `DispatchFromDyn` is used in the implementation of dyn-compatibility[^1] checks (specifically
 /// allowing arbitrary self types), to guarantee that a method's receiver type can be dispatched on.
@@ -122,13 +122,13 @@ pub trait DispatchFromDyn<T> {
 
 // &T -> &U
 #[unstable(feature = "dispatch_from_dyn", issue = "none")]
-impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
+impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<&'a U> for &'a T {}
 // &mut T -> &mut U
 #[unstable(feature = "dispatch_from_dyn", issue = "none")]
-impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
+impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<&'a mut U> for &'a mut T {}
 // *const T -> *const U
 #[unstable(feature = "dispatch_from_dyn", issue = "none")]
-impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
+impl<T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<*const U> for *const T {}
 // *mut T -> *mut U
 #[unstable(feature = "dispatch_from_dyn", issue = "none")]
-impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
+impl<T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<*mut U> for *mut T {}
diff --git a/library/core/src/panic/location.rs b/library/core/src/panic/location.rs
index 94cfd667ffa..f1eedede8aa 100644
--- a/library/core/src/panic/location.rs
+++ b/library/core/src/panic/location.rs
@@ -30,7 +30,7 @@ use crate::fmt;
 /// Files are compared as strings, not `Path`, which could be unexpected.
 /// See [`Location::file`]'s documentation for more discussion.
 #[lang = "panic_location"]
-#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
 #[stable(feature = "panic_hooks", since = "1.10.0")]
 pub struct Location<'a> {
     // Note: this filename will have exactly one nul byte at its end, but otherwise
@@ -43,6 +43,17 @@ pub struct Location<'a> {
     col: u32,
 }
 
+#[stable(feature = "panic_hooks", since = "1.10.0")]
+impl fmt::Debug for Location<'_> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Location")
+            .field("file", &self.file())
+            .field("line", &self.line)
+            .field("column", &self.col)
+            .finish()
+    }
+}
+
 impl<'a> Location<'a> {
     /// Returns the source location of the caller of this function. If that function's caller is
     /// annotated then its call location will be returned, and so on up the stack to the first call
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 9366cb36c6e..800eb74babb 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -4,7 +4,7 @@ use crate::intrinsics::const_eval_select;
 use crate::mem::{self, SizedTypeProperties};
 use crate::slice::{self, SliceIndex};
 
-impl<T: ?Sized> *const T {
+impl<T: PointeeSized> *const T {
     #[doc = include_str!("docs/is_null.md")]
     ///
     /// # Examples
@@ -129,7 +129,7 @@ impl<T: ?Sized> *const T {
     #[inline]
     pub const fn with_metadata_of<U>(self, meta: *const U) -> *const U
     where
-        U: ?Sized,
+        U: PointeeSized,
     {
         from_raw_parts::<U>(self as *const (), metadata(meta))
     }
@@ -1586,7 +1586,7 @@ impl<T, const N: usize> *const [T; N] {
 
 /// Pointer equality is by address, as produced by the [`<*const T>::addr`](pointer::addr) method.
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> PartialEq for *const T {
+impl<T: PointeeSized> PartialEq for *const T {
     #[inline]
     #[allow(ambiguous_wide_pointer_comparisons)]
     fn eq(&self, other: &*const T) -> bool {
@@ -1596,11 +1596,11 @@ impl<T: ?Sized> PartialEq for *const T {
 
 /// Pointer equality is an equivalence relation.
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> Eq for *const T {}
+impl<T: PointeeSized> Eq for *const T {}
 
 /// Pointer comparison is by address, as produced by the `[`<*const T>::addr`](pointer::addr)` method.
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> Ord for *const T {
+impl<T: PointeeSized> Ord for *const T {
     #[inline]
     #[allow(ambiguous_wide_pointer_comparisons)]
     fn cmp(&self, other: &*const T) -> Ordering {
@@ -1616,7 +1616,7 @@ impl<T: ?Sized> Ord for *const T {
 
 /// Pointer comparison is by address, as produced by the `[`<*const T>::addr`](pointer::addr)` method.
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> PartialOrd for *const T {
+impl<T: PointeeSized> PartialOrd for *const T {
     #[inline]
     #[allow(ambiguous_wide_pointer_comparisons)]
     fn partial_cmp(&self, other: &*const T) -> Option<Ordering> {
diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs
index 9c5da306e27..0deac3621e8 100644
--- a/library/core/src/ptr/metadata.rs
+++ b/library/core/src/ptr/metadata.rs
@@ -3,7 +3,7 @@
 use crate::fmt;
 use crate::hash::{Hash, Hasher};
 use crate::intrinsics::{aggregate_raw_ptr, ptr_metadata};
-use crate::marker::Freeze;
+use crate::marker::{Freeze, PointeeSized};
 use crate::ptr::NonNull;
 
 /// Provides the pointer metadata type of any pointed-to type.
@@ -55,7 +55,7 @@ use crate::ptr::NonNull;
 #[lang = "pointee_trait"]
 #[rustc_deny_explicit_impl]
 #[rustc_do_not_implement_via_object]
-pub trait Pointee {
+pub trait Pointee: PointeeSized {
     /// The type for metadata in pointers and references to `Self`.
     #[lang = "metadata_type"]
     // NOTE: Keep trait bounds in `static_assert_expected_bounds_for_metadata`
@@ -81,7 +81,7 @@ pub trait Pointee {
 /// ```
 #[unstable(feature = "ptr_metadata", issue = "81513")]
 // NOTE: don’t stabilize this before trait aliases are stable in the language?
-pub trait Thin = Pointee<Metadata = ()>;
+pub trait Thin = Pointee<Metadata = ()> + PointeeSized;
 
 /// Extracts the metadata component of a pointer.
 ///
@@ -96,7 +96,7 @@ pub trait Thin = Pointee<Metadata = ()>;
 /// assert_eq!(std::ptr::metadata("foo"), 3_usize);
 /// ```
 #[inline]
-pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
+pub const fn metadata<T: PointeeSized>(ptr: *const T) -> <T as Pointee>::Metadata {
     ptr_metadata(ptr)
 }
 
@@ -109,7 +109,7 @@ pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
 /// [`slice::from_raw_parts`]: crate::slice::from_raw_parts
 #[unstable(feature = "ptr_metadata", issue = "81513")]
 #[inline]
-pub const fn from_raw_parts<T: ?Sized>(
+pub const fn from_raw_parts<T: PointeeSized>(
     data_pointer: *const impl Thin,
     metadata: <T as Pointee>::Metadata,
 ) -> *const T {
@@ -122,7 +122,7 @@ pub const fn from_raw_parts<T: ?Sized>(
 /// See the documentation of [`from_raw_parts`] for more details.
 #[unstable(feature = "ptr_metadata", issue = "81513")]
 #[inline]
-pub const fn from_raw_parts_mut<T: ?Sized>(
+pub const fn from_raw_parts_mut<T: PointeeSized>(
     data_pointer: *mut impl Thin,
     metadata: <T as Pointee>::Metadata,
 ) -> *mut T {
@@ -152,7 +152,7 @@ pub const fn from_raw_parts_mut<T: ?Sized>(
 /// duplicated in multiple codegen units), and pointers to vtables of *different* types/traits can
 /// compare equal (since identical vtables can be deduplicated within a codegen unit).
 #[lang = "dyn_metadata"]
-pub struct DynMetadata<Dyn: ?Sized> {
+pub struct DynMetadata<Dyn: PointeeSized> {
     _vtable_ptr: NonNull<VTable>,
     _phantom: crate::marker::PhantomData<Dyn>,
 }
@@ -165,7 +165,7 @@ unsafe extern "C" {
     type VTable;
 }
 
-impl<Dyn: ?Sized> DynMetadata<Dyn> {
+impl<Dyn: PointeeSized> DynMetadata<Dyn> {
     /// When `DynMetadata` appears as the metadata field of a wide pointer, the rustc_middle layout
     /// computation does magic and the resulting layout is *not* a `FieldsShape::Aggregate`, instead
     /// it is a `FieldsShape::Primitive`. This means that the same type can have different layout
@@ -206,10 +206,10 @@ impl<Dyn: ?Sized> DynMetadata<Dyn> {
     }
 }
 
-unsafe impl<Dyn: ?Sized> Send for DynMetadata<Dyn> {}
-unsafe impl<Dyn: ?Sized> Sync for DynMetadata<Dyn> {}
+unsafe impl<Dyn: PointeeSized> Send for DynMetadata<Dyn> {}
+unsafe impl<Dyn: PointeeSized> Sync for DynMetadata<Dyn> {}
 
-impl<Dyn: ?Sized> fmt::Debug for DynMetadata<Dyn> {
+impl<Dyn: PointeeSized> fmt::Debug for DynMetadata<Dyn> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_tuple("DynMetadata").field(&self.vtable_ptr()).finish()
     }
@@ -217,27 +217,27 @@ impl<Dyn: ?Sized> fmt::Debug for DynMetadata<Dyn> {
 
 // Manual impls needed to avoid `Dyn: $Trait` bounds.
 
-impl<Dyn: ?Sized> Unpin for DynMetadata<Dyn> {}
+impl<Dyn: PointeeSized> Unpin for DynMetadata<Dyn> {}
 
-impl<Dyn: ?Sized> Copy for DynMetadata<Dyn> {}
+impl<Dyn: PointeeSized> Copy for DynMetadata<Dyn> {}
 
-impl<Dyn: ?Sized> Clone for DynMetadata<Dyn> {
+impl<Dyn: PointeeSized> Clone for DynMetadata<Dyn> {
     #[inline]
     fn clone(&self) -> Self {
         *self
     }
 }
 
-impl<Dyn: ?Sized> Eq for DynMetadata<Dyn> {}
+impl<Dyn: PointeeSized> Eq for DynMetadata<Dyn> {}
 
-impl<Dyn: ?Sized> PartialEq for DynMetadata<Dyn> {
+impl<Dyn: PointeeSized> PartialEq for DynMetadata<Dyn> {
     #[inline]
     fn eq(&self, other: &Self) -> bool {
         crate::ptr::eq::<VTable>(self.vtable_ptr(), other.vtable_ptr())
     }
 }
 
-impl<Dyn: ?Sized> Ord for DynMetadata<Dyn> {
+impl<Dyn: PointeeSized> Ord for DynMetadata<Dyn> {
     #[inline]
     #[allow(ambiguous_wide_pointer_comparisons)]
     fn cmp(&self, other: &Self) -> crate::cmp::Ordering {
@@ -245,14 +245,14 @@ impl<Dyn: ?Sized> Ord for DynMetadata<Dyn> {
     }
 }
 
-impl<Dyn: ?Sized> PartialOrd for DynMetadata<Dyn> {
+impl<Dyn: PointeeSized> PartialOrd for DynMetadata<Dyn> {
     #[inline]
     fn partial_cmp(&self, other: &Self) -> Option<crate::cmp::Ordering> {
         Some(self.cmp(other))
     }
 }
 
-impl<Dyn: ?Sized> Hash for DynMetadata<Dyn> {
+impl<Dyn: PointeeSized> Hash for DynMetadata<Dyn> {
     #[inline]
     fn hash<H: Hasher>(&self, hasher: &mut H) {
         crate::ptr::hash::<VTable, _>(self.vtable_ptr(), hasher)
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 81bf6778b05..fe8c6f83034 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -398,7 +398,7 @@
 
 use crate::cmp::Ordering;
 use crate::intrinsics::const_eval_select;
-use crate::marker::FnPtr;
+use crate::marker::{FnPtr, PointeeSized};
 use crate::mem::{self, MaybeUninit, SizedTypeProperties};
 use crate::num::NonZero;
 use crate::{fmt, hash, intrinsics, ub_checks};
@@ -796,7 +796,7 @@ pub const unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
 #[lang = "drop_in_place"]
 #[allow(unconditional_recursion)]
 #[rustc_diagnostic_item = "ptr_drop_in_place"]
-pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+pub unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T) {
     // Code here does not matter - this is replaced by the
     // real drop glue by the compiler.
 
@@ -825,7 +825,7 @@ pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
 #[rustc_promotable]
 #[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
 #[rustc_diagnostic_item = "ptr_null"]
-pub const fn null<T: ?Sized + Thin>() -> *const T {
+pub const fn null<T: PointeeSized + Thin>() -> *const T {
     from_raw_parts(without_provenance::<()>(0), ())
 }
 
@@ -850,7 +850,7 @@ pub const fn null<T: ?Sized + Thin>() -> *const T {
 #[rustc_promotable]
 #[rustc_const_stable(feature = "const_ptr_null", since = "1.24.0")]
 #[rustc_diagnostic_item = "ptr_null_mut"]
-pub const fn null_mut<T: ?Sized + Thin>() -> *mut T {
+pub const fn null_mut<T: PointeeSized + Thin>() -> *mut T {
     from_raw_parts_mut(without_provenance_mut::<()>(0), ())
 }
 
@@ -1068,7 +1068,7 @@ pub fn with_exposed_provenance_mut<T>(addr: usize) -> *mut T {
 #[rustc_const_stable(feature = "ptr_from_ref", since = "1.76.0")]
 #[rustc_never_returns_null_ptr]
 #[rustc_diagnostic_item = "ptr_from_ref"]
-pub const fn from_ref<T: ?Sized>(r: &T) -> *const T {
+pub const fn from_ref<T: PointeeSized>(r: &T) -> *const T {
     r
 }
 
@@ -1118,7 +1118,7 @@ pub const fn from_ref<T: ?Sized>(r: &T) -> *const T {
 #[stable(feature = "ptr_from_ref", since = "1.76.0")]
 #[rustc_const_stable(feature = "ptr_from_ref", since = "1.76.0")]
 #[rustc_never_returns_null_ptr]
-pub const fn from_mut<T: ?Sized>(r: &mut T) -> *mut T {
+pub const fn from_mut<T: PointeeSized>(r: &mut T) -> *mut T {
     r
 }
 
@@ -2419,7 +2419,7 @@ pub(crate) unsafe fn align_offset<T: Sized>(p: *const T, a: usize) -> usize {
 #[must_use = "pointer comparison produces a value"]
 #[rustc_diagnostic_item = "ptr_eq"]
 #[allow(ambiguous_wide_pointer_comparisons)] // it's actually clear here
-pub fn eq<T: ?Sized>(a: *const T, b: *const T) -> bool {
+pub fn eq<T: PointeeSized>(a: *const T, b: *const T) -> bool {
     a == b
 }
 
@@ -2443,7 +2443,7 @@ pub fn eq<T: ?Sized>(a: *const T, b: *const T) -> bool {
 #[stable(feature = "ptr_addr_eq", since = "1.76.0")]
 #[inline(always)]
 #[must_use = "pointer comparison produces a value"]
-pub fn addr_eq<T: ?Sized, U: ?Sized>(p: *const T, q: *const U) -> bool {
+pub fn addr_eq<T: PointeeSized, U: PointeeSized>(p: *const T, q: *const U) -> bool {
     (p as *const ()) == (q as *const ())
 }
 
@@ -2526,7 +2526,7 @@ pub fn fn_addr_eq<T: FnPtr, U: FnPtr>(f: T, g: U) -> bool {
 /// assert_eq!(actual, expected);
 /// ```
 #[stable(feature = "ptr_hash", since = "1.35.0")]
-pub fn hash<T: ?Sized, S: hash::Hasher>(hashee: *const T, into: &mut S) {
+pub fn hash<T: PointeeSized, S: hash::Hasher>(hashee: *const T, into: &mut S) {
     use crate::hash::Hash;
     hashee.hash(into);
 }
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index efe1031b79c..6b436184f20 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -1,10 +1,11 @@
 use super::*;
 use crate::cmp::Ordering::{Equal, Greater, Less};
 use crate::intrinsics::const_eval_select;
+use crate::marker::PointeeSized;
 use crate::mem::{self, SizedTypeProperties};
 use crate::slice::{self, SliceIndex};
 
-impl<T: ?Sized> *mut T {
+impl<T: PointeeSized> *mut T {
     #[doc = include_str!("docs/is_null.md")]
     ///
     /// # Examples
@@ -110,7 +111,7 @@ impl<T: ?Sized> *mut T {
     #[inline]
     pub const fn with_metadata_of<U>(self, meta: *const U) -> *mut U
     where
-        U: ?Sized,
+        U: PointeeSized,
     {
         from_raw_parts_mut::<U>(self as *mut (), metadata(meta))
     }
@@ -2006,7 +2007,7 @@ impl<T, const N: usize> *mut [T; N] {
 
 /// Pointer equality is by address, as produced by the [`<*mut T>::addr`](pointer::addr) method.
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> PartialEq for *mut T {
+impl<T: PointeeSized> PartialEq for *mut T {
     #[inline(always)]
     #[allow(ambiguous_wide_pointer_comparisons)]
     fn eq(&self, other: &*mut T) -> bool {
@@ -2016,11 +2017,11 @@ impl<T: ?Sized> PartialEq for *mut T {
 
 /// Pointer equality is an equivalence relation.
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> Eq for *mut T {}
+impl<T: PointeeSized> Eq for *mut T {}
 
 /// Pointer comparison is by address, as produced by the [`<*mut T>::addr`](pointer::addr) method.
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> Ord for *mut T {
+impl<T: PointeeSized> Ord for *mut T {
     #[inline]
     #[allow(ambiguous_wide_pointer_comparisons)]
     fn cmp(&self, other: &*mut T) -> Ordering {
@@ -2036,7 +2037,7 @@ impl<T: ?Sized> Ord for *mut T {
 
 /// Pointer comparison is by address, as produced by the [`<*mut T>::addr`](pointer::addr) method.
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: ?Sized> PartialOrd for *mut T {
+impl<T: PointeeSized> PartialOrd for *mut T {
     #[inline(always)]
     #[allow(ambiguous_wide_pointer_comparisons)]
     fn partial_cmp(&self, other: &*mut T) -> Option<Ordering> {
diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs
index 1fae5b83902..282ad32553c 100644
--- a/library/core/src/ptr/non_null.rs
+++ b/library/core/src/ptr/non_null.rs
@@ -1,5 +1,5 @@
 use crate::cmp::Ordering;
-use crate::marker::Unsize;
+use crate::marker::{PointeeSized, Unsize};
 use crate::mem::{MaybeUninit, SizedTypeProperties};
 use crate::num::NonZero;
 use crate::ops::{CoerceUnsized, DispatchFromDyn};
@@ -20,19 +20,24 @@ use crate::{fmt, hash, intrinsics, mem, ptr};
 /// as a discriminant -- `Option<NonNull<T>>` has the same size as `*mut T`.
 /// However the pointer may still dangle if it isn't dereferenced.
 ///
-/// Unlike `*mut T`, `NonNull<T>` was chosen to be covariant over `T`. This makes it
-/// possible to use `NonNull<T>` when building covariant types, but introduces the
-/// risk of unsoundness if used in a type that shouldn't actually be covariant.
-/// (The opposite choice was made for `*mut T` even though technically the unsoundness
-/// could only be caused by calling unsafe functions.)
+/// Unlike `*mut T`, `NonNull<T>` is covariant over `T`. This is usually the correct
+/// choice for most data structures and safe abstractions, such as `Box`, `Rc`, `Arc`, `Vec`,
+/// and `LinkedList`.
 ///
-/// Covariance is correct for most safe abstractions, such as `Box`, `Rc`, `Arc`, `Vec`,
-/// and `LinkedList`. This is the case because they provide a public API that follows the
-/// normal shared XOR mutable rules of Rust.
+/// In rare cases, if your type exposes a way to mutate the value of `T` through a `NonNull<T>`,
+/// and you need to prevent unsoundness from variance (for example, if `T` could be a reference
+/// with a shorter lifetime), you should add a field to make your type invariant, such as
+/// `PhantomData<Cell<T>>` or `PhantomData<&'a mut T>`.
 ///
-/// If your type cannot safely be covariant, you must ensure it contains some
-/// additional field to provide invariance. Often this field will be a [`PhantomData`]
-/// type like `PhantomData<Cell<T>>` or `PhantomData<&'a mut T>`.
+/// Example of a type that must be invariant:
+/// ```rust
+/// use std::cell::Cell;
+/// use std::marker::PhantomData;
+/// struct Invariant<T> {
+///     ptr: std::ptr::NonNull<T>,
+///     _invariant: PhantomData<Cell<T>>,
+/// }
+/// ```
 ///
 /// Notice that `NonNull<T>` has a `From` instance for `&T`. However, this does
 /// not change the fact that mutating through a (pointer derived from a) shared
@@ -67,7 +72,7 @@ use crate::{fmt, hash, intrinsics, mem, ptr};
 #[rustc_layout_scalar_valid_range_start(1)]
 #[rustc_nonnull_optimization_guaranteed]
 #[rustc_diagnostic_item = "NonNull"]
-pub struct NonNull<T: ?Sized> {
+pub struct NonNull<T: PointeeSized> {
     // Remember to use `.as_ptr()` instead of `.pointer`, as field projecting to
     // this is banned by <https://github.com/rust-lang/compiler-team/issues/807>.
     pointer: *const T,
@@ -76,12 +81,12 @@ pub struct NonNull<T: ?Sized> {
 /// `NonNull` pointers are not `Send` because the data they reference may be aliased.
 // N.B., this impl is unnecessary, but should provide better error messages.
 #[stable(feature = "nonnull", since = "1.25.0")]
-impl<T: ?Sized> !Send for NonNull<T> {}
+impl<T: PointeeSized> !Send for NonNull<T> {}
 
 /// `NonNull` pointers are not `Sync` because the data they reference may be aliased.
 // N.B., this impl is unnecessary, but should provide better error messages.
 #[stable(feature = "nonnull", since = "1.25.0")]
-impl<T: ?Sized> !Sync for NonNull<T> {}
+impl<T: PointeeSized> !Sync for NonNull<T> {}
 
 impl<T: Sized> NonNull<T> {
     /// Creates a pointer with the given address and no [provenance][crate::ptr#provenance].
@@ -190,7 +195,7 @@ impl<T: Sized> NonNull<T> {
     }
 }
 
-impl<T: ?Sized> NonNull<T> {
+impl<T: PointeeSized> NonNull<T> {
     /// Creates a new `NonNull`.
     ///
     /// # Safety
@@ -1604,7 +1609,7 @@ impl<T> NonNull<[T]> {
 }
 
 #[stable(feature = "nonnull", since = "1.25.0")]
-impl<T: ?Sized> Clone for NonNull<T> {
+impl<T: PointeeSized> Clone for NonNull<T> {
     #[inline(always)]
     fn clone(&self) -> Self {
         *self
@@ -1612,39 +1617,39 @@ impl<T: ?Sized> Clone for NonNull<T> {
 }
 
 #[stable(feature = "nonnull", since = "1.25.0")]
-impl<T: ?Sized> Copy for NonNull<T> {}
+impl<T: PointeeSized> Copy for NonNull<T> {}
 
 #[unstable(feature = "coerce_unsized", issue = "18598")]
-impl<T: ?Sized, U: ?Sized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
+impl<T: PointeeSized, U: PointeeSized> CoerceUnsized<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
 
 #[unstable(feature = "dispatch_from_dyn", issue = "none")]
-impl<T: ?Sized, U: ?Sized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
+impl<T: PointeeSized, U: PointeeSized> DispatchFromDyn<NonNull<U>> for NonNull<T> where T: Unsize<U> {}
 
 #[stable(feature = "pin", since = "1.33.0")]
-unsafe impl<T: ?Sized> PinCoerceUnsized for NonNull<T> {}
+unsafe impl<T: PointeeSized> PinCoerceUnsized for NonNull<T> {}
 
 #[unstable(feature = "pointer_like_trait", issue = "none")]
 impl<T> core::marker::PointerLike for NonNull<T> {}
 
 #[stable(feature = "nonnull", since = "1.25.0")]
-impl<T: ?Sized> fmt::Debug for NonNull<T> {
+impl<T: PointeeSized> fmt::Debug for NonNull<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt::Pointer::fmt(&self.as_ptr(), f)
     }
 }
 
 #[stable(feature = "nonnull", since = "1.25.0")]
-impl<T: ?Sized> fmt::Pointer for NonNull<T> {
+impl<T: PointeeSized> fmt::Pointer for NonNull<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt::Pointer::fmt(&self.as_ptr(), f)
     }
 }
 
 #[stable(feature = "nonnull", since = "1.25.0")]
-impl<T: ?Sized> Eq for NonNull<T> {}
+impl<T: PointeeSized> Eq for NonNull<T> {}
 
 #[stable(feature = "nonnull", since = "1.25.0")]
-impl<T: ?Sized> PartialEq for NonNull<T> {
+impl<T: PointeeSized> PartialEq for NonNull<T> {
     #[inline]
     #[allow(ambiguous_wide_pointer_comparisons)]
     fn eq(&self, other: &Self) -> bool {
@@ -1653,7 +1658,7 @@ impl<T: ?Sized> PartialEq for NonNull<T> {
 }
 
 #[stable(feature = "nonnull", since = "1.25.0")]
-impl<T: ?Sized> Ord for NonNull<T> {
+impl<T: PointeeSized> Ord for NonNull<T> {
     #[inline]
     #[allow(ambiguous_wide_pointer_comparisons)]
     fn cmp(&self, other: &Self) -> Ordering {
@@ -1662,7 +1667,7 @@ impl<T: ?Sized> Ord for NonNull<T> {
 }
 
 #[stable(feature = "nonnull", since = "1.25.0")]
-impl<T: ?Sized> PartialOrd for NonNull<T> {
+impl<T: PointeeSized> PartialOrd for NonNull<T> {
     #[inline]
     #[allow(ambiguous_wide_pointer_comparisons)]
     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
@@ -1671,7 +1676,7 @@ impl<T: ?Sized> PartialOrd for NonNull<T> {
 }
 
 #[stable(feature = "nonnull", since = "1.25.0")]
-impl<T: ?Sized> hash::Hash for NonNull<T> {
+impl<T: PointeeSized> hash::Hash for NonNull<T> {
     #[inline]
     fn hash<H: hash::Hasher>(&self, state: &mut H) {
         self.as_ptr().hash(state)
@@ -1679,7 +1684,7 @@ impl<T: ?Sized> hash::Hash for NonNull<T> {
 }
 
 #[unstable(feature = "ptr_internals", issue = "none")]
-impl<T: ?Sized> From<Unique<T>> for NonNull<T> {
+impl<T: PointeeSized> From<Unique<T>> for NonNull<T> {
     #[inline]
     fn from(unique: Unique<T>) -> Self {
         unique.as_non_null_ptr()
@@ -1687,7 +1692,7 @@ impl<T: ?Sized> From<Unique<T>> for NonNull<T> {
 }
 
 #[stable(feature = "nonnull", since = "1.25.0")]
-impl<T: ?Sized> From<&mut T> for NonNull<T> {
+impl<T: PointeeSized> From<&mut T> for NonNull<T> {
     /// Converts a `&mut T` to a `NonNull<T>`.
     ///
     /// This conversion is safe and infallible since references cannot be null.
@@ -1698,7 +1703,7 @@ impl<T: ?Sized> From<&mut T> for NonNull<T> {
 }
 
 #[stable(feature = "nonnull", since = "1.25.0")]
-impl<T: ?Sized> From<&T> for NonNull<T> {
+impl<T: PointeeSized> From<&T> for NonNull<T> {
     /// Converts a `&T` to a `NonNull<T>`.
     ///
     /// This conversion is safe and infallible since references cannot be null.
diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs
index d688ce2a07a..c069314ff7d 100644
--- a/library/core/src/ptr/unique.rs
+++ b/library/core/src/ptr/unique.rs
@@ -1,5 +1,5 @@
 use crate::fmt;
-use crate::marker::{PhantomData, Unsize};
+use crate::marker::{PhantomData, PointeeSized, Unsize};
 use crate::ops::{CoerceUnsized, DispatchFromDyn};
 use crate::pin::PinCoerceUnsized;
 use crate::ptr::NonNull;
@@ -34,7 +34,7 @@ use crate::ptr::NonNull;
 #[repr(transparent)]
 // Lang item used experimentally by Miri to define the semantics of `Unique`.
 #[lang = "ptr_unique"]
-pub struct Unique<T: ?Sized> {
+pub struct Unique<T: PointeeSized> {
     pointer: NonNull<T>,
     // NOTE: this marker has no consequences for variance, but is necessary
     // for dropck to understand that we logically own a `T`.
@@ -49,14 +49,14 @@ pub struct Unique<T: ?Sized> {
 /// unenforced by the type system; the abstraction using the
 /// `Unique` must enforce it.
 #[unstable(feature = "ptr_internals", issue = "none")]
-unsafe impl<T: Send + ?Sized> Send for Unique<T> {}
+unsafe impl<T: Send + PointeeSized> Send for Unique<T> {}
 
 /// `Unique` pointers are `Sync` if `T` is `Sync` because the data they
 /// reference is unaliased. Note that this aliasing invariant is
 /// unenforced by the type system; the abstraction using the
 /// `Unique` must enforce it.
 #[unstable(feature = "ptr_internals", issue = "none")]
-unsafe impl<T: Sync + ?Sized> Sync for Unique<T> {}
+unsafe impl<T: Sync + PointeeSized> Sync for Unique<T> {}
 
 #[unstable(feature = "ptr_internals", issue = "none")]
 impl<T: Sized> Unique<T> {
@@ -78,7 +78,7 @@ impl<T: Sized> Unique<T> {
 }
 
 #[unstable(feature = "ptr_internals", issue = "none")]
-impl<T: ?Sized> Unique<T> {
+impl<T: PointeeSized> Unique<T> {
     /// Creates a new `Unique`.
     ///
     /// # Safety
@@ -157,7 +157,7 @@ impl<T: ?Sized> Unique<T> {
 }
 
 #[unstable(feature = "ptr_internals", issue = "none")]
-impl<T: ?Sized> Clone for Unique<T> {
+impl<T: PointeeSized> Clone for Unique<T> {
     #[inline]
     fn clone(&self) -> Self {
         *self
@@ -165,33 +165,33 @@ impl<T: ?Sized> Clone for Unique<T> {
 }
 
 #[unstable(feature = "ptr_internals", issue = "none")]
-impl<T: ?Sized> Copy for Unique<T> {}
+impl<T: PointeeSized> Copy for Unique<T> {}
 
 #[unstable(feature = "ptr_internals", issue = "none")]
-impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}
+impl<T: PointeeSized, U: PointeeSized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}
 
 #[unstable(feature = "ptr_internals", issue = "none")]
-impl<T: ?Sized, U: ?Sized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> {}
+impl<T: PointeeSized, U: PointeeSized> DispatchFromDyn<Unique<U>> for Unique<T> where T: Unsize<U> {}
 
 #[unstable(feature = "pin_coerce_unsized_trait", issue = "123430")]
-unsafe impl<T: ?Sized> PinCoerceUnsized for Unique<T> {}
+unsafe impl<T: PointeeSized> PinCoerceUnsized for Unique<T> {}
 
 #[unstable(feature = "ptr_internals", issue = "none")]
-impl<T: ?Sized> fmt::Debug for Unique<T> {
+impl<T: PointeeSized> fmt::Debug for Unique<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt::Pointer::fmt(&self.as_ptr(), f)
     }
 }
 
 #[unstable(feature = "ptr_internals", issue = "none")]
-impl<T: ?Sized> fmt::Pointer for Unique<T> {
+impl<T: PointeeSized> fmt::Pointer for Unique<T> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt::Pointer::fmt(&self.as_ptr(), f)
     }
 }
 
 #[unstable(feature = "ptr_internals", issue = "none")]
-impl<T: ?Sized> From<&mut T> for Unique<T> {
+impl<T: PointeeSized> From<&mut T> for Unique<T> {
     /// Converts a `&mut T` to a `Unique<T>`.
     ///
     /// This conversion is infallible since references cannot be null.
@@ -202,7 +202,7 @@ impl<T: ?Sized> From<&mut T> for Unique<T> {
 }
 
 #[unstable(feature = "ptr_internals", issue = "none")]
-impl<T: ?Sized> From<NonNull<T>> for Unique<T> {
+impl<T: PointeeSized> From<NonNull<T>> for Unique<T> {
     /// Converts a `NonNull<T>` to a `Unique<T>`.
     ///
     /// This conversion is infallible since `NonNull` cannot be null.
diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs
index 02eb805ece1..3ff55792431 100644
--- a/library/core/src/tuple.rs
+++ b/library/core/src/tuple.rs
@@ -1,7 +1,7 @@
 // See core/src/primitive_docs.rs for documentation.
 
 use crate::cmp::Ordering::{self, *};
-use crate::marker::{ConstParamTy_, StructuralPartialEq, UnsizedConstParamTy};
+use crate::marker::{ConstParamTy_, PointeeSized, StructuralPartialEq, UnsizedConstParamTy};
 use crate::ops::ControlFlow::{self, Break, Continue};
 
 // Recursive macro for implementing n-ary tuple functions and operations
@@ -25,7 +25,7 @@ macro_rules! tuple_impls {
             #[stable(feature = "rust1", since = "1.0.0")]
             impl<$($T: PartialEq),+> PartialEq for ($($T,)+)
             where
-                last_type!($($T,)+): ?Sized
+                last_type!($($T,)+): PointeeSized
             {
                 #[inline]
                 fn eq(&self, other: &($($T,)+)) -> bool {
@@ -43,7 +43,7 @@ macro_rules! tuple_impls {
             #[stable(feature = "rust1", since = "1.0.0")]
             impl<$($T: Eq),+> Eq for ($($T,)+)
             where
-                last_type!($($T,)+): ?Sized
+                last_type!($($T,)+): PointeeSized
             {}
         }
 
@@ -73,7 +73,7 @@ macro_rules! tuple_impls {
             #[stable(feature = "rust1", since = "1.0.0")]
             impl<$($T: PartialOrd),+> PartialOrd for ($($T,)+)
             where
-                last_type!($($T,)+): ?Sized
+                last_type!($($T,)+): PointeeSized
             {
                 #[inline]
                 fn partial_cmp(&self, other: &($($T,)+)) -> Option<Ordering> {
@@ -119,7 +119,7 @@ macro_rules! tuple_impls {
             #[stable(feature = "rust1", since = "1.0.0")]
             impl<$($T: Ord),+> Ord for ($($T,)+)
             where
-                last_type!($($T,)+): ?Sized
+                last_type!($($T,)+): PointeeSized
             {
                 #[inline]
                 fn cmp(&self, other: &($($T,)+)) -> Ordering {
diff --git a/library/coretests/tests/panic/location.rs b/library/coretests/tests/panic/location.rs
index d20241d8380..5ce0b06e90e 100644
--- a/library/coretests/tests/panic/location.rs
+++ b/library/coretests/tests/panic/location.rs
@@ -29,3 +29,11 @@ fn location_const_column() {
     const COLUMN: u32 = CALLER.column();
     assert_eq!(COLUMN, 40);
 }
+
+#[test]
+fn location_debug() {
+    let f = format!("{:?}", Location::caller());
+    assert!(f.contains(&format!("{:?}", file!())));
+    assert!(f.contains("35"));
+    assert!(f.contains("29"));
+}
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index 32c306be94e..b0084edf2f8 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -45,6 +45,7 @@ mod diagnostic;
 mod escape;
 mod to_tokens;
 
+use core::ops::BitOr;
 use std::ffi::CStr;
 use std::ops::{Range, RangeBounds};
 use std::path::PathBuf;
@@ -237,7 +238,7 @@ impl Default for TokenStream {
 }
 
 #[unstable(feature = "proc_macro_quote", issue = "54722")]
-pub use quote::{quote, quote_span};
+pub use quote::{HasIterator, RepInterp, ThereIsNoIteratorInRepetition, ext, quote, quote_span};
 
 fn tree_to_bridge_tree(
     tree: TokenTree,
diff --git a/library/proc_macro/src/quote.rs b/library/proc_macro/src/quote.rs
index bcb15912bb6..dbb55cd9fb3 100644
--- a/library/proc_macro/src/quote.rs
+++ b/library/proc_macro/src/quote.rs
@@ -5,9 +5,183 @@
 //! items from `proc_macro`, to build a `proc_macro::TokenStream`.
 
 use crate::{
-    Delimiter, Group, Ident, Literal, Punct, Spacing, Span, ToTokens, TokenStream, TokenTree,
+    BitOr, Delimiter, Group, Ident, Literal, Punct, Spacing, Span, ToTokens, TokenStream, TokenTree,
 };
 
+#[doc(hidden)]
+pub struct HasIterator; // True
+#[doc(hidden)]
+pub struct ThereIsNoIteratorInRepetition; // False
+
+impl BitOr<ThereIsNoIteratorInRepetition> for ThereIsNoIteratorInRepetition {
+    type Output = ThereIsNoIteratorInRepetition;
+    fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> ThereIsNoIteratorInRepetition {
+        ThereIsNoIteratorInRepetition
+    }
+}
+
+impl BitOr<ThereIsNoIteratorInRepetition> for HasIterator {
+    type Output = HasIterator;
+    fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> HasIterator {
+        HasIterator
+    }
+}
+
+impl BitOr<HasIterator> for ThereIsNoIteratorInRepetition {
+    type Output = HasIterator;
+    fn bitor(self, _rhs: HasIterator) -> HasIterator {
+        HasIterator
+    }
+}
+
+impl BitOr<HasIterator> for HasIterator {
+    type Output = HasIterator;
+    fn bitor(self, _rhs: HasIterator) -> HasIterator {
+        HasIterator
+    }
+}
+
+/// Extension traits used by the implementation of `quote!`. These are defined
+/// in separate traits, rather than as a single trait due to ambiguity issues.
+///
+/// These traits expose a `quote_into_iter` method which should allow calling
+/// whichever impl happens to be applicable. Calling that method repeatedly on
+/// the returned value should be idempotent.
+#[doc(hidden)]
+pub mod ext {
+    use core::slice;
+    use std::collections::btree_set::{self, BTreeSet};
+
+    use super::{
+        HasIterator as HasIter, RepInterp, ThereIsNoIteratorInRepetition as DoesNotHaveIter,
+    };
+    use crate::ToTokens;
+
+    /// Extension trait providing the `quote_into_iter` method on iterators.
+    #[doc(hidden)]
+    pub trait RepIteratorExt: Iterator + Sized {
+        fn quote_into_iter(self) -> (Self, HasIter) {
+            (self, HasIter)
+        }
+    }
+
+    impl<T: Iterator> RepIteratorExt for T {}
+
+    /// Extension trait providing the `quote_into_iter` method for
+    /// non-iterable types. These types interpolate the same value in each
+    /// iteration of the repetition.
+    #[doc(hidden)]
+    pub trait RepToTokensExt {
+        /// Pretend to be an iterator for the purposes of `quote_into_iter`.
+        /// This allows repeated calls to `quote_into_iter` to continue
+        /// correctly returning DoesNotHaveIter.
+        fn next(&self) -> Option<&Self> {
+            Some(self)
+        }
+
+        fn quote_into_iter(&self) -> (&Self, DoesNotHaveIter) {
+            (self, DoesNotHaveIter)
+        }
+    }
+
+    impl<T: ToTokens + ?Sized> RepToTokensExt for T {}
+
+    /// Extension trait providing the `quote_into_iter` method for types that
+    /// can be referenced as an iterator.
+    #[doc(hidden)]
+    pub trait RepAsIteratorExt<'q> {
+        type Iter: Iterator;
+
+        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter);
+    }
+
+    impl<'q, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &T {
+        type Iter = T::Iter;
+
+        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
+            <T as RepAsIteratorExt>::quote_into_iter(*self)
+        }
+    }
+
+    impl<'q, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &mut T {
+        type Iter = T::Iter;
+
+        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
+            <T as RepAsIteratorExt>::quote_into_iter(*self)
+        }
+    }
+
+    impl<'q, T: 'q> RepAsIteratorExt<'q> for [T] {
+        type Iter = slice::Iter<'q, T>;
+
+        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
+            (self.iter(), HasIter)
+        }
+    }
+
+    impl<'q, T: 'q, const N: usize> RepAsIteratorExt<'q> for [T; N] {
+        type Iter = slice::Iter<'q, T>;
+
+        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
+            (self.iter(), HasIter)
+        }
+    }
+
+    impl<'q, T: 'q> RepAsIteratorExt<'q> for Vec<T> {
+        type Iter = slice::Iter<'q, T>;
+
+        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
+            (self.iter(), HasIter)
+        }
+    }
+
+    impl<'q, T: 'q> RepAsIteratorExt<'q> for BTreeSet<T> {
+        type Iter = btree_set::Iter<'q, T>;
+
+        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
+            (self.iter(), HasIter)
+        }
+    }
+
+    impl<'q, T: RepAsIteratorExt<'q>> RepAsIteratorExt<'q> for RepInterp<T> {
+        type Iter = T::Iter;
+
+        fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) {
+            self.0.quote_into_iter()
+        }
+    }
+}
+
+// Helper type used within interpolations to allow for repeated binding names.
+// Implements the relevant traits, and exports a dummy `next()` method.
+#[derive(Copy, Clone)]
+#[doc(hidden)]
+pub struct RepInterp<T>(pub T);
+
+impl<T> RepInterp<T> {
+    // This method is intended to look like `Iterator::next`, and is called when
+    // a name is bound multiple times, as the previous binding will shadow the
+    // original `Iterator` object. This allows us to avoid advancing the
+    // iterator multiple times per iteration.
+    pub fn next(self) -> Option<T> {
+        Some(self.0)
+    }
+}
+
+impl<T: Iterator> Iterator for RepInterp<T> {
+    type Item = T::Item;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.0.next()
+    }
+}
+
+impl<T: ToTokens> ToTokens for RepInterp<T> {
+    fn to_tokens(&self, tokens: &mut TokenStream) {
+        self.0.to_tokens(tokens);
+    }
+}
+
 macro_rules! minimal_quote_tt {
     (($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, minimal_quote!($($t)*)) };
     ([$($t:tt)*]) => { Group::new(Delimiter::Bracket, minimal_quote!($($t)*)) };
@@ -20,7 +194,13 @@ macro_rules! minimal_quote_tt {
     (>) => { Punct::new('>', Spacing::Alone) };
     (&) => { Punct::new('&', Spacing::Alone) };
     (=) => { Punct::new('=', Spacing::Alone) };
+    (#) => { Punct::new('#', Spacing::Alone) };
+    (|) => { Punct::new('|', Spacing::Alone) };
+    (:) => { Punct::new(':', Spacing::Alone) };
+    (*) => { Punct::new('*', Spacing::Alone) };
+    (_) => { Ident::new("_", Span::def_site()) };
     ($i:ident) => { Ident::new(stringify!($i), Span::def_site()) };
+    ($lit:literal) => { stringify!($lit).parse::<Literal>().unwrap() };
 }
 
 macro_rules! minimal_quote_ts {
@@ -36,6 +216,39 @@ macro_rules! minimal_quote_ts {
             [c.0, c.1].into_iter().collect::<TokenStream>()
         }
     };
+    (=>) => {
+        {
+            let mut c = (
+                TokenTree::from(Punct::new('=', Spacing::Joint)),
+                TokenTree::from(Punct::new('>', Spacing::Alone))
+            );
+            c.0.set_span(Span::def_site());
+            c.1.set_span(Span::def_site());
+            [c.0, c.1].into_iter().collect::<TokenStream>()
+        }
+    };
+    (+=) => {
+        {
+            let mut c = (
+                TokenTree::from(Punct::new('+', Spacing::Joint)),
+                TokenTree::from(Punct::new('=', Spacing::Alone))
+            );
+            c.0.set_span(Span::def_site());
+            c.1.set_span(Span::def_site());
+            [c.0, c.1].into_iter().collect::<TokenStream>()
+        }
+    };
+    (!=) => {
+        {
+            let mut c = (
+                TokenTree::from(Punct::new('!', Spacing::Joint)),
+                TokenTree::from(Punct::new('=', Spacing::Alone))
+            );
+            c.0.set_span(Span::def_site());
+            c.1.set_span(Span::def_site());
+            [c.0, c.1].into_iter().collect::<TokenStream>()
+        }
+    };
     ($t:tt) => { TokenTree::from(minimal_quote_tt!($t)) };
 }
 
@@ -71,17 +284,99 @@ pub fn quote(stream: TokenStream) -> TokenStream {
     let mut after_dollar = false;
 
     let mut tokens = crate::TokenStream::new();
-    for tree in stream {
+    let mut iter = stream.into_iter().peekable();
+    while let Some(tree) = iter.next() {
         if after_dollar {
             after_dollar = false;
             match tree {
+                TokenTree::Group(tt) => {
+                    // Handles repetition by expanding `$( CONTENTS ) SEP_OPT *` to `{ REP_EXPANDED }`.
+                    let contents = tt.stream();
+
+                    // The `*` token is also consumed here.
+                    let sep_opt: Option<Punct> = match (iter.next(), iter.peek()) {
+                        (Some(TokenTree::Punct(sep)), Some(TokenTree::Punct(star)))
+                            if sep.spacing() == Spacing::Joint && star.as_char() == '*' =>
+                        {
+                            iter.next();
+                            Some(sep)
+                        }
+                        (Some(TokenTree::Punct(star)), _) if star.as_char() == '*' => None,
+                        _ => panic!("`$(...)` must be followed by `*` in `quote!`"),
+                    };
+
+                    let mut rep_expanded = TokenStream::new();
+
+                    // Append setup code for a `while`, where recursively quoted `CONTENTS`
+                    // and `SEP_OPT` are repeatedly processed, to `REP_EXPANDED`.
+                    let meta_vars = collect_meta_vars(contents.clone());
+                    minimal_quote!(
+                        use crate::ext::*;
+                        (@ if sep_opt.is_some() {
+                            minimal_quote!(let mut _i = 0usize;)
+                        } else {
+                            minimal_quote!(();)
+                        })
+                        let has_iter = crate::ThereIsNoIteratorInRepetition;
+                    )
+                    .to_tokens(&mut rep_expanded);
+                    for meta_var in &meta_vars {
+                        minimal_quote!(
+                            #[allow(unused_mut)]
+                            let (mut (@ meta_var), i) = (@ meta_var).quote_into_iter();
+                            let has_iter = has_iter | i;
+                        )
+                        .to_tokens(&mut rep_expanded);
+                    }
+                    minimal_quote!(let _: crate::HasIterator = has_iter;)
+                        .to_tokens(&mut rep_expanded);
+
+                    // Append the `while` to `REP_EXPANDED`.
+                    let mut while_body = TokenStream::new();
+                    for meta_var in &meta_vars {
+                        minimal_quote!(
+                            let (@ meta_var) = match (@ meta_var).next() {
+                                Some(_x) => crate::RepInterp(_x),
+                                None => break,
+                            };
+                        )
+                        .to_tokens(&mut while_body);
+                    }
+                    minimal_quote!(
+                        (@ if let Some(sep) = sep_opt {
+                            minimal_quote!(
+                                if _i > 0 {
+                                    (@ minimal_quote!(crate::ToTokens::to_tokens(&crate::TokenTree::Punct(crate::Punct::new(
+                                        (@ TokenTree::from(Literal::character(sep.as_char()))),
+                                        (@ minimal_quote!(crate::Spacing::Alone)),
+                                    )), &mut ts);))
+                                }
+                                _i += 1;
+                            )
+                        } else {
+                            minimal_quote!(();)
+                        })
+                        (@ quote(contents.clone())).to_tokens(&mut ts);
+                    )
+                        .to_tokens(&mut while_body);
+                    rep_expanded.extend(vec![
+                        TokenTree::Ident(Ident::new("while", Span::call_site())),
+                        TokenTree::Ident(Ident::new("true", Span::call_site())),
+                        TokenTree::Group(Group::new(Delimiter::Brace, while_body)),
+                    ]);
+
+                    minimal_quote!((@ TokenTree::Group(Group::new(Delimiter::Brace, rep_expanded)))).to_tokens(&mut tokens);
+                    continue;
+                }
                 TokenTree::Ident(_) => {
                     minimal_quote!(crate::ToTokens::to_tokens(&(@ tree), &mut ts);)
                         .to_tokens(&mut tokens);
                     continue;
                 }
                 TokenTree::Punct(ref tt) if tt.as_char() == '$' => {}
-                _ => panic!("`$` must be followed by an ident or `$` in `quote!`"),
+                _ => panic!(
+                    "`$` must be followed by an ident or `$` or a repetition group in `quote!`"
+                ),
             }
         } else if let TokenTree::Punct(ref tt) = tree {
             if tt.as_char() == '$' {
@@ -155,6 +450,33 @@ pub fn quote(stream: TokenStream) -> TokenStream {
     }
 }
 
+/// Helper function to support macro repetitions like `$( CONTENTS ) SEP_OPT *` in `quote!`.
+/// Recursively collects all `Ident`s (meta-variables) that follow a `$`
+/// from the given `CONTENTS` stream, preserving their order of appearance.
+fn collect_meta_vars(content_stream: TokenStream) -> Vec<Ident> {
+    fn helper(stream: TokenStream, out: &mut Vec<Ident>) {
+        let mut iter = stream.into_iter().peekable();
+        while let Some(tree) = iter.next() {
+            match &tree {
+                TokenTree::Punct(tt) if tt.as_char() == '$' => {
+                    if let Some(TokenTree::Ident(id)) = iter.peek() {
+                        out.push(id.clone());
+                        iter.next();
+                    }
+                }
+                TokenTree::Group(tt) => {
+                    helper(tt.stream(), out);
+                }
+                _ => {}
+            }
+        }
+    }
+
+    let mut vars = Vec::new();
+    helper(content_stream, &mut vars);
+    vars
+}
+
 /// Quote a `Span` into a `TokenStream`.
 /// This is needed to implement a custom quoter.
 #[unstable(feature = "proc_macro_quote", issue = "54722")]
diff --git a/library/rtstartup/rsbegin.rs b/library/rtstartup/rsbegin.rs
index 67b09599d9d..0e915b92697 100644
--- a/library/rtstartup/rsbegin.rs
+++ b/library/rtstartup/rsbegin.rs
@@ -21,8 +21,21 @@
 #![allow(internal_features)]
 #![warn(unreachable_pub)]
 
+#[cfg(not(bootstrap))]
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[cfg(not(bootstrap))]
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
+#[cfg(bootstrap)]
+#[lang = "sized"]
+pub trait Sized {}
+#[cfg(not(bootstrap))]
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
+
 #[lang = "sync"]
 auto trait Sync {}
 #[lang = "copy"]
@@ -30,14 +43,25 @@ trait Copy {}
 #[lang = "freeze"]
 auto trait Freeze {}
 
+#[cfg(bootstrap)]
 impl<T: ?Sized> Copy for *mut T {}
+#[cfg(not(bootstrap))]
+impl<T: PointeeSized> Copy for *mut T {}
 
+#[cfg(bootstrap)]
 #[lang = "drop_in_place"]
 #[inline]
 #[allow(unconditional_recursion)]
 pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     drop_in_place(to_drop);
 }
+#[cfg(not(bootstrap))]
+#[lang = "drop_in_place"]
+#[inline]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T) {
+    drop_in_place(to_drop);
+}
 
 // Frame unwind info registration
 //
diff --git a/library/rtstartup/rsend.rs b/library/rtstartup/rsend.rs
index a6f7d103356..75f9212695d 100644
--- a/library/rtstartup/rsend.rs
+++ b/library/rtstartup/rsend.rs
@@ -8,8 +8,21 @@
 #![allow(internal_features)]
 #![warn(unreachable_pub)]
 
+#[cfg(not(bootstrap))]
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[cfg(not(bootstrap))]
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
+#[cfg(bootstrap)]
+#[lang = "sized"]
+pub trait Sized {}
+#[cfg(not(bootstrap))]
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
+
 #[lang = "sync"]
 trait Sync {}
 impl<T> Sync for T {}
@@ -18,14 +31,25 @@ trait Copy {}
 #[lang = "freeze"]
 auto trait Freeze {}
 
+#[cfg(bootstrap)]
 impl<T: ?Sized> Copy for *mut T {}
+#[cfg(not(bootstrap))]
+impl<T: PointeeSized> Copy for *mut T {}
 
+#[cfg(bootstrap)]
 #[lang = "drop_in_place"]
 #[inline]
 #[allow(unconditional_recursion)]
 pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
     drop_in_place(to_drop);
 }
+#[cfg(not(bootstrap))]
+#[lang = "drop_in_place"]
+#[inline]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T) {
+    drop_in_place(to_drop);
+}
 
 #[cfg(all(target_os = "windows", target_arch = "x86", target_env = "gnu"))]
 pub mod eh_frames {
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 0cd794fd3ef..865ea620a28 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -121,7 +121,7 @@ pub struct File {
 ///
 /// [`try_lock`]: File::try_lock
 /// [`try_lock_shared`]: File::try_lock_shared
-#[unstable(feature = "file_lock", issue = "130994")]
+#[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")]
 pub enum TryLockError {
     /// The lock could not be acquired due to an I/O error on the file. The standard library will
     /// not return an [`ErrorKind::WouldBlock`] error inside [`TryLockError::Error`]
@@ -366,10 +366,10 @@ pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result
     inner(path.as_ref(), contents.as_ref())
 }
 
-#[unstable(feature = "file_lock", issue = "130994")]
+#[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")]
 impl error::Error for TryLockError {}
 
-#[unstable(feature = "file_lock", issue = "130994")]
+#[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")]
 impl fmt::Debug for TryLockError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
@@ -379,7 +379,7 @@ impl fmt::Debug for TryLockError {
     }
 }
 
-#[unstable(feature = "file_lock", issue = "130994")]
+#[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")]
 impl fmt::Display for TryLockError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
@@ -390,7 +390,7 @@ impl fmt::Display for TryLockError {
     }
 }
 
-#[unstable(feature = "file_lock", issue = "130994")]
+#[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")]
 impl From<TryLockError> for io::Error {
     fn from(err: TryLockError) -> io::Error {
         match err {
@@ -713,7 +713,6 @@ impl File {
     /// # Examples
     ///
     /// ```no_run
-    /// #![feature(file_lock)]
     /// use std::fs::File;
     ///
     /// fn main() -> std::io::Result<()> {
@@ -722,7 +721,7 @@ impl File {
     ///     Ok(())
     /// }
     /// ```
-    #[unstable(feature = "file_lock", issue = "130994")]
+    #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")]
     pub fn lock(&self) -> io::Result<()> {
         self.inner.lock()
     }
@@ -766,7 +765,6 @@ impl File {
     /// # Examples
     ///
     /// ```no_run
-    /// #![feature(file_lock)]
     /// use std::fs::File;
     ///
     /// fn main() -> std::io::Result<()> {
@@ -775,7 +773,7 @@ impl File {
     ///     Ok(())
     /// }
     /// ```
-    #[unstable(feature = "file_lock", issue = "130994")]
+    #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")]
     pub fn lock_shared(&self) -> io::Result<()> {
         self.inner.lock_shared()
     }
@@ -824,7 +822,6 @@ impl File {
     /// # Examples
     ///
     /// ```no_run
-    /// #![feature(file_lock)]
     /// use std::fs::{File, TryLockError};
     ///
     /// fn main() -> std::io::Result<()> {
@@ -840,7 +837,7 @@ impl File {
     ///     Ok(())
     /// }
     /// ```
-    #[unstable(feature = "file_lock", issue = "130994")]
+    #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")]
     pub fn try_lock(&self) -> Result<(), TryLockError> {
         self.inner.try_lock()
     }
@@ -888,7 +885,6 @@ impl File {
     /// # Examples
     ///
     /// ```no_run
-    /// #![feature(file_lock)]
     /// use std::fs::{File, TryLockError};
     ///
     /// fn main() -> std::io::Result<()> {
@@ -905,7 +901,7 @@ impl File {
     ///     Ok(())
     /// }
     /// ```
-    #[unstable(feature = "file_lock", issue = "130994")]
+    #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")]
     pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
         self.inner.try_lock_shared()
     }
@@ -933,7 +929,6 @@ impl File {
     /// # Examples
     ///
     /// ```no_run
-    /// #![feature(file_lock)]
     /// use std::fs::File;
     ///
     /// fn main() -> std::io::Result<()> {
@@ -943,7 +938,7 @@ impl File {
     ///     Ok(())
     /// }
     /// ```
-    #[unstable(feature = "file_lock", issue = "130994")]
+    #[stable(feature = "file_lock", since = "CURRENT_RUSTC_VERSION")]
     pub fn unlock(&self) -> io::Result<()> {
         self.inner.unlock()
     }
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 826d9f0f39d..0469db0814c 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -1882,6 +1882,19 @@ impl FromStr for PathBuf {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<P: AsRef<Path>> FromIterator<P> for PathBuf {
+    /// Creates a new `PathBuf` from the [`Path`] elements of an iterator.
+    ///
+    /// This uses [`push`](Self::push) to add each element, so can be used to adjoin multiple path
+    /// [components](Components).
+    ///
+    /// # Examples
+    /// ```
+    /// # use std::path::PathBuf;
+    /// let path = PathBuf::from_iter(["/tmp", "foo", "bar"]);
+    /// assert_eq!(path, PathBuf::from("/tmp/foo/bar"));
+    /// ```
+    ///
+    /// See documentation for [`push`](Self::push) for more details on how the path is constructed.
     fn from_iter<I: IntoIterator<Item = P>>(iter: I) -> PathBuf {
         let mut buf = PathBuf::new();
         buf.extend(iter);
@@ -1891,6 +1904,20 @@ impl<P: AsRef<Path>> FromIterator<P> for PathBuf {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<P: AsRef<Path>> Extend<P> for PathBuf {
+    /// Extends `self` with [`Path`] elements from `iter`.
+    ///
+    /// This uses [`push`](Self::push) to add each element, so can be used to adjoin multiple path
+    /// [components](Components).
+    ///
+    /// # Examples
+    /// ```
+    /// # use std::path::PathBuf;
+    /// let mut path = PathBuf::from("/tmp");
+    /// path.extend(["foo", "bar", "file.txt"]);
+    /// assert_eq!(path, PathBuf::from("/tmp/foo/bar/file.txt"));
+    /// ```
+    ///
+    /// See documentation for [`push`](Self::push) for more details on how the path is constructed.
     fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) {
         iter.into_iter().for_each(move |p| self.push(p.as_ref()));
     }
diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs
index ac1c5e9932e..53dec105d0c 100644
--- a/library/std/src/sys/pal/windows/c.rs
+++ b/library/std/src/sys/pal/windows/c.rs
@@ -119,6 +119,23 @@ unsafe extern "system" {
     pub fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL;
 }
 
+windows_targets::link!("ntdll.dll" "system" fn NtCreateNamedPipeFile(
+    filehandle: *mut HANDLE,
+    desiredaccess: FILE_ACCESS_RIGHTS,
+    objectattributes: *const OBJECT_ATTRIBUTES,
+    iostatusblock: *mut IO_STATUS_BLOCK,
+    shareaccess: FILE_SHARE_MODE,
+    createdisposition: NTCREATEFILE_CREATE_DISPOSITION,
+    createoptions: NTCREATEFILE_CREATE_OPTIONS,
+    namedpipetype: u32,
+    readmode: u32,
+    completionmode: u32,
+    maximuminstances: u32,
+    inboundquota: u32,
+    outboundquota: u32,
+    defaulttimeout: *const u64,
+) -> NTSTATUS);
+
 // Functions that aren't available on every version of Windows that we support,
 // but we still use them and just provide some form of a fallback implementation.
 compat_fn_with_fallback! {
diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt
index a99c474c763..827d96e73db 100644
--- a/library/std/src/sys/pal/windows/c/bindings.txt
+++ b/library/std/src/sys/pal/windows/c/bindings.txt
@@ -2060,6 +2060,14 @@ FILE_OPEN_REPARSE_POINT
 FILE_OPEN_REQUIRING_OPLOCK
 FILE_OVERWRITE
 FILE_OVERWRITE_IF
+FILE_PIPE_ACCEPT_REMOTE_CLIENTS
+FILE_PIPE_BYTE_STREAM_MODE
+FILE_PIPE_BYTE_STREAM_TYPE
+FILE_PIPE_COMPLETE_OPERATION
+FILE_PIPE_MESSAGE_MODE
+FILE_PIPE_MESSAGE_TYPE
+FILE_PIPE_QUEUE_OPERATION
+FILE_PIPE_REJECT_REMOTE_CLIENTS
 FILE_RANDOM_ACCESS
 FILE_READ_ATTRIBUTES
 FILE_READ_DATA
@@ -2294,7 +2302,16 @@ NtOpenFile
 NtReadFile
 NTSTATUS
 NtWriteFile
+OBJ_CASE_INSENSITIVE
 OBJ_DONT_REPARSE
+OBJ_EXCLUSIVE
+OBJ_FORCE_ACCESS_CHECK
+OBJ_IGNORE_IMPERSONATED_DEVICEMAP
+OBJ_INHERIT
+OBJ_KERNEL_HANDLE
+OBJ_OPENIF
+OBJ_OPENLINK
+OBJ_PERMANENT
 OPEN_ALWAYS
 OPEN_EXISTING
 OpenProcessToken
diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs
index 95bf8040229..b2e3aabc633 100644
--- a/library/std/src/sys/pal/windows/c/windows_sys.rs
+++ b/library/std/src/sys/pal/windows/c/windows_sys.rs
@@ -1,4 +1,4 @@
-// Bindings generated by `windows-bindgen` 0.61.0
+// Bindings generated by `windows-bindgen` 0.61.1
 
 #![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)]
 
@@ -2552,6 +2552,14 @@ pub const FILE_OPEN_REPARSE_POINT: NTCREATEFILE_CREATE_OPTIONS = 2097152u32;
 pub const FILE_OPEN_REQUIRING_OPLOCK: NTCREATEFILE_CREATE_OPTIONS = 65536u32;
 pub const FILE_OVERWRITE: NTCREATEFILE_CREATE_DISPOSITION = 4u32;
 pub const FILE_OVERWRITE_IF: NTCREATEFILE_CREATE_DISPOSITION = 5u32;
+pub const FILE_PIPE_ACCEPT_REMOTE_CLIENTS: u32 = 0u32;
+pub const FILE_PIPE_BYTE_STREAM_MODE: u32 = 0u32;
+pub const FILE_PIPE_BYTE_STREAM_TYPE: u32 = 0u32;
+pub const FILE_PIPE_COMPLETE_OPERATION: u32 = 1u32;
+pub const FILE_PIPE_MESSAGE_MODE: u32 = 1u32;
+pub const FILE_PIPE_MESSAGE_TYPE: u32 = 1u32;
+pub const FILE_PIPE_QUEUE_OPERATION: u32 = 0u32;
+pub const FILE_PIPE_REJECT_REMOTE_CLIENTS: u32 = 2u32;
 pub const FILE_RANDOM_ACCESS: NTCREATEFILE_CREATE_OPTIONS = 2048u32;
 pub const FILE_READ_ATTRIBUTES: FILE_ACCESS_RIGHTS = 128u32;
 pub const FILE_READ_DATA: FILE_ACCESS_RIGHTS = 1u32;
@@ -2983,7 +2991,16 @@ impl Default for OBJECT_ATTRIBUTES {
     }
 }
 pub type OBJECT_ATTRIBUTE_FLAGS = u32;
+pub const OBJ_CASE_INSENSITIVE: OBJECT_ATTRIBUTE_FLAGS = 64u32;
 pub const OBJ_DONT_REPARSE: OBJECT_ATTRIBUTE_FLAGS = 4096u32;
+pub const OBJ_EXCLUSIVE: OBJECT_ATTRIBUTE_FLAGS = 32u32;
+pub const OBJ_FORCE_ACCESS_CHECK: OBJECT_ATTRIBUTE_FLAGS = 1024u32;
+pub const OBJ_IGNORE_IMPERSONATED_DEVICEMAP: OBJECT_ATTRIBUTE_FLAGS = 2048u32;
+pub const OBJ_INHERIT: OBJECT_ATTRIBUTE_FLAGS = 2u32;
+pub const OBJ_KERNEL_HANDLE: OBJECT_ATTRIBUTE_FLAGS = 512u32;
+pub const OBJ_OPENIF: OBJECT_ATTRIBUTE_FLAGS = 128u32;
+pub const OBJ_OPENLINK: OBJECT_ATTRIBUTE_FLAGS = 256u32;
+pub const OBJ_PERMANENT: OBJECT_ATTRIBUTE_FLAGS = 16u32;
 pub const OPEN_ALWAYS: FILE_CREATION_DISPOSITION = 4u32;
 pub const OPEN_EXISTING: FILE_CREATION_DISPOSITION = 3u32;
 #[repr(C)]
diff --git a/library/std/src/sys/pal/windows/pipe.rs b/library/std/src/sys/pal/windows/pipe.rs
index 00d469fbaf8..bc5d05c4505 100644
--- a/library/std/src/sys/pal/windows/pipe.rs
+++ b/library/std/src/sys/pal/windows/pipe.rs
@@ -1,14 +1,9 @@
-use crate::ffi::OsStr;
 use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut};
+use crate::ops::Neg;
 use crate::os::windows::prelude::*;
-use crate::path::Path;
-use crate::random::{DefaultRandomSource, Random};
-use crate::sync::atomic::Ordering::Relaxed;
-use crate::sync::atomic::{Atomic, AtomicUsize};
+use crate::sys::api::utf16;
 use crate::sys::c;
-use crate::sys::fs::{File, OpenOptions};
 use crate::sys::handle::Handle;
-use crate::sys::pal::windows::api::{self, WinError};
 use crate::sys_common::{FromInner, IntoInner};
 use crate::{mem, ptr};
 
@@ -62,92 +57,113 @@ pub fn anon_pipe(ours_readable: bool, their_handle_inheritable: bool) -> io::Res
 
     // Note that we specifically do *not* use `CreatePipe` here because
     // unfortunately the anonymous pipes returned do not support overlapped
-    // operations. Instead, we create a "hopefully unique" name and create a
-    // named pipe which has overlapped operations enabled.
+    // operations. Instead, we use `NtCreateNamedPipeFile` to create the
+    // anonymous pipe with overlapped support.
     //
-    // Once we do this, we connect do it as usual via `CreateFileW`, and then
+    // Once we do this, we connect to it via `NtOpenFile`, and then
     // we return those reader/writer halves. Note that the `ours` pipe return
     // value is always the named pipe, whereas `theirs` is just the normal file.
     // This should hopefully shield us from child processes which assume their
     // stdout is a named pipe, which would indeed be odd!
     unsafe {
-        let ours;
-        let mut name;
-        let mut tries = 0;
-        loop {
-            tries += 1;
-            name = format!(
-                r"\\.\pipe\__rust_anonymous_pipe1__.{}.{}",
-                c::GetCurrentProcessId(),
-                random_number(),
+        let mut io_status = c::IO_STATUS_BLOCK::default();
+        let mut object_attributes = c::OBJECT_ATTRIBUTES::default();
+        object_attributes.Length = size_of::<c::OBJECT_ATTRIBUTES>() as u32;
+
+        // Open a handle to the pipe filesystem (`\??\PIPE\`).
+        // This will be used when creating a new annon pipe.
+        let pipe_fs = {
+            let path = c::UNICODE_STRING::from_ref(utf16!(r"\??\PIPE\"));
+            object_attributes.ObjectName = &path;
+            let mut pipe_fs = ptr::null_mut();
+            let status = c::NtOpenFile(
+                &mut pipe_fs,
+                c::SYNCHRONIZE | c::GENERIC_READ,
+                &object_attributes,
+                &mut io_status,
+                c::FILE_SHARE_READ | c::FILE_SHARE_WRITE,
+                c::FILE_SYNCHRONOUS_IO_NONALERT, // synchronous access
             );
-            let wide_name = OsStr::new(&name).encode_wide().chain(Some(0)).collect::<Vec<_>>();
-            let mut flags = c::FILE_FLAG_FIRST_PIPE_INSTANCE | c::FILE_FLAG_OVERLAPPED;
-            if ours_readable {
-                flags |= c::PIPE_ACCESS_INBOUND;
+            if c::nt_success(status) {
+                Handle::from_raw_handle(pipe_fs)
             } else {
-                flags |= c::PIPE_ACCESS_OUTBOUND;
+                return Err(io::Error::from_raw_os_error(c::RtlNtStatusToDosError(status) as i32));
             }
+        };
 
-            let handle = c::CreateNamedPipeW(
-                wide_name.as_ptr(),
-                flags,
-                c::PIPE_TYPE_BYTE
-                    | c::PIPE_READMODE_BYTE
-                    | c::PIPE_WAIT
-                    | c::PIPE_REJECT_REMOTE_CLIENTS,
+        // From now on we're using handles instead of paths to create and open pipes.
+        // So set the `ObjectName` to a zero length string.
+        let empty = c::UNICODE_STRING::default();
+        object_attributes.ObjectName = &empty;
+
+        // Create our side of the pipe for async access.
+        let ours = {
+            // Use the pipe filesystem as the root directory.
+            // With no name provided, an anonymous pipe will be created.
+            object_attributes.RootDirectory = pipe_fs.as_raw_handle();
+
+            // A negative timeout value is a relative time (rather than an absolute time).
+            // The time is given in 100's of nanoseconds so this is 50 milliseconds.
+            // This value was chosen to be consistent with the default timeout set by `CreateNamedPipeW`
+            // See: https://learn.microsoft.com/en-us/windows/win32/api/namedpipeapi/nf-namedpipeapi-createnamedpipew
+            let timeout = (50_i64 * 10000).neg() as u64;
+
+            let mut ours = ptr::null_mut();
+            let status = c::NtCreateNamedPipeFile(
+                &mut ours,
+                c::SYNCHRONIZE | if ours_readable { c::GENERIC_READ } else { c::GENERIC_WRITE },
+                &object_attributes,
+                &mut io_status,
+                if ours_readable { c::FILE_SHARE_WRITE } else { c::FILE_SHARE_READ },
+                c::FILE_CREATE,
+                0,
+                c::FILE_PIPE_BYTE_STREAM_TYPE,
+                c::FILE_PIPE_BYTE_STREAM_MODE,
+                c::FILE_PIPE_QUEUE_OPERATION,
+                // only allow one client pipe
                 1,
                 PIPE_BUFFER_CAPACITY,
                 PIPE_BUFFER_CAPACITY,
-                0,
-                ptr::null_mut(),
+                &timeout,
             );
-
-            // We pass the `FILE_FLAG_FIRST_PIPE_INSTANCE` flag above, and we're
-            // also just doing a best effort at selecting a unique name. If
-            // `ERROR_ACCESS_DENIED` is returned then it could mean that we
-            // accidentally conflicted with an already existing pipe, so we try
-            // again.
-            //
-            // Don't try again too much though as this could also perhaps be a
-            // legit error.
-            if handle == c::INVALID_HANDLE_VALUE {
-                let error = api::get_last_error();
-                if tries < 10 && error == WinError::ACCESS_DENIED {
-                    continue;
-                } else {
-                    return Err(io::Error::from_raw_os_error(error.code as i32));
-                }
+            if c::nt_success(status) {
+                Handle::from_raw_handle(ours)
+            } else {
+                return Err(io::Error::from_raw_os_error(c::RtlNtStatusToDosError(status) as i32));
             }
+        };
 
-            ours = Handle::from_raw_handle(handle);
-            break;
-        }
+        // Open their side of the pipe for synchronous access.
+        let theirs = {
+            // We can reopen the anonymous pipe without a name by setting
+            // RootDirectory to the pipe handle and not setting a path name,
+            object_attributes.RootDirectory = ours.as_raw_handle();
 
-        // Connect to the named pipe we just created. This handle is going to be
-        // returned in `theirs`, so if `ours` is readable we want this to be
-        // writable, otherwise if `ours` is writable we want this to be
-        // readable.
-        //
-        // Additionally we don't enable overlapped mode on this because most
-        // client processes aren't enabled to work with that.
-        let mut opts = OpenOptions::new();
-        opts.write(ours_readable);
-        opts.read(!ours_readable);
-        opts.share_mode(0);
-        let size = size_of::<c::SECURITY_ATTRIBUTES>();
-        let mut sa = c::SECURITY_ATTRIBUTES {
-            nLength: size as u32,
-            lpSecurityDescriptor: ptr::null_mut(),
-            bInheritHandle: their_handle_inheritable as i32,
+            if their_handle_inheritable {
+                object_attributes.Attributes |= c::OBJ_INHERIT;
+            }
+            let mut theirs = ptr::null_mut();
+            let status = c::NtOpenFile(
+                &mut theirs,
+                c::SYNCHRONIZE
+                    | if ours_readable {
+                        c::GENERIC_WRITE | c::FILE_READ_ATTRIBUTES
+                    } else {
+                        c::GENERIC_READ
+                    },
+                &object_attributes,
+                &mut io_status,
+                0,
+                c::FILE_NON_DIRECTORY_FILE | c::FILE_SYNCHRONOUS_IO_NONALERT,
+            );
+            if c::nt_success(status) {
+                Handle::from_raw_handle(theirs)
+            } else {
+                return Err(io::Error::from_raw_os_error(c::RtlNtStatusToDosError(status) as i32));
+            }
         };
-        opts.security_attributes(&mut sa);
-        let theirs = File::open(Path::new(&name), &opts)?;
 
-        Ok(Pipes {
-            ours: AnonPipe { inner: ours },
-            theirs: AnonPipe { inner: theirs.into_inner() },
-        })
+        Ok(Pipes { ours: AnonPipe { inner: ours }, theirs: AnonPipe { inner: theirs } })
     }
 }
 
@@ -191,17 +207,6 @@ pub fn spawn_pipe_relay(
     Ok(theirs)
 }
 
-fn random_number() -> usize {
-    static N: Atomic<usize> = AtomicUsize::new(0);
-    loop {
-        if N.load(Relaxed) != 0 {
-            return N.fetch_add(1, Relaxed);
-        }
-
-        N.store(usize::random(&mut DefaultRandomSource), Relaxed);
-    }
-}
-
 impl AnonPipe {
     pub fn handle(&self) -> &Handle {
         &self.inner
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index 0c8e6633560..a6ca699e282 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -44,6 +44,7 @@ dependencies = [
  "fd-lock",
  "home",
  "ignore",
+ "insta",
  "junction",
  "libc",
  "object",
@@ -159,6 +160,18 @@ dependencies = [
 ]
 
 [[package]]
+name = "console"
+version = "0.15.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8"
+dependencies = [
+ "encode_unicode",
+ "libc",
+ "once_cell",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
 name = "cpufeatures"
 version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -219,6 +232,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "encode_unicode"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
+
+[[package]]
 name = "errno"
 version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -324,6 +343,17 @@ dependencies = [
 ]
 
 [[package]]
+name = "insta"
+version = "1.43.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "154934ea70c58054b556dd430b99a98c2a7ff5309ac9891597e339b5c28f4371"
+dependencies = [
+ "console",
+ "once_cell",
+ "similar",
+]
+
+[[package]]
 name = "itoa"
 version = "1.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -676,6 +706,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
 
 [[package]]
+name = "similar"
+version = "2.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa"
+
+[[package]]
 name = "smallvec"
 version = "1.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index b12b3dfc7b2..9785a306c9b 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -84,6 +84,7 @@ features = [
 [dev-dependencies]
 pretty_assertions = "1.4"
 tempfile = "3.15.0"
+insta = "1.43"
 
 # We care a lot about bootstrap's compile times, so don't include debuginfo for
 # dependencies, only bootstrap itself.
diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md
index f9d7c811f60..5ff999f01a9 100644
--- a/src/bootstrap/README.md
+++ b/src/bootstrap/README.md
@@ -200,6 +200,10 @@ please file issues on the [Rust issue tracker][rust-issue-tracker].
 [rust-bootstrap-zulip]: https://rust-lang.zulipchat.com/#narrow/stream/t-infra.2Fbootstrap
 [rust-issue-tracker]: https://github.com/rust-lang/rust/issues
 
+## Testing
+
+To run bootstrap tests, execute `x test bootstrap`. If you want to bless snapshot tests, then install `cargo-insta` (`cargo install cargo-insta`) and then run `cargo insta review --manifest-path src/bootstrap/Cargo.toml`.
+
 ## Changelog
 
 Because we do not release bootstrap with versions, we also do not maintain CHANGELOG files. To
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 560925abba6..52f421b4782 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -2105,19 +2105,20 @@ impl Step for Assemble {
         if builder.config.llvm_enzyme && !builder.config.dry_run() {
             debug!("`llvm_enzyme` requested");
             let enzyme_install = builder.ensure(llvm::Enzyme { target: build_compiler.host });
-            let llvm_config = builder.llvm_config(builder.config.host_target).unwrap();
-            let llvm_version_major = llvm::get_llvm_version_major(builder, &llvm_config);
-            let lib_ext = std::env::consts::DLL_EXTENSION;
-            let libenzyme = format!("libEnzyme-{llvm_version_major}");
-            let src_lib =
-                enzyme_install.join("build/Enzyme").join(&libenzyme).with_extension(lib_ext);
-            let libdir = builder.sysroot_target_libdir(build_compiler, build_compiler.host);
-            let target_libdir =
-                builder.sysroot_target_libdir(target_compiler, target_compiler.host);
-            let dst_lib = libdir.join(&libenzyme).with_extension(lib_ext);
-            let target_dst_lib = target_libdir.join(&libenzyme).with_extension(lib_ext);
-            builder.copy_link(&src_lib, &dst_lib, FileType::NativeLibrary);
-            builder.copy_link(&src_lib, &target_dst_lib, FileType::NativeLibrary);
+            if let Some(llvm_config) = builder.llvm_config(builder.config.host_target) {
+                let llvm_version_major = llvm::get_llvm_version_major(builder, &llvm_config);
+                let lib_ext = std::env::consts::DLL_EXTENSION;
+                let libenzyme = format!("libEnzyme-{llvm_version_major}");
+                let src_lib =
+                    enzyme_install.join("build/Enzyme").join(&libenzyme).with_extension(lib_ext);
+                let libdir = builder.sysroot_target_libdir(build_compiler, build_compiler.host);
+                let target_libdir =
+                    builder.sysroot_target_libdir(target_compiler, target_compiler.host);
+                let dst_lib = libdir.join(&libenzyme).with_extension(lib_ext);
+                let target_dst_lib = target_libdir.join(&libenzyme).with_extension(lib_ext);
+                builder.copy_link(&src_lib, &dst_lib, FileType::NativeLibrary);
+                builder.copy_link(&src_lib, &target_dst_lib, FileType::NativeLibrary);
+            }
         }
 
         // Build the libraries for this compiler to link to (i.e., the libraries
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index ebb926d81ce..419839067f9 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -2009,7 +2009,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
             // Note that if we encounter `PATH` we make sure to append to our own `PATH`
             // rather than stomp over it.
             if !builder.config.dry_run() && target.is_msvc() {
-                for (k, v) in builder.cc.borrow()[&target].env() {
+                for (k, v) in builder.cc[&target].env() {
                     if k != "PATH" {
                         cmd.env(k, v);
                     }
@@ -2026,8 +2026,7 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
             // address sanitizer enabled (e.g., ntdll.dll).
             cmd.env("ASAN_WIN_CONTINUE_ON_INTERCEPTION_FAILURE", "1");
             // Add the address sanitizer runtime to the PATH - it is located next to cl.exe.
-            let asan_runtime_path =
-                builder.cc.borrow()[&target].path().parent().unwrap().to_path_buf();
+            let asan_runtime_path = builder.cc[&target].path().parent().unwrap().to_path_buf();
             let old_path = cmd
                 .get_envs()
                 .find_map(|(k, v)| (k == "PATH").then_some(v))
@@ -2575,7 +2574,7 @@ fn prepare_cargo_test(
     // by `Cargo::new` and that actually makes things go wrong.
     if builder.kind != Kind::Miri {
         let mut dylib_paths = builder.rustc_lib_paths(compiler);
-        dylib_paths.push(PathBuf::from(&builder.sysroot_target_libdir(compiler, target)));
+        dylib_paths.push(builder.sysroot_target_libdir(compiler, target));
         helpers::add_dylib_path(dylib_paths, &mut cargo);
     }
 
@@ -3059,6 +3058,8 @@ impl Step for Bootstrap {
         cargo
             .rustflag("-Cdebuginfo=2")
             .env("CARGO_TARGET_DIR", builder.out.join("bootstrap"))
+            // Needed for insta to correctly write pending snapshots to the right directories.
+            .env("INSTA_WORKSPACE_ROOT", &builder.src)
             .env("RUSTC_BOOTSTRAP", "1");
 
         // bootstrap tests are racy on directory creation so just run them one at a time.
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index f64d67341cf..0088e851d39 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -589,7 +589,7 @@ impl ErrorIndex {
         let compiler = builder.compiler_for(builder.top_stage, host, host);
         let mut cmd = command(builder.ensure(ErrorIndex { compiler }).tool_path);
         let mut dylib_paths = builder.rustc_lib_paths(compiler);
-        dylib_paths.push(PathBuf::from(&builder.sysroot_target_libdir(compiler, compiler.host)));
+        dylib_paths.push(builder.sysroot_target_libdir(compiler, compiler.host));
         add_dylib_path(dylib_paths, &mut cmd);
         cmd
     }
@@ -1334,7 +1334,7 @@ impl Builder<'_> {
         if compiler.host.is_msvc() {
             let curpaths = env::var_os("PATH").unwrap_or_default();
             let curpaths = env::split_paths(&curpaths).collect::<Vec<_>>();
-            for (k, v) in self.cc.borrow()[&compiler.host].env() {
+            for (k, v) in self.cc[&compiler.host].env() {
                 if k != "PATH" {
                     continue;
                 }
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
index c6cfdb69356..0e3c3aaee0f 100644
--- a/src/bootstrap/src/core/builder/cargo.rs
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -278,9 +278,7 @@ impl Cargo {
             self.rustdocflags.arg(&arg);
         }
 
-        if !builder.config.dry_run()
-            && builder.cc.borrow()[&target].args().iter().any(|arg| arg == "-gz")
-        {
+        if !builder.config.dry_run() && builder.cc[&target].args().iter().any(|arg| arg == "-gz") {
             self.rustflags.arg("-Clink-arg=-gz");
         }
 
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index 887db683f78..7433f0b0f3b 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -5,7 +5,7 @@ use std::fmt::{self, Debug, Write};
 use std::hash::Hash;
 use std::ops::Deref;
 use std::path::{Path, PathBuf};
-use std::sync::LazyLock;
+use std::sync::{LazyLock, OnceLock};
 use std::time::{Duration, Instant};
 use std::{env, fs};
 
@@ -60,6 +60,9 @@ pub struct Builder<'a> {
     /// to do. For example: with `./x check foo bar` we get `paths=["foo",
     /// "bar"]`.
     pub paths: Vec<PathBuf>,
+
+    /// Cached list of submodules from self.build.src.
+    submodule_paths_cache: OnceLock<Vec<String>>,
 }
 
 impl Deref for Builder<'_> {
@@ -687,7 +690,7 @@ impl<'a> ShouldRun<'a> {
     ///
     /// [`path`]: ShouldRun::path
     pub fn paths(mut self, paths: &[&str]) -> Self {
-        let submodules_paths = build_helper::util::parse_gitmodules(&self.builder.src);
+        let submodules_paths = self.builder.submodule_paths();
 
         self.paths.insert(PathSet::Set(
             paths
@@ -1180,6 +1183,7 @@ impl<'a> Builder<'a> {
             stack: RefCell::new(Vec::new()),
             time_spent_on_dependencies: Cell::new(Duration::new(0, 0)),
             paths,
+            submodule_paths_cache: Default::default(),
         }
     }
 
@@ -1510,6 +1514,19 @@ impl<'a> Builder<'a> {
         None
     }
 
+    /// Updates all submodules, and exits with an error if submodule
+    /// management is disabled and the submodule does not exist.
+    pub fn require_and_update_all_submodules(&self) {
+        for submodule in self.submodule_paths() {
+            self.require_submodule(submodule, None);
+        }
+    }
+
+    /// Get all submodules from the src directory.
+    pub fn submodule_paths(&self) -> &[String] {
+        self.submodule_paths_cache.get_or_init(|| build_helper::util::parse_gitmodules(&self.src))
+    }
+
     /// Ensure that a given step is built, returning its output. This will
     /// cache the step, so it is safe (and good!) to call this as often as
     /// needed to ensure that all dependencies are built.
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index a26a96f2815..d07df7f4a84 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -15,11 +15,12 @@ static TEST_TRIPLE_2: &str = "i686-unknown-hurd-gnu";
 static TEST_TRIPLE_3: &str = "i686-unknown-netbsd";
 
 fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config {
-    configure_with_args(&[cmd.to_owned()], host, target)
+    configure_with_args(&[cmd], host, target)
 }
 
-fn configure_with_args(cmd: &[String], host: &[&str], target: &[&str]) -> Config {
-    let mut config = Config::parse(Flags::parse(cmd));
+fn configure_with_args(cmd: &[&str], host: &[&str], target: &[&str]) -> Config {
+    let cmd = cmd.iter().copied().map(String::from).collect::<Vec<_>>();
+    let mut config = Config::parse(Flags::parse(&cmd));
     // don't save toolstates
     config.save_toolstates = None;
     config.set_dry_run(DryRun::SelfCheck);
@@ -67,7 +68,7 @@ fn run_build(paths: &[PathBuf], config: Config) -> Cache {
 fn check_cli<const N: usize>(paths: [&str; N]) {
     run_build(
         &paths.map(PathBuf::from),
-        configure_with_args(&paths.map(String::from), &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]),
+        configure_with_args(&paths, &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]),
     );
 }
 
@@ -1000,8 +1001,7 @@ mod sysroot_target_dirs {
 /// cg_gcc tests instead.
 #[test]
 fn test_test_compiler() {
-    let cmd = &["test", "compiler"].map(str::to_owned);
-    let config = configure_with_args(cmd, &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]);
+    let config = configure_with_args(&["test", "compiler"], &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]);
     let cache = run_build(&config.paths.clone(), config);
 
     let compiler = cache.contains::<test::CrateLibrustc>();
@@ -1034,8 +1034,7 @@ fn test_test_coverage() {
         // Print each test case so that if one fails, the most recently printed
         // case is the one that failed.
         println!("Testing case: {cmd:?}");
-        let cmd = cmd.iter().copied().map(str::to_owned).collect::<Vec<_>>();
-        let config = configure_with_args(&cmd, &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]);
+        let config = configure_with_args(cmd, &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]);
         let mut cache = run_build(&config.paths.clone(), config);
 
         let modes =
@@ -1207,8 +1206,7 @@ fn test_get_tool_rustc_compiler() {
 /// of `Any { .. }`.
 #[test]
 fn step_cycle_debug() {
-    let cmd = ["run", "cyclic-step"].map(str::to_owned);
-    let config = configure_with_args(&cmd, &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]);
+    let config = configure_with_args(&["run", "cyclic-step"], &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]);
 
     let err = panic::catch_unwind(|| run_build(&config.paths.clone(), config)).unwrap_err();
     let err = err.downcast_ref::<String>().unwrap().as_str();
@@ -1233,3 +1231,81 @@ fn any_debug() {
     // Downcasting to the underlying type should succeed.
     assert_eq!(x.downcast_ref::<MyStruct>(), Some(&MyStruct { x: 7 }));
 }
+
+/// The staging tests use insta for snapshot testing.
+/// See bootstrap's README on how to bless the snapshots.
+mod staging {
+    use crate::core::builder::tests::{
+        TEST_TRIPLE_1, configure, configure_with_args, render_steps, run_build,
+    };
+
+    #[test]
+    fn build_compiler_stage_1() {
+        let mut cache = run_build(
+            &["compiler".into()],
+            configure_with_args(&["build", "--stage", "1"], &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]),
+        );
+        let steps = cache.into_executed_steps();
+        insta::assert_snapshot!(render_steps(&steps), @r"
+        [build] rustc 0 <target1> -> std 0 <target1>
+        [build] llvm <target1>
+        [build] rustc 0 <target1> -> rustc 1 <target1>
+        [build] rustc 0 <target1> -> rustc 1 <target1>
+        ");
+    }
+}
+
+/// Renders the executed bootstrap steps for usage in snapshot tests with insta.
+/// Only renders certain important steps.
+/// Each value in `steps` should be a tuple of (Step, step output).
+fn render_steps(steps: &[(Box<dyn Any>, Box<dyn Any>)]) -> String {
+    steps
+        .iter()
+        .filter_map(|(step, output)| {
+            // FIXME: implement an optional method on Step to produce metadata for test, instead
+            // of this downcasting
+            if let Some((rustc, output)) = downcast_step::<compile::Rustc>(step, output) {
+                Some(format!(
+                    "[build] {} -> {}",
+                    render_compiler(rustc.build_compiler),
+                    // FIXME: return the correct stage from the `Rustc` step, now it behaves weirdly
+                    render_compiler(Compiler::new(rustc.build_compiler.stage + 1, rustc.target)),
+                ))
+            } else if let Some((std, output)) = downcast_step::<compile::Std>(step, output) {
+                Some(format!(
+                    "[build] {} -> std {} <{}>",
+                    render_compiler(std.compiler),
+                    std.compiler.stage,
+                    std.target
+                ))
+            } else if let Some((llvm, output)) = downcast_step::<llvm::Llvm>(step, output) {
+                Some(format!("[build] llvm <{}>", llvm.target))
+            } else {
+                None
+            }
+        })
+        .map(|line| {
+            line.replace(TEST_TRIPLE_1, "target1")
+                .replace(TEST_TRIPLE_2, "target2")
+                .replace(TEST_TRIPLE_3, "target3")
+        })
+        .collect::<Vec<_>>()
+        .join("\n")
+}
+
+fn downcast_step<'a, S: Step>(
+    step: &'a Box<dyn Any>,
+    output: &'a Box<dyn Any>,
+) -> Option<(&'a S, &'a S::Output)> {
+    let Some(step) = step.downcast_ref::<S>() else {
+        return None;
+    };
+    let Some(output) = output.downcast_ref::<S::Output>() else {
+        return None;
+    };
+    Some((step, output))
+}
+
+fn render_compiler(compiler: Compiler) -> String {
+    format!("rustc {} <{}>", compiler.stage, compiler.host)
+}
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 7254c653a2d..f1628f34dda 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -17,7 +17,7 @@
 //! also check out the `src/bootstrap/README.md` file for more information.
 #![cfg_attr(test, allow(unused))]
 
-use std::cell::{Cell, RefCell};
+use std::cell::Cell;
 use std::collections::{BTreeSet, HashMap, HashSet};
 use std::fmt::Display;
 use std::path::{Path, PathBuf};
@@ -189,10 +189,12 @@ pub struct Build {
 
     // Runtime state filled in later on
     // C/C++ compilers and archiver for all targets
-    cc: RefCell<HashMap<TargetSelection, cc::Tool>>,
-    cxx: RefCell<HashMap<TargetSelection, cc::Tool>>,
-    ar: RefCell<HashMap<TargetSelection, PathBuf>>,
-    ranlib: RefCell<HashMap<TargetSelection, PathBuf>>,
+    cc: HashMap<TargetSelection, cc::Tool>,
+    cxx: HashMap<TargetSelection, cc::Tool>,
+    ar: HashMap<TargetSelection, PathBuf>,
+    ranlib: HashMap<TargetSelection, PathBuf>,
+    wasi_sdk_path: Option<PathBuf>,
+
     // Miscellaneous
     // allow bidirectional lookups: both name -> path and path -> name
     crates: HashMap<String, Crate>,
@@ -466,10 +468,11 @@ impl Build {
             enzyme_info,
             in_tree_llvm_info,
             in_tree_gcc_info,
-            cc: RefCell::new(HashMap::new()),
-            cxx: RefCell::new(HashMap::new()),
-            ar: RefCell::new(HashMap::new()),
-            ranlib: RefCell::new(HashMap::new()),
+            cc: HashMap::new(),
+            cxx: HashMap::new(),
+            ar: HashMap::new(),
+            ranlib: HashMap::new(),
+            wasi_sdk_path: env::var_os("WASI_SDK_PATH").map(PathBuf::from),
             crates: HashMap::new(),
             crate_paths: HashMap::new(),
             is_sudo,
@@ -498,7 +501,7 @@ impl Build {
         }
 
         build.verbose(|| println!("finding compilers"));
-        utils::cc_detect::find(&build);
+        utils::cc_detect::fill_compilers(&mut build);
         // When running `setup`, the profile is about to change, so any requirements we have now may
         // be different on the next invocation. Don't check for them until the next time x.py is
         // run. This is ok because `setup` never runs any build commands, so it won't fail if commands are missing.
@@ -593,14 +596,6 @@ impl Build {
         }
     }
 
-    /// Updates all submodules, and exits with an error if submodule
-    /// management is disabled and the submodule does not exist.
-    pub fn require_and_update_all_submodules(&self) {
-        for submodule in build_helper::util::parse_gitmodules(&self.src) {
-            self.require_submodule(submodule, None);
-        }
-    }
-
     /// If any submodule has been initialized already, sync it unconditionally.
     /// This avoids contributors checking in a submodule change by accident.
     fn update_existing_submodules(&self) {
@@ -1143,17 +1138,17 @@ impl Build {
         if self.config.dry_run() {
             return PathBuf::new();
         }
-        self.cc.borrow()[&target].path().into()
+        self.cc[&target].path().into()
     }
 
     /// Returns the internal `cc::Tool` for the C compiler.
     fn cc_tool(&self, target: TargetSelection) -> Tool {
-        self.cc.borrow()[&target].clone()
+        self.cc[&target].clone()
     }
 
     /// Returns the internal `cc::Tool` for the C++ compiler.
     fn cxx_tool(&self, target: TargetSelection) -> Tool {
-        self.cxx.borrow()[&target].clone()
+        self.cxx[&target].clone()
     }
 
     /// Returns C flags that `cc-rs` thinks should be enabled for the
@@ -1163,8 +1158,8 @@ impl Build {
             return Vec::new();
         }
         let base = match c {
-            CLang::C => self.cc.borrow()[&target].clone(),
-            CLang::Cxx => self.cxx.borrow()[&target].clone(),
+            CLang::C => self.cc[&target].clone(),
+            CLang::Cxx => self.cxx[&target].clone(),
         };
 
         // Filter out -O and /O (the optimization flags) that we picked up
@@ -1217,7 +1212,7 @@ impl Build {
         if self.config.dry_run() {
             return None;
         }
-        self.ar.borrow().get(&target).cloned()
+        self.ar.get(&target).cloned()
     }
 
     /// Returns the path to the `ranlib` utility for the target specified.
@@ -1225,7 +1220,7 @@ impl Build {
         if self.config.dry_run() {
             return None;
         }
-        self.ranlib.borrow().get(&target).cloned()
+        self.ranlib.get(&target).cloned()
     }
 
     /// Returns the path to the C++ compiler for the target specified.
@@ -1233,7 +1228,7 @@ impl Build {
         if self.config.dry_run() {
             return Ok(PathBuf::new());
         }
-        match self.cxx.borrow().get(&target) {
+        match self.cxx.get(&target) {
             Some(p) => Ok(p.path().into()),
             None => Err(format!("target `{target}` is not configured as a host, only as a target")),
         }
@@ -1250,7 +1245,7 @@ impl Build {
         } else if target.contains("vxworks") {
             // need to use CXX compiler as linker to resolve the exception functions
             // that are only existed in CXX libraries
-            Some(self.cxx.borrow()[&target].path().into())
+            Some(self.cxx[&target].path().into())
         } else if !self.config.is_host_target(target)
             && helpers::use_host_linker(target)
             && !target.is_msvc()
diff --git a/src/bootstrap/src/utils/build_stamp/tests.rs b/src/bootstrap/src/utils/build_stamp/tests.rs
index 2d7d1f71246..f150266159a 100644
--- a/src/bootstrap/src/utils/build_stamp/tests.rs
+++ b/src/bootstrap/src/utils/build_stamp/tests.rs
@@ -1,32 +1,28 @@
 use std::path::PathBuf;
 
-use crate::{BuildStamp, Config, Flags};
+use tempfile::TempDir;
 
-fn temp_dir() -> PathBuf {
-    let config =
-        Config::parse(Flags::parse(&["check".to_owned(), "--config=/does/not/exist".to_owned()]));
-    config.tempdir()
-}
+use crate::{BuildStamp, Config, Flags};
 
 #[test]
 #[should_panic(expected = "prefix can not start or end with '.'")]
 fn test_with_invalid_prefix() {
-    let dir = temp_dir();
-    BuildStamp::new(&dir).with_prefix(".invalid");
+    let dir = TempDir::new().unwrap();
+    BuildStamp::new(dir.path()).with_prefix(".invalid");
 }
 
 #[test]
 #[should_panic(expected = "prefix can not start or end with '.'")]
 fn test_with_invalid_prefix2() {
-    let dir = temp_dir();
-    BuildStamp::new(&dir).with_prefix("invalid.");
+    let dir = TempDir::new().unwrap();
+    BuildStamp::new(dir.path()).with_prefix("invalid.");
 }
 
 #[test]
 fn test_is_up_to_date() {
-    let dir = temp_dir();
+    let dir = TempDir::new().unwrap();
 
-    let mut build_stamp = BuildStamp::new(&dir).add_stamp("v1.0.0");
+    let mut build_stamp = BuildStamp::new(dir.path()).add_stamp("v1.0.0");
     build_stamp.write().unwrap();
 
     assert!(
@@ -45,9 +41,9 @@ fn test_is_up_to_date() {
 
 #[test]
 fn test_with_prefix() {
-    let dir = temp_dir();
+    let dir = TempDir::new().unwrap();
 
-    let stamp = BuildStamp::new(&dir).add_stamp("v1.0.0");
+    let stamp = BuildStamp::new(dir.path()).add_stamp("v1.0.0");
     assert_eq!(stamp.path.file_name().unwrap(), ".stamp");
 
     let stamp = stamp.with_prefix("test");
diff --git a/src/bootstrap/src/utils/cache.rs b/src/bootstrap/src/utils/cache.rs
index 46eeffad88c..0c737470958 100644
--- a/src/bootstrap/src/utils/cache.rs
+++ b/src/bootstrap/src/utils/cache.rs
@@ -17,6 +17,7 @@ use std::borrow::Borrow;
 use std::cell::RefCell;
 use std::cmp::Ordering;
 use std::collections::HashMap;
+use std::fmt::Debug;
 use std::hash::{Hash, Hasher};
 use std::marker::PhantomData;
 use std::ops::Deref;
@@ -208,25 +209,30 @@ pub static INTERNER: LazyLock<Interner> = LazyLock::new(Interner::default);
 /// any type in its output. It is a write-once cache; values are never evicted,
 /// which means that references to the value can safely be returned from the
 /// `get()` method.
-#[derive(Debug)]
-pub struct Cache(
-    RefCell<
+#[derive(Debug, Default)]
+pub struct Cache {
+    cache: RefCell<
         HashMap<
             TypeId,
             Box<dyn Any>, // actually a HashMap<Step, Interned<Step::Output>>
         >,
     >,
-);
+    #[cfg(test)]
+    /// Contains steps in the same order in which they were executed
+    /// Useful for tests
+    /// Tuples (step, step output)
+    executed_steps: RefCell<Vec<(Box<dyn Any>, Box<dyn Any>)>>,
+}
 
 impl Cache {
     /// Creates a new empty cache.
     pub fn new() -> Cache {
-        Cache(RefCell::new(HashMap::new()))
+        Cache::default()
     }
 
     /// Stores the result of a computation step in the cache.
     pub fn put<S: Step>(&self, step: S, value: S::Output) {
-        let mut cache = self.0.borrow_mut();
+        let mut cache = self.cache.borrow_mut();
         let type_id = TypeId::of::<S>();
         let stepcache = cache
             .entry(type_id)
@@ -234,12 +240,20 @@ impl Cache {
             .downcast_mut::<HashMap<S, S::Output>>()
             .expect("invalid type mapped");
         assert!(!stepcache.contains_key(&step), "processing {step:?} a second time");
+
+        #[cfg(test)]
+        {
+            let step: Box<dyn Any> = Box::new(step.clone());
+            let output: Box<dyn Any> = Box::new(value.clone());
+            self.executed_steps.borrow_mut().push((step, output));
+        }
+
         stepcache.insert(step, value);
     }
 
     /// Retrieves a cached result for the given step, if available.
     pub fn get<S: Step>(&self, step: &S) -> Option<S::Output> {
-        let mut cache = self.0.borrow_mut();
+        let mut cache = self.cache.borrow_mut();
         let type_id = TypeId::of::<S>();
         let stepcache = cache
             .entry(type_id)
@@ -252,8 +266,8 @@ impl Cache {
 
 #[cfg(test)]
 impl Cache {
-    pub fn all<S: Ord + Clone + Step>(&mut self) -> Vec<(S, S::Output)> {
-        let cache = self.0.get_mut();
+    pub fn all<S: Ord + Step>(&mut self) -> Vec<(S, S::Output)> {
+        let cache = self.cache.get_mut();
         let type_id = TypeId::of::<S>();
         let mut v = cache
             .remove(&type_id)
@@ -265,7 +279,12 @@ impl Cache {
     }
 
     pub fn contains<S: Step>(&self) -> bool {
-        self.0.borrow().contains_key(&TypeId::of::<S>())
+        self.cache.borrow().contains_key(&TypeId::of::<S>())
+    }
+
+    #[cfg(test)]
+    pub fn into_executed_steps(mut self) -> Vec<(Box<dyn Any>, Box<dyn Any>)> {
+        mem::take(&mut self.executed_steps.borrow_mut())
     }
 }
 
diff --git a/src/bootstrap/src/utils/cc_detect.rs b/src/bootstrap/src/utils/cc_detect.rs
index 851bb38074e..dcafeb80f90 100644
--- a/src/bootstrap/src/utils/cc_detect.rs
+++ b/src/bootstrap/src/utils/cc_detect.rs
@@ -61,8 +61,8 @@ fn new_cc_build(build: &Build, target: TargetSelection) -> cc::Build {
 ///
 /// This function determines which targets need a C compiler (and, if needed, a C++ compiler)
 /// by combining the primary build target, host targets, and any additional targets. For
-/// each target, it calls [`find_target`] to configure the necessary compiler tools.
-pub fn find(build: &Build) {
+/// each target, it calls [`fill_target_compiler`] to configure the necessary compiler tools.
+pub fn fill_compilers(build: &mut Build) {
     let targets: HashSet<_> = match build.config.cmd {
         // We don't need to check cross targets for these commands.
         crate::Subcommand::Clean { .. }
@@ -87,7 +87,7 @@ pub fn find(build: &Build) {
     };
 
     for target in targets.into_iter() {
-        find_target(build, target);
+        fill_target_compiler(build, target);
     }
 }
 
@@ -96,7 +96,7 @@ pub fn find(build: &Build) {
 /// This function uses both user-specified configuration (from `bootstrap.toml`) and auto-detection
 /// logic to determine the correct C/C++ compilers for the target. It also determines the appropriate
 /// archiver (`ar`) and sets up additional compilation flags (both handled and unhandled).
-pub fn find_target(build: &Build, target: TargetSelection) {
+pub fn fill_target_compiler(build: &mut Build, target: TargetSelection) {
     let mut cfg = new_cc_build(build, target);
     let config = build.config.target_config.get(&target);
     if let Some(cc) = config
@@ -113,7 +113,7 @@ pub fn find_target(build: &Build, target: TargetSelection) {
         cfg.try_get_archiver().map(|c| PathBuf::from(c.get_program())).ok()
     };
 
-    build.cc.borrow_mut().insert(target, compiler.clone());
+    build.cc.insert(target, compiler.clone());
     let mut cflags = build.cc_handled_clags(target, CLang::C);
     cflags.extend(build.cc_unhandled_cflags(target, GitRepo::Rustc, CLang::C));
 
@@ -135,7 +135,7 @@ pub fn find_target(build: &Build, target: TargetSelection) {
     // for VxWorks, record CXX compiler which will be used in lib.rs:linker()
     if cxx_configured || target.contains("vxworks") {
         let compiler = cfg.get_compiler();
-        build.cxx.borrow_mut().insert(target, compiler);
+        build.cxx.insert(target, compiler);
     }
 
     build.verbose(|| println!("CC_{} = {:?}", target.triple, build.cc(target)));
@@ -148,11 +148,11 @@ pub fn find_target(build: &Build, target: TargetSelection) {
     }
     if let Some(ar) = ar {
         build.verbose(|| println!("AR_{} = {ar:?}", target.triple));
-        build.ar.borrow_mut().insert(target, ar);
+        build.ar.insert(target, ar);
     }
 
     if let Some(ranlib) = config.and_then(|c| c.ranlib.clone()) {
-        build.ranlib.borrow_mut().insert(target, ranlib);
+        build.ranlib.insert(target, ranlib);
     }
 }
 
@@ -221,7 +221,10 @@ fn default_compiler(
         }
 
         t if t.contains("-wasi") => {
-            let root = PathBuf::from(std::env::var_os("WASI_SDK_PATH")?);
+            let root = build
+                .wasi_sdk_path
+                .as_ref()
+                .expect("WASI_SDK_PATH mut be configured for a -wasi target");
             let compiler = match compiler {
                 Language::C => format!("{t}-clang"),
                 Language::CPlusPlus => format!("{t}-clang++"),
diff --git a/src/bootstrap/src/utils/cc_detect/tests.rs b/src/bootstrap/src/utils/cc_detect/tests.rs
index 1f50738959f..bed03c18aaa 100644
--- a/src/bootstrap/src/utils/cc_detect/tests.rs
+++ b/src/bootstrap/src/utils/cc_detect/tests.rs
@@ -77,11 +77,11 @@ fn test_new_cc_build() {
 
 #[test]
 fn test_default_compiler_wasi() {
-    let build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) });
+    let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) });
     let target = TargetSelection::from_user("wasm32-wasi");
     let wasi_sdk = PathBuf::from("/wasi-sdk");
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe { env::set_var("WASI_SDK_PATH", &wasi_sdk) };
+    build.wasi_sdk_path = Some(wasi_sdk.clone());
+
     let mut cfg = cc::Build::new();
     if let Some(result) = default_compiler(&mut cfg, Language::C, target.clone(), &build) {
         let expected = {
@@ -94,10 +94,6 @@ fn test_default_compiler_wasi() {
             "default_compiler should return a compiler path for wasi target when WASI_SDK_PATH is set"
         );
     }
-    // SAFETY: bootstrap tests run on a single thread
-    unsafe {
-        env::remove_var("WASI_SDK_PATH");
-    }
 }
 
 #[test]
@@ -119,18 +115,14 @@ fn test_find_target_with_config() {
     target_config.ar = Some(PathBuf::from("dummy-ar"));
     target_config.ranlib = Some(PathBuf::from("dummy-ranlib"));
     build.config.target_config.insert(target.clone(), target_config);
-    find_target(&build, target.clone());
-    let binding = build.cc.borrow();
-    let cc_tool = binding.get(&target).unwrap();
+    fill_target_compiler(&mut build, target.clone());
+    let cc_tool = build.cc.get(&target).unwrap();
     assert_eq!(cc_tool.path(), &PathBuf::from("dummy-cc"));
-    let binding = build.cxx.borrow();
-    let cxx_tool = binding.get(&target).unwrap();
+    let cxx_tool = build.cxx.get(&target).unwrap();
     assert_eq!(cxx_tool.path(), &PathBuf::from("dummy-cxx"));
-    let binding = build.ar.borrow();
-    let ar = binding.get(&target).unwrap();
+    let ar = build.ar.get(&target).unwrap();
     assert_eq!(ar, &PathBuf::from("dummy-ar"));
-    let binding = build.ranlib.borrow();
-    let ranlib = binding.get(&target).unwrap();
+    let ranlib = build.ranlib.get(&target).unwrap();
     assert_eq!(ranlib, &PathBuf::from("dummy-ranlib"));
 }
 
@@ -139,12 +131,12 @@ fn test_find_target_without_config() {
     let mut build = Build::new(Config { ..Config::parse(Flags::parse(&["build".to_owned()])) });
     let target = TargetSelection::from_user("x86_64-unknown-linux-gnu");
     build.config.target_config.clear();
-    find_target(&build, target.clone());
-    assert!(build.cc.borrow().contains_key(&target));
+    fill_target_compiler(&mut build, target.clone());
+    assert!(build.cc.contains_key(&target));
     if !target.triple.contains("vxworks") {
-        assert!(build.cxx.borrow().contains_key(&target));
+        assert!(build.cxx.contains_key(&target));
     }
-    assert!(build.ar.borrow().contains_key(&target));
+    assert!(build.ar.contains_key(&target));
 }
 
 #[test]
@@ -154,8 +146,8 @@ fn test_find() {
     let target2 = TargetSelection::from_user("x86_64-unknown-openbsd");
     build.targets.push(target1.clone());
     build.hosts.push(target2.clone());
-    find(&build);
+    fill_compilers(&mut build);
     for t in build.hosts.iter().chain(build.targets.iter()).chain(iter::once(&build.host_target)) {
-        assert!(build.cc.borrow().contains_key(t), "CC not set for target {}", t.triple);
+        assert!(build.cc.contains_key(t), "CC not set for target {}", t.triple);
     }
 }
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index 8b2f2dd431e..f4be22f1e64 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -98,7 +98,7 @@ pub fn is_dylib(path: &Path) -> bool {
 
 /// Return the path to the containing submodule if available.
 pub fn submodule_path_of(builder: &Builder<'_>, path: &str) -> Option<String> {
-    let submodule_paths = build_helper::util::parse_gitmodules(&builder.src);
+    let submodule_paths = builder.submodule_paths();
     submodule_paths.iter().find_map(|submodule_path| {
         if path.starts_with(submodule_path) { Some(submodule_path.to_string()) } else { None }
     })
diff --git a/src/bootstrap/src/utils/shared_helpers.rs b/src/bootstrap/src/utils/shared_helpers.rs
index 561af34a447..9c6b4a7615d 100644
--- a/src/bootstrap/src/utils/shared_helpers.rs
+++ b/src/bootstrap/src/utils/shared_helpers.rs
@@ -6,6 +6,9 @@
 
 #![allow(dead_code)]
 
+#[cfg(test)]
+mod tests;
+
 use std::env;
 use std::ffi::OsString;
 use std::fs::OpenOptions;
diff --git a/src/bootstrap/src/utils/tests/shared_helpers_tests.rs b/src/bootstrap/src/utils/shared_helpers/tests.rs
index 6c47e7f2438..559e9f70abd 100644
--- a/src/bootstrap/src/utils/tests/shared_helpers_tests.rs
+++ b/src/bootstrap/src/utils/shared_helpers/tests.rs
@@ -1,10 +1,3 @@
-//! The `shared_helpers` module can't have its own tests submodule, because
-//! that would cause problems for the shim binaries that include it via
-//! `#[path]`, so instead those unit tests live here.
-//!
-//! To prevent tidy from complaining about this file not being named `tests.rs`,
-//! it lives inside a submodule directory named `tests`.
-
 use crate::utils::shared_helpers::parse_value_from_args;
 
 #[test]
diff --git a/src/bootstrap/src/utils/tests/mod.rs b/src/bootstrap/src/utils/tests/mod.rs
index 73d55db994c..73c500f6e36 100644
--- a/src/bootstrap/src/utils/tests/mod.rs
+++ b/src/bootstrap/src/utils/tests/mod.rs
@@ -1,2 +1,3 @@
+//! This module contains shared utilities for bootstrap tests.
+
 pub mod git;
-mod shared_helpers_tests;
diff --git a/src/build_helper/src/util.rs b/src/build_helper/src/util.rs
index 72c05c4c48a..80dd6813d13 100644
--- a/src/build_helper/src/util.rs
+++ b/src/build_helper/src/util.rs
@@ -2,7 +2,6 @@ use std::fs::File;
 use std::io::{BufRead, BufReader};
 use std::path::Path;
 use std::process::Command;
-use std::sync::OnceLock;
 
 /// Invokes `build_helper::util::detail_exit` with `cfg!(test)`
 ///
@@ -51,25 +50,20 @@ pub fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> Result<(), ()> {
 }
 
 /// Returns the submodule paths from the `.gitmodules` file in the given directory.
-pub fn parse_gitmodules(target_dir: &Path) -> &[String] {
-    static SUBMODULES_PATHS: OnceLock<Vec<String>> = OnceLock::new();
+pub fn parse_gitmodules(target_dir: &Path) -> Vec<String> {
     let gitmodules = target_dir.join(".gitmodules");
     assert!(gitmodules.exists(), "'{}' file is missing.", gitmodules.display());
 
-    let init_submodules_paths = || {
-        let file = File::open(gitmodules).unwrap();
+    let file = File::open(gitmodules).unwrap();
 
-        let mut submodules_paths = vec![];
-        for line in BufReader::new(file).lines().map_while(Result::ok) {
-            let line = line.trim();
-            if line.starts_with("path") {
-                let actual_path = line.split(' ').last().expect("Couldn't get value of path");
-                submodules_paths.push(actual_path.to_owned());
-            }
+    let mut submodules_paths = vec![];
+    for line in BufReader::new(file).lines().map_while(Result::ok) {
+        let line = line.trim();
+        if line.starts_with("path") {
+            let actual_path = line.split(' ').last().expect("Couldn't get value of path");
+            submodules_paths.push(actual_path.to_owned());
         }
+    }
 
-        submodules_paths
-    };
-
-    SUBMODULES_PATHS.get_or_init(|| init_submodules_paths())
+    submodules_paths
 }
diff --git a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
index 241199d3baf..58e66fd637a 100644
--- a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
+++ b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile
@@ -22,10 +22,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-RUN mkdir -p /config
-RUN echo "[rust]" > /config/nopt-std-config.toml
-RUN echo "optimize = false" >> /config/nopt-std-config.toml
-
 ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests
 ARG SCRIPT_ARG
 COPY scripts/stage_2_test_set1.sh /scripts/
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile
index 1b57ae7c8da..854c36ee01c 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile
@@ -22,12 +22,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
-RUN mkdir -p /config
-RUN echo "[rust]" > /config/nopt-std-config.toml
-RUN echo "optimize = false" >> /config/nopt-std-config.toml
-
 ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu \
   --disable-optimize-tests \
   --set rust.test-compare-mode
-ENV SCRIPT python3 ../x.py test --stage 1 --config /config/nopt-std-config.toml library/std \
+ENV SCRIPT python3 ../x.py test --stage 1 --set rust.optimize=false library/std \
   && python3 ../x.py --stage 2 test
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index d6d9e0fb773..217cf764afb 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -300,7 +300,7 @@ auto:
     env:
       IMAGE: i686-gnu-nopt
       DOCKER_SCRIPT: >-
-        python3 ../x.py test --stage 1 --config /config/nopt-std-config.toml library/std &&
+        python3 ../x.py test --stage 1 --set rust.optimize=false library/std &&
         /scripts/stage_2_test_set2.sh
     <<: *job-linux-4c
 
diff --git a/src/doc/book b/src/doc/book
-Subproject 634724ea85ebb08a542970bf8871ac8b0f77fd1
+Subproject 4433c9f0cad8460bee05ede040587f8a1fa3f1d
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 8e0f593a30f3b56ddb0908fb7ab9249974e0873
+Subproject d4c66b346f4b72d29e70390a3fa3ea7d4e064db
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 21f4e32b8b40d36453fae16ec07ad4b857c445b
+Subproject 9baa9e863116cb9524a177d5a5c475baac18928
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 9b5491310b4..dcd499d5f0d 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -265,13 +265,27 @@ pub(crate) fn build_trait(cx: &mut DocContext<'_>, did: DefId) -> clean::Trait {
         .collect();
 
     let generics = clean_ty_generics(cx, did);
-    let (generics, supertrait_bounds) = separate_self_bounds(generics);
+    let (generics, mut supertrait_bounds) = separate_self_bounds(generics);
+
+    supertrait_bounds.retain(|b| {
+        // FIXME(sized-hierarchy): Always skip `MetaSized` bounds so that only `?Sized`
+        // is shown and none of the new sizedness traits leak into documentation.
+        !b.is_meta_sized_bound(cx)
+    });
+
     clean::Trait { def_id: did, generics, items: trait_items, bounds: supertrait_bounds }
 }
 
 fn build_trait_alias(cx: &mut DocContext<'_>, did: DefId) -> clean::TraitAlias {
     let generics = clean_ty_generics(cx, did);
-    let (generics, bounds) = separate_self_bounds(generics);
+    let (generics, mut bounds) = separate_self_bounds(generics);
+
+    bounds.retain(|b| {
+        // FIXME(sized-hierarchy): Always skip `MetaSized` bounds so that only `?Sized`
+        // is shown and none of the new sizedness traits leak into documentation.
+        !b.is_meta_sized_bound(cx)
+    });
+
     clean::TraitAlias { generics, bounds }
 }
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index db4bcdaeb6c..d77bdf09d01 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -39,9 +39,9 @@ use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet, IndexEntry};
 use rustc_errors::codes::*;
 use rustc_errors::{FatalError, struct_span_code_err};
-use rustc_hir::PredicateOrigin;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{DefId, DefIdMap, DefIdSet, LOCAL_CRATE, LocalDefId};
+use rustc_hir::{LangItem, PredicateOrigin};
 use rustc_hir_analysis::hir_ty_lowering::FeedConstTy;
 use rustc_hir_analysis::{lower_const_arg_for_rustdoc, lower_ty};
 use rustc_middle::metadata::Reexport;
@@ -886,6 +886,10 @@ fn clean_ty_generics_inner<'tcx>(
             if b.is_sized_bound(cx) {
                 has_sized = true;
                 false
+            } else if b.is_meta_sized_bound(cx) {
+                // FIXME(sized-hierarchy): Always skip `MetaSized` bounds so that only `?Sized`
+                // is shown and none of the new sizedness traits leak into documentation.
+                false
             } else {
                 true
             }
@@ -1448,6 +1452,13 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
                     }
                     _ => true,
                 });
+
+                bounds.retain(|b| {
+                    // FIXME(sized-hierarchy): Always skip `MetaSized` bounds so that only `?Sized`
+                    // is shown and none of the new sizedness traits leak into documentation.
+                    !b.is_meta_sized_bound(cx)
+                });
+
                 // Our Sized/?Sized bound didn't get handled when creating the generics
                 // because we didn't actually get our whole set of bounds until just now
                 // (some of them may have come from the trait). If we do have a sized
@@ -2276,6 +2287,12 @@ fn clean_middle_opaque_bounds<'tcx>(
                 _ => return None,
             };
 
+            // FIXME(sized-hierarchy): Always skip `MetaSized` bounds so that only `?Sized`
+            // is shown and none of the new sizedness traits leak into documentation.
+            if cx.tcx.is_lang_item(trait_ref.def_id(), LangItem::MetaSized) {
+                return None;
+            }
+
             if let Some(sized) = cx.tcx.lang_items().sized_trait()
                 && trait_ref.def_id() == sized
             {
diff --git a/src/librustdoc/clean/simplify.rs b/src/librustdoc/clean/simplify.rs
index 40efa997868..f813e6c5517 100644
--- a/src/librustdoc/clean/simplify.rs
+++ b/src/librustdoc/clean/simplify.rs
@@ -135,11 +135,17 @@ pub(crate) fn sized_bounds(cx: &mut DocContext<'_>, generics: &mut clean::Generi
     // don't actually know the set of associated types right here so that
     // should be handled when cleaning associated types.
     generics.where_predicates.retain(|pred| {
-        if let WP::BoundPredicate { ty: clean::Generic(param), bounds, .. } = pred
-            && bounds.iter().any(|b| b.is_sized_bound(cx))
-        {
+        let WP::BoundPredicate { ty: clean::Generic(param), bounds, .. } = pred else {
+            return true;
+        };
+
+        if bounds.iter().any(|b| b.is_sized_bound(cx)) {
             sized_params.insert(*param);
             false
+        } else if bounds.iter().any(|b| b.is_meta_sized_bound(cx)) {
+            // FIXME(sized-hierarchy): Always skip `MetaSized` bounds so that only `?Sized`
+            // is shown and none of the new sizedness traits leak into documentation.
+            false
         } else {
             true
         }
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 58e05bd1e85..2d9670a3d10 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1289,11 +1289,19 @@ impl GenericBound {
     }
 
     pub(crate) fn is_sized_bound(&self, cx: &DocContext<'_>) -> bool {
+        self.is_bounded_by_lang_item(cx, LangItem::Sized)
+    }
+
+    pub(crate) fn is_meta_sized_bound(&self, cx: &DocContext<'_>) -> bool {
+        self.is_bounded_by_lang_item(cx, LangItem::MetaSized)
+    }
+
+    fn is_bounded_by_lang_item(&self, cx: &DocContext<'_>, lang_item: LangItem) -> bool {
         if let GenericBound::TraitBound(
             PolyTrait { ref trait_, .. },
             rustc_hir::TraitBoundModifiers::NONE,
         ) = *self
-            && Some(trait_.def_id()) == cx.tcx.lang_items().sized_trait()
+            && cx.tcx.is_lang_item(trait_.def_id(), lang_item)
         {
             return true;
         }
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index 33738f7a242..fb2b45802a6 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -477,11 +477,7 @@ impl SourcesPart {
         // This needs to be `var`, not `const`.
         // This variable needs declared in the current global scope so that if
         // src-script.js loads first, it can pick it up.
-        SortedTemplate::from_before_after(
-            r"var srcIndex = new Map(JSON.parse('[",
-            r"]'));
-createSrcSidebar();",
-        )
+        SortedTemplate::from_before_after(r"createSrcSidebar('[", r"]');")
     }
 
     fn get(cx: &Context<'_>, crate_name: &OrderedJson) -> Result<PartsAndLocations<Self>, Error> {
diff --git a/src/librustdoc/html/render/write_shared/tests.rs b/src/librustdoc/html/render/write_shared/tests.rs
index a235f1d3724..6f185e85345 100644
--- a/src/librustdoc/html/render/write_shared/tests.rs
+++ b/src/librustdoc/html/render/write_shared/tests.rs
@@ -22,23 +22,11 @@ fn but_last_line(s: &str) -> &str {
 #[test]
 fn sources_template() {
     let mut template = SourcesPart::blank();
-    assert_eq!(
-        but_last_line(&template.to_string()),
-        r"var srcIndex = new Map(JSON.parse('[]'));
-createSrcSidebar();"
-    );
+    assert_eq!(but_last_line(&template.to_string()), r"createSrcSidebar('[]');");
     template.append(EscapedJson::from(OrderedJson::serialize("u").unwrap()).to_string());
-    assert_eq!(
-        but_last_line(&template.to_string()),
-        r#"var srcIndex = new Map(JSON.parse('["u"]'));
-createSrcSidebar();"#
-    );
+    assert_eq!(but_last_line(&template.to_string()), r#"createSrcSidebar('["u"]');"#);
     template.append(EscapedJson::from(OrderedJson::serialize("v").unwrap()).to_string());
-    assert_eq!(
-        but_last_line(&template.to_string()),
-        r#"var srcIndex = new Map(JSON.parse('["u","v"]'));
-createSrcSidebar();"#
-    );
+    assert_eq!(but_last_line(&template.to_string()), r#"createSrcSidebar('["u","v"]');"#);
 }
 
 #[test]
diff --git a/src/librustdoc/html/static/.eslintrc.js b/src/librustdoc/html/static/.eslintrc.js
index fbb096fe9c7..303c5667140 100644
--- a/src/librustdoc/html/static/.eslintrc.js
+++ b/src/librustdoc/html/static/.eslintrc.js
@@ -91,5 +91,6 @@ module.exports = {
         "no-script-url": "error",
         "no-sequences": "error",
         "no-div-regex": "error",
+        "no-console": "error",
     }
 };
diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts
index 0d2e19e019f..6af16441de8 100644
--- a/src/librustdoc/html/static/js/rustdoc.d.ts
+++ b/src/librustdoc/html/static/js/rustdoc.d.ts
@@ -4,8 +4,6 @@
 
 /* eslint-disable */
 declare global {
-    /** Map from crate name to directory structure, for source view */
-    declare var srcIndex: Map<string, rustdoc.Dir>;
     /** Defined and documented in `storage.js` */
     declare function nonnull(x: T|null, msg: string|undefined);
     /** Defined and documented in `storage.js` */
@@ -64,7 +62,7 @@ declare global {
          * create's the sidebar in source code view.
          * called in generated `src-files.js`.
          */
-        createSrcSidebar?: function(),
+        createSrcSidebar?: function(string),
         /**
          * Set up event listeners for a scraped source example.
          */
@@ -129,7 +127,7 @@ declare namespace rustdoc {
 
     /**
      * A single parsed "atom" in a search query. For example,
-     * 
+     *
      *     std::fmt::Formatter, Write -> Result<()>
      *     ┏━━━━━━━━━━━━━━━━━━  ┌────    ┏━━━━━┅┅┅┅┄┄┄┄┄┄┄┄┄┄┄┄┄┄┐
      *     ┃                    │        ┗ QueryElement {        ┊
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index dce5fddb317..b611a3e501d 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -1133,6 +1133,7 @@ class RoaringBitmap {
         }
         for (let j = 0; j < size; ++j) {
             if (offsets && offsets[j] !== i) {
+                // eslint-disable-next-line no-console
                 console.log(this.containers);
                 throw new Error(`corrupt bitmap ${j}: ${i} / ${offsets[j]}`);
             }
diff --git a/src/librustdoc/html/static/js/src-script.js b/src/librustdoc/html/static/js/src-script.js
index b9ab6e85603..0c6afbeed22 100644
--- a/src/librustdoc/html/static/js/src-script.js
+++ b/src/librustdoc/html/static/js/src-script.js
@@ -1,6 +1,3 @@
-// From rust:
-/* global srcIndex */
-
 // Local js definitions:
 /* global addClass, onEachLazy, removeClass, browserSupportsHistoryApi */
 /* global updateLocalStorage, getVar, nonnull */
@@ -100,11 +97,15 @@ window.rustdocToggleSrcSidebar = () => {
 
 // This function is called from "src-files.js", generated in `html/render/write_shared.rs`.
 // eslint-disable-next-line no-unused-vars
-function createSrcSidebar() {
+/**
+ * @param {string} srcIndexStr - strinified json map from crate name to dir structure
+ */
+function createSrcSidebar(srcIndexStr) {
     const container = nonnull(document.querySelector("nav.sidebar"));
 
     const sidebar = document.createElement("div");
     sidebar.id = "src-sidebar";
+    const srcIndex = new Map(JSON.parse(srcIndexStr));
 
     let hasFoundFile = false;
 
diff --git a/src/llvm-project b/src/llvm-project
-Subproject c1118fdbb3024157df7f4cfe765f2b0b4339e8a
+Subproject ed6566573eb21b00a3f87815e14ff766fd56ef4
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 8a3ab6f8640..1f93895ae07 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -30,7 +30,15 @@ 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 = 46;
+//
+// WARNING: When you update `FORMAT_VERSION`, please also update the "Latest feature" line with a
+// description of the change. This minimizes the risk of two concurrent PRs changing
+// `FORMAT_VERSION` from N to N+1 and git merging them without conflicts; the "Latest feature" line
+// will instead cause conflicts. See #94591 for more. (This paragraph and the "Latest feature" line
+// are deliberately not in a doc comment, because they need not be in public docs.)
+//
+// Latest feature: Pretty printing of inline attributes changed
+pub const FORMAT_VERSION: u32 = 48;
 
 /// The root of the emitted JSON blob.
 ///
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject fc1518ef02b77327d70d4026b95ea719dd9b8c5
+Subproject 2251525ae503fa196f6d7f9ce6d32eccb2d5f04
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 cb63fadb4e2..58e51128a0d 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs
@@ -1,29 +1,22 @@
 use super::INLINE_ALWAYS;
-use super::utils::is_word;
 use clippy_utils::diagnostics::span_lint;
+use rustc_attr_data_structures::{find_attr, AttributeKind, InlineAttr};
 use rustc_hir::Attribute;
 use rustc_lint::LateContext;
 use rustc_span::symbol::Symbol;
-use rustc_span::{Span, sym};
+use rustc_span::Span;
 
 pub(super) fn check(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribute]) {
     if span.from_expansion() {
         return;
     }
 
-    for attr in attrs {
-        if let Some(values) = attr.meta_item_list() {
-            if values.len() != 1 || !attr.has_name(sym::inline) {
-                continue;
-            }
-            if is_word(&values[0], sym::always) {
-                span_lint(
-                    cx,
-                    INLINE_ALWAYS,
-                    attr.span(),
-                    format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"),
-                );
-            }
-        }
+    if let Some(span) = find_attr!(attrs, AttributeKind::Inline(InlineAttr::Always, span) => *span) {
+        span_lint(
+            cx,
+            INLINE_ALWAYS,
+            span,
+            format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"),
+        );
     }
 }
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 da5ca5e6772..617c006795b 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
@@ -1,10 +1,10 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::sugg::DiagExt;
+use rustc_attr_data_structures::{find_attr, AttributeKind};
 use rustc_errors::Applicability;
 use rustc_hir::{TraitFn, TraitItem, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
-use rustc_span::sym;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -32,15 +32,19 @@ declare_lint_pass!(InlineFnWithoutBody => [INLINE_FN_WITHOUT_BODY]);
 impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody {
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) {
         if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind
-            && let Some(attr) = cx.tcx.hir_attrs(item.hir_id()).iter().find(|a| a.has_name(sym::inline))
+            && let Some(attr_span) = find_attr!(cx
+                .tcx
+                .hir_attrs(item.hir_id()),
+                AttributeKind::Inline(_, span) => *span
+        )
         {
             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/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index fdccf1fb33d..769526d131b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -388,9 +388,11 @@ fn check_other_call_arg<'tcx>(
         && let (input, n_refs) = peel_middle_ty_refs(*input)
         && let (trait_predicates, _) = get_input_traits_and_projections(cx, callee_def_id, input)
         && let Some(sized_def_id) = cx.tcx.lang_items().sized_trait()
+        && let Some(meta_sized_def_id) = cx.tcx.lang_items().meta_sized_trait()
         && let [trait_predicate] = trait_predicates
             .iter()
             .filter(|trait_predicate| trait_predicate.def_id() != sized_def_id)
+            .filter(|trait_predicate| trait_predicate.def_id() != meta_sized_def_id)
             .collect::<Vec<_>>()[..]
         && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
         && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef)
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index 1f613171b46..f835bbb7c56 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -1,10 +1,11 @@
 use clippy_utils::diagnostics::span_lint;
+use rustc_attr_data_structures::{find_attr, AttributeKind};
 use rustc_hir as hir;
 use rustc_hir::Attribute;
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty::AssocItemContainer;
 use rustc_session::declare_lint_pass;
-use rustc_span::{Span, sym};
+use rustc_span::Span;
 
 declare_clippy_lint! {
     /// ### What it does
@@ -64,8 +65,7 @@ declare_clippy_lint! {
 }
 
 fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[Attribute], sp: Span, desc: &'static str) {
-    let has_inline = attrs.iter().any(|a| a.has_name(sym::inline));
-    if !has_inline {
+    if !find_attr!(attrs, AttributeKind::Inline(..)) {
         span_lint(
             cx,
             MISSING_INLINE_IN_PUBLIC_ITEMS,
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
index 2efb55b9880..8d2f8029112 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
@@ -174,6 +174,7 @@ fn needless_borrow_count<'tcx>(
 ) -> usize {
     let destruct_trait_def_id = cx.tcx.lang_items().destruct_trait();
     let sized_trait_def_id = cx.tcx.lang_items().sized_trait();
+    let meta_sized_trait_def_id = cx.tcx.lang_items().meta_sized_trait();
     let drop_trait_def_id = cx.tcx.lang_items().drop_trait();
 
     let fn_sig = cx.tcx.fn_sig(fn_id).instantiate_identity().skip_binder();
@@ -209,6 +210,7 @@ fn needless_borrow_count<'tcx>(
         .all(|trait_def_id| {
             Some(trait_def_id) == destruct_trait_def_id
                 || Some(trait_def_id) == sized_trait_def_id
+                || Some(trait_def_id) == meta_sized_trait_def_id
                 || cx.tcx.is_diagnostic_item(sym::Any, trait_def_id)
         })
     {
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 95623467b81..9aede1dec93 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -116,13 +116,16 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
         ];
 
         let sized_trait = need!(cx.tcx.lang_items().sized_trait());
+        let meta_sized_trait = need!(cx.tcx.lang_items().meta_sized_trait());
 
         let preds = traits::elaborate(cx.tcx, cx.param_env.caller_bounds().iter())
             .filter(|p| !p.is_global())
             .filter_map(|pred| {
                 // Note that we do not want to deal with qualified predicates here.
                 match pred.kind().no_bound_vars() {
-                    Some(ty::ClauseKind::Trait(pred)) if pred.def_id() != sized_trait => Some(pred),
+                    Some(ty::ClauseKind::Trait(pred))
+                        if pred.def_id() != sized_trait && pred.def_id() != meta_sized_trait
+                            => Some(pred),
                     _ => None,
                 }
             })
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index dadf49b64e5..e18bdfb34ac 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -3,10 +3,10 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet;
 use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy};
 use clippy_utils::{is_self, is_self_ty};
+use rustc_attr_data_structures::{find_attr, AttributeKind, InlineAttr};
+use rustc_data_structures::fx::FxHashSet;
 use core::ops::ControlFlow;
 use rustc_abi::ExternAbi;
-use rustc_ast::attr;
-use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::intravisit::FnKind;
@@ -270,11 +270,13 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue {
                     return;
                 }
                 let attrs = cx.tcx.hir_attrs(hir_id);
+                if find_attr!(attrs, AttributeKind::Inline(InlineAttr::Always, _)) {
+                    return;
+                }
+
                 for a in attrs {
-                    if let Some(meta_items) = a.meta_item_list()
-                        && (a.has_name(sym::proc_macro_derive)
-                            || (a.has_name(sym::inline) && attr::list_contains_name(&meta_items, sym::always)))
-                    {
+                    // FIXME(jdonszelmann): make part of the find_attr above
+                    if a.has_name(sym::proc_macro_derive) {
                         return;
                     }
                 }
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index b839b6f5672..bd8420917f5 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -128,7 +128,7 @@ fn remove_all_parens(pat: &mut P<Pat>) {
     }
 
     impl MutVisitor for Visitor {
-        fn visit_pat(&mut self, pat: &mut P<Pat>) {
+        fn visit_pat(&mut self, pat: &mut Pat) {
             let is_inner = mem::replace(&mut self.is_inner, true);
             walk_pat(self, pat);
             let inner = match &mut pat.kind {
@@ -145,7 +145,7 @@ fn remove_all_parens(pat: &mut P<Pat>) {
 fn insert_necessary_parens(pat: &mut P<Pat>) {
     struct Visitor;
     impl MutVisitor for Visitor {
-        fn visit_pat(&mut self, pat: &mut P<Pat>) {
+        fn visit_pat(&mut self, pat: &mut Pat) {
             use ast::BindingMode;
             walk_pat(self, pat);
             let target = match &mut pat.kind {
@@ -167,7 +167,7 @@ fn unnest_or_patterns(pat: &mut P<Pat>) -> bool {
         changed: bool,
     }
     impl MutVisitor for Visitor {
-        fn visit_pat(&mut self, p: &mut P<Pat>) {
+        fn visit_pat(&mut self, p: &mut Pat) {
             // This is a bottom up transformation, so recurse first.
             walk_pat(self, p);
 
diff --git a/src/tools/clippy/tests/ui/def_id_nocore.rs b/src/tools/clippy/tests/ui/def_id_nocore.rs
index 40f40f7ea09..5c13d862276 100644
--- a/src/tools/clippy/tests/ui/def_id_nocore.rs
+++ b/src/tools/clippy/tests/ui/def_id_nocore.rs
@@ -7,8 +7,14 @@
 #[link(name = "c")]
 unsafe extern "C" {}
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-pub trait Sized {}
+pub trait Sized: MetaSized {}
 #[lang = "copy"]
 pub trait Copy {}
 #[lang = "freeze"]
diff --git a/src/tools/clippy/tests/ui/def_id_nocore.stderr b/src/tools/clippy/tests/ui/def_id_nocore.stderr
index 2718217313f..175dd075408 100644
--- a/src/tools/clippy/tests/ui/def_id_nocore.stderr
+++ b/src/tools/clippy/tests/ui/def_id_nocore.stderr
@@ -1,5 +1,5 @@
 error: methods called `as_*` usually take `self` by reference or `self` by mutable reference
-  --> tests/ui/def_id_nocore.rs:27:19
+  --> tests/ui/def_id_nocore.rs:33:19
    |
 LL |     pub fn as_ref(self) -> &'static str {
    |                   ^^^^
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 68f7d14f57f..e96c81d5b1d 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -16,7 +16,7 @@
 #![feature(unqualified_local_imports)]
 #![feature(derive_coerce_pointee)]
 #![feature(arbitrary_self_types)]
-#![feature(file_lock)]
+#![cfg_attr(bootstrap, feature(file_lock))]
 // Configure clippy and other lints
 #![allow(
     clippy::collapsible_else_if,
diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs
index acf258f4eed..030c2e36721 100644
--- a/src/tools/miri/src/shims/native_lib.rs
+++ b/src/tools/miri/src/shims/native_lib.rs
@@ -72,7 +72,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
             }
             // Functions with no declared return type (i.e., the default return)
             // have the output_type `Tuple([])`.
-            ty::Tuple(t_list) if t_list.is_empty() => {
+            ty::Tuple(t_list) if (*t_list).deref().is_empty() => {
                 unsafe { ffi::call::<()>(ptr, libffi_args.as_slice()) };
                 return interp_ok(ImmTy::uninit(dest.layout));
             }
diff --git a/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr
index 32446a8e1ce..ec578db2d0a 100644
--- a/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr
+++ b/src/tools/miri/tests/fail/stacked_borrows/drop_in_place_retag.stderr
@@ -1,8 +1,8 @@
 error: Undefined Behavior: trying to retag from <TAG> for Unique permission at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location
   --> RUSTLIB/core/src/ptr/mod.rs:LL:CC
    |
-LL | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this error occurs as part of retag at ALLOC[0x0..0x1]
+LL | pub unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this error occurs as part of retag at ALLOC[0x0..0x1]
    |
    = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
    = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
diff --git a/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr
index 1a8509a0b13..72aeb0fdf8e 100644
--- a/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr
+++ b/src/tools/miri/tests/fail/unaligned_pointers/drop_in_place.stderr
@@ -1,8 +1,8 @@
 error: Undefined Behavior: constructing invalid value: encountered an unaligned reference (required ALIGN byte alignment but found ALIGN)
   --> RUSTLIB/core/src/ptr/mod.rs:LL:CC
    |
-LL | pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
+LL | pub unsafe fn drop_in_place<T: PointeeSized>(to_drop: *mut T) {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs
index 2f30827c933..9d5725773e6 100644
--- a/src/tools/miri/tests/pass/shims/fs.rs
+++ b/src/tools/miri/tests/pass/shims/fs.rs
@@ -2,7 +2,6 @@
 
 #![feature(io_error_more)]
 #![feature(io_error_uncategorized)]
-#![feature(file_lock)]
 
 use std::collections::BTreeMap;
 use std::ffi::OsString;
diff --git a/src/tools/rust-analyzer/.typos.toml b/src/tools/rust-analyzer/.typos.toml
index e938bddd4b1..cdbc003a808 100644
--- a/src/tools/rust-analyzer/.typos.toml
+++ b/src/tools/rust-analyzer/.typos.toml
@@ -18,6 +18,7 @@ extend-ignore-re = [
     "INOUT",
     "optin",
     "=Pn",
+    "\\[[0-9A-F]{4},",  # AstId hex hashes
     # ignore `// spellchecker:off` until `// spellchecker:on`
     "(?s)(#|//)\\s*spellchecker:off.*?\\n\\s*(#|//)\\s*spellchecker:on",
 ]
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 01de430925d..2c7b4641641 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -13,9 +13,9 @@ dependencies = [
 
 [[package]]
 name = "adler2"
-version = "2.0.0"
+version = "2.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
+checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
 
 [[package]]
 name = "allocator-api2"
@@ -25,9 +25,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
 
 [[package]]
 name = "anyhow"
-version = "1.0.97"
+version = "1.0.98"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f"
+checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
 
 [[package]]
 name = "arbitrary"
@@ -100,51 +100,68 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bitflags"
-version = "2.9.0"
+version = "2.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
+checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
 
 [[package]]
 name = "borsh"
-version = "1.5.5"
+version = "1.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5430e3be710b68d984d1391c854eb431a9d548640711faa54eecb1df93db91cc"
+checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce"
 dependencies = [
  "cfg_aliases",
 ]
 
 [[package]]
 name = "boxcar"
-version = "0.2.12"
+version = "0.2.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "66bb12751a83493ef4b8da1120451a262554e216a247f14b48cb5e8fe7ed8bdf"
+checksum = "26c4925bc979b677330a8c7fe7a8c94af2dbb4a2d37b4a20a80d884400f46baa"
 
 [[package]]
 name = "camino"
-version = "1.1.9"
+version = "1.1.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3"
+checksum = "0da45bc31171d8d6960122e222a67740df867c1dd53b4d51caa297084c185cab"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "cargo-platform"
-version = "0.1.9"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea"
+checksum = "84982c6c0ae343635a3a4ee6dedef965513735c8b183caa7289fa6e27399ebd4"
 dependencies = [
  "serde",
 ]
 
 [[package]]
+name = "cargo-util-schemas"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e63d2780ac94487eb9f1fea7b0d56300abc9eb488800854ca217f102f5caccca"
+dependencies = [
+ "semver",
+ "serde",
+ "serde-untagged",
+ "serde-value",
+ "thiserror 1.0.69",
+ "toml",
+ "unicode-xid",
+ "url",
+]
+
+[[package]]
 name = "cargo_metadata"
-version = "0.19.2"
+version = "0.20.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba"
+checksum = "4f7835cfc6135093070e95eb2b53e5d9b5c403dc3a6be6040ee026270aa82502"
 dependencies = [
  "camino",
  "cargo-platform",
+ "cargo-util-schemas",
  "semver",
  "serde",
  "serde_json",
@@ -153,9 +170,9 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.2.16"
+version = "1.2.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
+checksum = "956a5e21988b87f372569b66183b78babf23ebc2e744b733e4350a752c4dafac"
 dependencies = [
  "shlex",
 ]
@@ -178,9 +195,9 @@ dependencies = [
 
 [[package]]
 name = "cfg-if"
-version = "1.0.0"
+version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
 
 [[package]]
 name = "cfg_aliases"
@@ -190,9 +207,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
 
 [[package]]
 name = "chalk-derive"
-version = "0.102.0"
+version = "0.103.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "feb14e3ff0ebac26d8e58b6ed1417afb60c4a0a44b6425546ee7eb9c75ebb336"
+checksum = "eb4899682de915ca7c0b025bdd0a3d34c75fe12184122fda6805a7baddaa293c"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -202,19 +219,19 @@ dependencies = [
 
 [[package]]
 name = "chalk-ir"
-version = "0.102.0"
+version = "0.103.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72f0a61621a088af69fee8df39ec63cf5b6d0b9ab663a740cdeb376aabf2f244"
+checksum = "90a37d2ab99352b4caca135061e7b4ac67024b648c28ed0b787feec4bea4caed"
 dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
  "chalk-derive",
 ]
 
 [[package]]
 name = "chalk-recursive"
-version = "0.102.0"
+version = "0.103.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cbd3415cc540015533aa4a8ad007696d585dd9c5f81e7c099872f1dd4bf14894"
+checksum = "c855be60e646664bc37c2496d3dc81ca5ef60520930e5e0f0057a0575aff6c19"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -225,9 +242,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-solve"
-version = "0.102.0"
+version = "0.103.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "747707b0c082b3ecf4b1ae28d0d8df708a46cddd22a386f9cc85a312a4de25ff"
+checksum = "477ac6cdfd2013e9f93b09b036c2b607a67b2e728f4777b8422d55a79e9e3a34"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -374,7 +391,7 @@ dependencies = [
  "libc",
  "option-ext",
  "redox_users",
- "windows-sys 0.59.0",
+ "windows-sys 0.60.2",
 ]
 
 [[package]]
@@ -432,6 +449,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
 
 [[package]]
+name = "erased-serde"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7"
+dependencies = [
+ "serde",
+ "typeid",
+]
+
+[[package]]
 name = "expect-test"
 version = "1.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -461,9 +488,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
 
 [[package]]
 name = "flate2"
-version = "1.1.1"
+version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
+checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d"
 dependencies = [
  "crc32fast",
  "miniz_oxide",
@@ -471,9 +498,9 @@ dependencies = [
 
 [[package]]
 name = "foldhash"
-version = "0.1.4"
+version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
+checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
 
 [[package]]
 name = "form_urlencoded"
@@ -501,9 +528,9 @@ checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a"
 
 [[package]]
 name = "getrandom"
-version = "0.2.15"
+version = "0.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
+checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
 dependencies = [
  "cfg-if",
  "libc",
@@ -524,9 +551,9 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
 
 [[package]]
 name = "hashbrown"
-version = "0.15.2"
+version = "0.15.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
+checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
 dependencies = [
  "allocator-api2",
  "equivalent",
@@ -539,7 +566,7 @@ version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1"
 dependencies = [
- "hashbrown 0.15.2",
+ "hashbrown 0.15.4",
 ]
 
 [[package]]
@@ -550,9 +577,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
 
 [[package]]
 name = "hermit-abi"
-version = "0.3.9"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
 
 [[package]]
 name = "hir"
@@ -588,7 +615,7 @@ version = "0.0.0"
 dependencies = [
  "arrayvec",
  "base-db",
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
  "cfg",
  "cov-mark",
  "drop_bomb",
@@ -655,7 +682,7 @@ version = "0.0.0"
 dependencies = [
  "arrayvec",
  "base-db",
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
  "chalk-derive",
  "chalk-ir",
  "chalk-recursive",
@@ -705,21 +732,22 @@ dependencies = [
 
 [[package]]
 name = "icu_collections"
-version = "1.5.0"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
+checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47"
 dependencies = [
  "displaydoc",
+ "potential_utf",
  "yoke",
  "zerofrom",
  "zerovec",
 ]
 
 [[package]]
-name = "icu_locid"
-version = "1.5.0"
+name = "icu_locale_core"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
+checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a"
 dependencies = [
  "displaydoc",
  "litemap",
@@ -729,30 +757,10 @@ dependencies = [
 ]
 
 [[package]]
-name = "icu_locid_transform"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
-dependencies = [
- "displaydoc",
- "icu_locid",
- "icu_locid_transform_data",
- "icu_provider",
- "tinystr",
- "zerovec",
-]
-
-[[package]]
-name = "icu_locid_transform_data"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
-
-[[package]]
 name = "icu_normalizer"
-version = "1.5.0"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
+checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979"
 dependencies = [
  "displaydoc",
  "icu_collections",
@@ -760,68 +768,55 @@ dependencies = [
  "icu_properties",
  "icu_provider",
  "smallvec",
- "utf16_iter",
- "utf8_iter",
- "write16",
  "zerovec",
 ]
 
 [[package]]
 name = "icu_normalizer_data"
-version = "1.5.0"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
+checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3"
 
 [[package]]
 name = "icu_properties"
-version = "1.5.1"
+version = "2.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
+checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b"
 dependencies = [
  "displaydoc",
  "icu_collections",
- "icu_locid_transform",
+ "icu_locale_core",
  "icu_properties_data",
  "icu_provider",
- "tinystr",
+ "potential_utf",
+ "zerotrie",
  "zerovec",
 ]
 
 [[package]]
 name = "icu_properties_data"
-version = "1.5.0"
+version = "2.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
+checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632"
 
 [[package]]
 name = "icu_provider"
-version = "1.5.0"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
+checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af"
 dependencies = [
  "displaydoc",
- "icu_locid",
- "icu_provider_macros",
+ "icu_locale_core",
  "stable_deref_trait",
  "tinystr",
  "writeable",
  "yoke",
  "zerofrom",
+ "zerotrie",
  "zerovec",
 ]
 
 [[package]]
-name = "icu_provider_macros"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
 name = "ide"
 version = "0.0.0"
 dependencies = [
@@ -898,7 +893,7 @@ version = "0.0.0"
 dependencies = [
  "arrayvec",
  "base-db",
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
  "cov-mark",
  "crossbeam-channel",
  "either",
@@ -976,9 +971,9 @@ dependencies = [
 
 [[package]]
 name = "idna_adapter"
-version = "1.2.0"
+version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
+checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
 dependencies = [
  "icu_normalizer",
  "icu_properties",
@@ -991,7 +986,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
 dependencies = [
  "equivalent",
- "hashbrown 0.15.2",
+ "hashbrown 0.15.4",
  "serde",
 ]
 
@@ -1001,7 +996,7 @@ version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3"
 dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
  "inotify-sys",
  "libc",
 ]
@@ -1057,9 +1052,9 @@ checksum = "a037eddb7d28de1d0fc42411f501b53b75838d313908078d6698d064f3029b24"
 
 [[package]]
 name = "kqueue"
-version = "1.0.8"
+version = "1.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c"
+checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a"
 dependencies = [
  "kqueue-sys",
  "libc",
@@ -1099,19 +1094,19 @@ checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
 
 [[package]]
 name = "libloading"
-version = "0.8.7"
+version = "0.8.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c"
+checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
 dependencies = [
  "cfg-if",
- "windows-targets 0.53.0",
+ "windows-targets 0.53.2",
 ]
 
 [[package]]
 name = "libmimalloc-sys"
-version = "0.1.40"
+version = "0.1.42"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07d0e07885d6a754b9c7993f2625187ad694ee985d60f23355ff0e7077261502"
+checksum = "ec9d6fac27761dabcd4ee73571cdb06b7022dc99089acbe5435691edffaac0f4"
 dependencies = [
  "cc",
  "libc",
@@ -1123,7 +1118,7 @@ version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
 dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
  "libc",
  "redox_syscall",
 ]
@@ -1149,9 +1144,9 @@ dependencies = [
 
 [[package]]
 name = "litemap"
-version = "0.7.5"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856"
+checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
 
 [[package]]
 name = "load-cargo"
@@ -1174,9 +1169,9 @@ dependencies = [
 
 [[package]]
 name = "lock_api"
-version = "0.4.12"
+version = "0.4.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
+checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
 dependencies = [
  "autocfg",
  "scopeguard",
@@ -1184,9 +1179,9 @@ dependencies = [
 
 [[package]]
 name = "log"
-version = "0.4.26"
+version = "0.4.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
+checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
 
 [[package]]
 name = "lsp-server"
@@ -1249,9 +1244,9 @@ dependencies = [
 
 [[package]]
 name = "memchr"
-version = "2.7.4"
+version = "2.7.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
 
 [[package]]
 name = "memmap2"
@@ -1273,32 +1268,32 @@ dependencies = [
 
 [[package]]
 name = "mimalloc"
-version = "0.1.44"
+version = "0.1.46"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99585191385958383e13f6b822e6b6d8d9cf928e7d286ceb092da92b43c87bc1"
+checksum = "995942f432bbb4822a7e9c3faa87a695185b0d09273ba85f097b54f4e458f2af"
 dependencies = [
  "libmimalloc-sys",
 ]
 
 [[package]]
 name = "miniz_oxide"
-version = "0.8.5"
+version = "0.8.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5"
+checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316"
 dependencies = [
  "adler2",
 ]
 
 [[package]]
 name = "mio"
-version = "1.0.3"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
+checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
 dependencies = [
  "libc",
  "log",
  "wasi",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -1316,7 +1311,7 @@ version = "0.30.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
 dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
  "cfg-if",
  "cfg_aliases",
  "libc",
@@ -1334,7 +1329,7 @@ version = "8.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943"
 dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
  "filetime",
  "fsevent-sys",
  "inotify",
@@ -1369,10 +1364,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
 
 [[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
 name = "num_cpus"
-version = "1.16.0"
+version = "1.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
+checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
 dependencies = [
  "hermit-abi",
  "libc",
@@ -1398,9 +1402,9 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.21.1"
+version = "1.21.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc"
+checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
 
 [[package]]
 name = "oorandom"
@@ -1415,10 +1419,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
 
 [[package]]
+name = "ordered-float"
+version = "2.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
 name = "parking_lot"
-version = "0.12.3"
+version = "0.12.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
+checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13"
 dependencies = [
  "lock_api",
  "parking_lot_core",
@@ -1426,9 +1439,9 @@ dependencies = [
 
 [[package]]
 name = "parking_lot_core"
-version = "0.9.10"
+version = "0.9.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
+checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
 dependencies = [
  "cfg-if",
  "libc",
@@ -1445,7 +1458,7 @@ dependencies = [
  "edition",
  "expect-test",
  "ra-ap-rustc_lexer",
- "rustc-literal-escaper",
+ "rustc-literal-escaper 0.0.3",
  "stdx",
  "tracing",
 ]
@@ -1506,9 +1519,18 @@ checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b"
 
 [[package]]
 name = "portable-atomic"
-version = "1.11.0"
+version = "1.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
+checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
+
+[[package]]
+name = "potential_utf"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585"
+dependencies = [
+ "zerovec",
+]
 
 [[package]]
 name = "powerfmt"
@@ -1569,9 +1591,9 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.94"
+version = "1.0.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
+checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
 dependencies = [
  "unicode-ident",
 ]
@@ -1596,7 +1618,7 @@ dependencies = [
  "libc",
  "perf-event",
  "tikv-jemalloc-ctl",
- "windows-sys 0.59.0",
+ "windows-sys 0.60.2",
 ]
 
 [[package]]
@@ -1650,7 +1672,7 @@ version = "0.9.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b"
 dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
  "memchr",
  "unicase",
 ]
@@ -1687,11 +1709,11 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_abi"
-version = "0.113.0"
+version = "0.116.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c33b8fa229789975647ca5426be432c7c327ebde89ab15889928185dbcee3230"
+checksum = "a967e3a9cd3e38b543f503978e0eccee461e3aea3f7b10e944959bff41dbe612"
 dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
  "ra-ap-rustc_hashes",
  "ra-ap-rustc_index",
  "tracing",
@@ -1699,18 +1721,18 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_hashes"
-version = "0.113.0"
+version = "0.116.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0d68a3e389927002f552938a90b04787f6435f55b46fc5691360470d1cb2e99d"
+checksum = "1ea4c755ecbbffa5743c251344f484ebe571ec7bc5b36d80b2a8ae775d1a7a40"
 dependencies = [
  "rustc-stable-hash",
 ]
 
 [[package]]
 name = "ra-ap-rustc_index"
-version = "0.113.0"
+version = "0.116.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32502273df2838d0ca13f1c67e2a48feef940e591f9771869f07e2db2acede53"
+checksum = "aca7ad7cf911538c619caa2162339fe98637e9e46f11bb0484ef96735df4d64a"
 dependencies = [
  "ra-ap-rustc_index_macros",
  "smallvec",
@@ -1718,9 +1740,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_index_macros"
-version = "0.113.0"
+version = "0.116.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a32f081864ae34c7ae6634edfa7a95ab9260ba85015e8b1d347580eda79d14f"
+checksum = "8767ba551c9355bc3031be072cc4bb0381106e5e7cd275e72b7a8c76051c4070"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1729,9 +1751,9 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_lexer"
-version = "0.113.0"
+version = "0.116.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed34c51974718c5bd90d876d1364d9725159fc8030c2382b9cb837034152ed68"
+checksum = "6101374afb267e6c27e4e2eb0b1352e9f3504c1a8f716f619cd39244e2ed92ab"
 dependencies = [
  "memchr",
  "unicode-properties",
@@ -1740,19 +1762,19 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_parse_format"
-version = "0.113.0"
+version = "0.116.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff0440e5d27facbf4ff13ea651e48c2f6e360b3dbfc56251b41d60719b965fb8"
+checksum = "ecd88a19f00da4f43e6727d5013444cbc399804b5046dfa2bbcd28ebed3970ce"
 dependencies = [
  "ra-ap-rustc_lexer",
- "rustc-literal-escaper",
+ "rustc-literal-escaper 0.0.2",
 ]
 
 [[package]]
 name = "ra-ap-rustc_pattern_analysis"
-version = "0.113.0"
+version = "0.116.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a6056efa57aba3aa0cc69a0bf1a8281624c23ad25b05748d11ebcd4668037bfc"
+checksum = "bb332dd32d7850a799862533b1c021e6062558861a4ad57817bf522499fbb892"
 dependencies = [
  "ra-ap-rustc_index",
  "rustc-hash 2.1.1",
@@ -1783,11 +1805,11 @@ dependencies = [
 
 [[package]]
 name = "redox_syscall"
-version = "0.5.10"
+version = "0.5.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1"
+checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6"
 dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
 ]
 
 [[package]]
@@ -1874,16 +1896,16 @@ dependencies = [
  "vfs",
  "vfs-notify",
  "walkdir",
- "windows-sys 0.59.0",
+ "windows-sys 0.60.2",
  "xflags",
  "xshell",
 ]
 
 [[package]]
 name = "rustc-demangle"
-version = "0.1.24"
+version = "0.1.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
+checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
 
 [[package]]
 name = "rustc-hash"
@@ -1904,6 +1926,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0041b6238913c41fe704213a4a9329e2f685a156d1781998128b4149c230ad04"
 
 [[package]]
+name = "rustc-literal-escaper"
+version = "0.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78744cd17f5d01c75b709e49807d1363e02a940ccee2e9e72435843fdb0d076e"
+
+[[package]]
 name = "rustc-stable-hash"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1911,11 +1939,11 @@ checksum = "781442f29170c5c93b7185ad559492601acdc71d5bb0706f5868094f45cfcd08"
 
 [[package]]
 name = "rustc_apfloat"
-version = "0.2.2+llvm-462a31f5a5ab"
+version = "0.2.3+llvm-462a31f5a5ab"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "121e2195ff969977a4e2b5c9965ea867fce7e4cb5aee5b09dee698a7932d574f"
+checksum = "486c2179b4796f65bfe2ee33679acf0927ac83ecf583ad6c91c3b4570911b9ad"
 dependencies = [
- "bitflags 2.9.0",
+ "bitflags 2.9.1",
  "smallvec",
 ]
 
@@ -1934,7 +1962,7 @@ dependencies = [
  "boxcar",
  "crossbeam-queue",
  "dashmap",
- "hashbrown 0.15.2",
+ "hashbrown 0.15.4",
  "hashlink",
  "indexmap",
  "parking_lot",
@@ -2016,6 +2044,27 @@ dependencies = [
 ]
 
 [[package]]
+name = "serde-untagged"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "299d9c19d7d466db4ab10addd5703e4c615dec2a5a16dbbafe191045e87ee66e"
+dependencies = [
+ "erased-serde",
+ "serde",
+ "typeid",
+]
+
+[[package]]
+name = "serde-value"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c"
+dependencies = [
+ "ordered-float",
+ "serde",
+]
+
+[[package]]
 name = "serde_derive"
 version = "1.0.219"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2052,9 +2101,9 @@ dependencies = [
 
 [[package]]
 name = "serde_spanned"
-version = "0.6.8"
+version = "0.6.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
+checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
 dependencies = [
  "serde",
 ]
@@ -2076,9 +2125,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
 
 [[package]]
 name = "smallvec"
-version = "1.14.0"
+version = "1.15.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
+checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
 
 [[package]]
 name = "smol_str"
@@ -2122,14 +2171,14 @@ dependencies = [
  "libc",
  "miow",
  "tracing",
- "windows-sys 0.59.0",
+ "windows-sys 0.60.2",
 ]
 
 [[package]]
 name = "syn"
-version = "2.0.100"
+version = "2.0.103"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
+checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2138,9 +2187,9 @@ dependencies = [
 
 [[package]]
 name = "synstructure"
-version = "0.13.1"
+version = "0.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
+checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2158,7 +2207,7 @@ dependencies = [
  "rayon",
  "rowan",
  "rustc-hash 2.1.1",
- "rustc-literal-escaper",
+ "rustc-literal-escaper 0.0.3",
  "rustc_apfloat",
  "smol_str",
  "stdx",
@@ -2183,9 +2232,9 @@ dependencies = [
 
 [[package]]
 name = "tenthash"
-version = "1.0.0"
+version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d092d622df8bb64e5de8dc86a3667702d5f1e0fe2f0604c6035540703c8cd1e"
+checksum = "e5c4bcc0a4fa333239f43662d15fbf995f384b2aeaf89c4ab4c83353d6cbb952"
 
 [[package]]
 name = "test-fixture"
@@ -2270,12 +2319,11 @@ dependencies = [
 
 [[package]]
 name = "thread_local"
-version = "1.1.8"
+version = "1.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c"
+checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
 dependencies = [
  "cfg-if",
- "once_cell",
 ]
 
 [[package]]
@@ -2311,9 +2359,9 @@ dependencies = [
 
 [[package]]
 name = "time"
-version = "0.3.40"
+version = "0.3.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d9c75b47bdff86fa3334a3db91356b8d7d86a9b839dab7d0bdc5c3d3a077618"
+checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
 dependencies = [
  "deranged",
  "itoa",
@@ -2334,9 +2382,9 @@ checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
 
 [[package]]
 name = "time-macros"
-version = "0.2.21"
+version = "0.2.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29aa485584182073ed57fd5004aa09c371f021325014694e432313345865fd04"
+checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
 dependencies = [
  "num-conv",
  "time-core",
@@ -2344,9 +2392,9 @@ dependencies = [
 
 [[package]]
 name = "tinystr"
-version = "0.7.6"
+version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
+checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b"
 dependencies = [
  "displaydoc",
  "zerovec",
@@ -2354,9 +2402,9 @@ dependencies = [
 
 [[package]]
 name = "toml"
-version = "0.8.20"
+version = "0.8.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148"
+checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
 dependencies = [
  "serde",
  "serde_spanned",
@@ -2366,27 +2414,34 @@ dependencies = [
 
 [[package]]
 name = "toml_datetime"
-version = "0.6.8"
+version = "0.6.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
+checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "toml_edit"
-version = "0.22.24"
+version = "0.22.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
+checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
 dependencies = [
  "indexmap",
  "serde",
  "serde_spanned",
  "toml_datetime",
+ "toml_write",
  "winnow",
 ]
 
 [[package]]
+name = "toml_write"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801"
+
+[[package]]
 name = "toolchain"
 version = "0.0.0"
 dependencies = [
@@ -2407,9 +2462,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-attributes"
-version = "0.1.28"
+version = "0.1.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
+checksum = "1b1ffbcf9c6f6b99d386e7444eb608ba646ae452a36b39737deb9663b610f662"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2418,9 +2473,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-core"
-version = "0.1.33"
+version = "0.1.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
+checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
 dependencies = [
  "once_cell",
  "valuable",
@@ -2486,6 +2541,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
 
 [[package]]
+name = "typeid"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c"
+
+[[package]]
 name = "ungrammar"
 version = "1.16.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2528,12 +2589,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "utf16_iter"
-version = "1.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
-
-[[package]]
 name = "utf8_iter"
 version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2586,9 +2641,9 @@ dependencies = [
 
 [[package]]
 name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
+version = "0.11.1+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
 
 [[package]]
 name = "winapi-util"
@@ -2601,9 +2656,9 @@ dependencies = [
 
 [[package]]
 name = "windows"
-version = "0.61.1"
+version = "0.61.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419"
+checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
 dependencies = [
  "windows-collections",
  "windows-core",
@@ -2623,9 +2678,9 @@ dependencies = [
 
 [[package]]
 name = "windows-core"
-version = "0.61.0"
+version = "0.61.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
+checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
 dependencies = [
  "windows-implement",
  "windows-interface",
@@ -2636,12 +2691,13 @@ dependencies = [
 
 [[package]]
 name = "windows-future"
-version = "0.2.0"
+version = "0.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32"
+checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
 dependencies = [
  "windows-core",
  "windows-link",
+ "windows-threading",
 ]
 
 [[package]]
@@ -2668,9 +2724,9 @@ dependencies = [
 
 [[package]]
 name = "windows-link"
-version = "0.1.1"
+version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
+checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
 
 [[package]]
 name = "windows-numerics"
@@ -2684,18 +2740,18 @@ dependencies = [
 
 [[package]]
 name = "windows-result"
-version = "0.3.2"
+version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
+checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
 dependencies = [
  "windows-link",
 ]
 
 [[package]]
 name = "windows-strings"
-version = "0.4.0"
+version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
+checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
 dependencies = [
  "windows-link",
 ]
@@ -2728,6 +2784,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "windows-sys"
+version = "0.60.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
+dependencies = [
+ "windows-targets 0.53.2",
+]
+
+[[package]]
 name = "windows-targets"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2760,9 +2825,9 @@ dependencies = [
 
 [[package]]
 name = "windows-targets"
-version = "0.53.0"
+version = "0.53.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b"
+checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef"
 dependencies = [
  "windows_aarch64_gnullvm 0.53.0",
  "windows_aarch64_msvc 0.53.0",
@@ -2775,6 +2840,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "windows-threading"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
 name = "windows_aarch64_gnullvm"
 version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2914,9 +2988,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
 
 [[package]]
 name = "winnow"
-version = "0.7.3"
+version = "0.7.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1"
+checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd"
 dependencies = [
  "memchr",
 ]
@@ -2928,16 +3002,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "23f6174b2566cc4a74f95e1367ec343e7fa80c93cc8087f5c4a3d6a1088b2118"
 
 [[package]]
-name = "write16"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
-
-[[package]]
 name = "writeable"
-version = "0.5.5"
+version = "0.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
+checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb"
 
 [[package]]
 name = "xflags"
@@ -2992,9 +3060,9 @@ dependencies = [
 
 [[package]]
 name = "yoke"
-version = "0.7.5"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
+checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc"
 dependencies = [
  "serde",
  "stable_deref_trait",
@@ -3004,9 +3072,9 @@ dependencies = [
 
 [[package]]
 name = "yoke-derive"
-version = "0.7.5"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
+checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3036,10 +3104,21 @@ dependencies = [
 ]
 
 [[package]]
+name = "zerotrie"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595"
+dependencies = [
+ "displaydoc",
+ "yoke",
+ "zerofrom",
+]
+
+[[package]]
 name = "zerovec"
-version = "0.10.4"
+version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
+checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428"
 dependencies = [
  "yoke",
  "zerofrom",
@@ -3048,9 +3127,9 @@ dependencies = [
 
 [[package]]
 name = "zerovec-derive"
-version = "0.10.3"
+version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
+checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3059,9 +3138,9 @@ dependencies = [
 
 [[package]]
 name = "zip"
-version = "3.0.0"
+version = "4.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12598812502ed0105f607f941c386f43d441e00148fce9dec3ca5ffb0bde9308"
+checksum = "153a6fff49d264c4babdcfa6b4d534747f520e56e8f0f384f3b808c4b64cc1fd"
 dependencies = [
  "arbitrary",
  "crc32fast",
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 975fe277b22..449c75859cf 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -87,11 +87,11 @@ 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.113", default-features = false }
-ra-ap-rustc_parse_format = { version = "0.113", default-features = false }
-ra-ap-rustc_index = { version = "0.113", default-features = false }
-ra-ap-rustc_abi = { version = "0.113", default-features = false }
-ra-ap-rustc_pattern_analysis = { version = "0.113", default-features = false }
+ra-ap-rustc_lexer = { version = "0.116", default-features = false }
+ra-ap-rustc_parse_format = { version = "0.116", default-features = false }
+ra-ap-rustc_index = { version = "0.116", default-features = false }
+ra-ap-rustc_abi = { version = "0.116", default-features = false }
+ra-ap-rustc_pattern_analysis = { version = "0.116", default-features = false }
 
 # local crates that aren't published to crates.io. These should not have versions.
 
@@ -101,24 +101,24 @@ la-arena = { version = "0.3.1" }
 lsp-server = { version = "0.7.8" }
 
 # non-local crates
-anyhow = "1.0.97"
+anyhow = "1.0.98"
 arrayvec = "0.7.6"
-bitflags = "2.9.0"
-cargo_metadata = "0.19.2"
-camino = "1.1.9"
-chalk-solve = { version = "0.102.0", default-features = false }
-chalk-ir = "0.102.0"
-chalk-recursive = { version = "0.102.0", default-features = false }
-chalk-derive = "0.102.0"
+bitflags = "2.9.1"
+cargo_metadata = "0.20.0"
+camino = "1.1.10"
+chalk-solve = { version = "0.103.0", default-features = false }
+chalk-ir = "0.103.0"
+chalk-recursive = { version = "0.103.0", default-features = false }
+chalk-derive = "0.103.0"
 crossbeam-channel = "0.5.15"
 dissimilar = "1.0.10"
 dot = "0.1.4"
 either = "1.15.0"
 expect-test = "1.5.1"
-indexmap = { version = "2.8.0", features = ["serde"] }
+indexmap = { version = "2.9.0", features = ["serde"] }
 itertools = "0.14.0"
-libc = "0.2.171"
-libloading = "0.8.6"
+libc = "0.2.172"
+libloading = "0.8.8"
 memmap2 = "0.9.5"
 nohash-hasher = "0.2.0"
 oorandom = "11.1.5"
@@ -129,20 +129,22 @@ object = { version = "0.36.7", default-features = false, features = [
   "macho",
   "pe",
 ] }
-process-wrap = { version = "8.2.0", features = ["std"] }
+process-wrap = { version = "8.2.1", features = ["std"] }
 pulldown-cmark-to-cmark = "10.0.4"
 pulldown-cmark = { version = "0.9.6", default-features = false }
 rayon = "1.10.0"
 rowan = "=0.15.15"
-salsa = { version = "0.22.0", default-features = false, features = ["rayon","salsa_unstable"] }
+# Ideally we'd not enable the macros feature but unfortunately the `tracked` attribute does not work
+# on impls without it
+salsa = { version = "0.22.0", default-features = true, features = ["rayon","salsa_unstable", "macros"] }
 salsa-macros = "0.22.0"
 semver = "1.0.26"
 serde = { version = "1.0.219" }
 serde_derive = { version = "1.0.219" }
 serde_json = "1.0.140"
 rustc-hash = "2.1.1"
-rustc-literal-escaper = "0.0.2"
-smallvec = { version = "1.14.0", features = [
+rustc-literal-escaper = "0.0.3"
+smallvec = { version = "1.15.1", features = [
   "const_new",
   "union",
   "const_generics",
@@ -166,7 +168,7 @@ xshell = "0.2.7"
 # We need to freeze the version of the crate, as the raw-api feature is considered unstable
 dashmap = { version = "=6.1.0", features = ["raw-api", "inline"] }
 # We need to freeze the version of the crate, as it needs to match with dashmap
-hashbrown = { version = "0.14.0", features = [
+hashbrown = { version = "0.14.*", features = [
   "inline-more",
 ], default-features = false }
 
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 745238167bc..2a87b152487 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/input.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs
@@ -20,12 +20,10 @@ use span::Edition;
 use triomphe::Arc;
 use vfs::{AbsPathBuf, AnchoredPath, FileId, VfsPath, file_set::FileSet};
 
-use crate::{CrateWorkspaceData, EditionedFileId, RootQueryDb};
+use crate::{CrateWorkspaceData, EditionedFileId, FxIndexSet, RootQueryDb};
 
 pub type ProcMacroPaths = FxHashMap<CrateBuilderId, Result<(String, AbsPathBuf), String>>;
 
-type FxIndexSet<T> = indexmap::IndexSet<T, FxBuildHasher>;
-
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
 pub struct SourceRootId(pub u32);
 
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 4d4e6cae037..478fae67c80 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
@@ -28,6 +28,8 @@ use syntax::{Parse, SyntaxError, ast};
 use triomphe::Arc;
 pub use vfs::{AnchoredPath, AnchoredPathBuf, FileId, VfsPath, file_set::FileSet};
 
+pub type FxIndexSet<T> = indexmap::IndexSet<T, rustc_hash::FxBuildHasher>;
+
 #[macro_export]
 macro_rules! impl_intern_key {
     ($id:ident, $loc:ident) => {
diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
index c1c89e8d1cc..c6922eca49f 100644
--- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
@@ -25,7 +25,7 @@ rustc-hash.workspace = true
 tracing.workspace = true
 smallvec.workspace = true
 triomphe.workspace = true
-rustc_apfloat = "0.2.2"
+rustc_apfloat = "0.2.3"
 text-size.workspace = true
 salsa.workspace = true
 salsa-macros.workspace = true
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
index bb6222b1d46..b509e69b0d3 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
@@ -14,6 +14,7 @@ use intern::{Symbol, sym};
 use la_arena::{ArenaMap, Idx, RawIdx};
 use mbe::DelimiterKind;
 use rustc_abi::ReprOptions;
+use span::AstIdNode;
 use syntax::{
     AstPtr,
     ast::{self, HasAttrs},
@@ -22,10 +23,10 @@ use triomphe::Arc;
 use tt::iter::{TtElement, TtIter};
 
 use crate::{
-    AdtId, AttrDefId, GenericParamId, HasModule, ItemTreeLoc, LocalFieldId, Lookup, MacroId,
+    AdtId, AstIdLoc, AttrDefId, GenericParamId, HasModule, LocalFieldId, Lookup, MacroId,
     VariantId,
     db::DefDatabase,
-    item_tree::{AttrOwner, FieldParent, ItemTreeNode},
+    item_tree::block_item_tree_query,
     lang_item::LangItem,
     nameres::{ModuleOrigin, ModuleSource},
     src::{HasChildSource, HasSource},
@@ -42,6 +43,15 @@ pub struct AttrsWithOwner {
 }
 
 impl Attrs {
+    pub fn new(
+        db: &dyn DefDatabase,
+        owner: &dyn ast::HasAttrs,
+        span_map: SpanMapRef<'_>,
+        cfg_options: &CfgOptions,
+    ) -> Self {
+        Attrs(RawAttrs::new_expanded(db, owner, span_map, cfg_options))
+    }
+
     pub fn get(&self, id: AttrId) -> Option<&Attr> {
         (**self).iter().find(|attr| attr.id == id)
     }
@@ -94,44 +104,64 @@ impl Attrs {
         v: VariantId,
     ) -> Arc<ArenaMap<LocalFieldId, Attrs>> {
         let _p = tracing::info_span!("fields_attrs_query").entered();
-        // FIXME: There should be some proper form of mapping between item tree field ids and hir field ids
         let mut res = ArenaMap::default();
-        let item_tree;
-        let (parent, fields, krate) = match v {
+        let (fields, file_id, krate) = match v {
             VariantId::EnumVariantId(it) => {
                 let loc = it.lookup(db);
                 let krate = loc.parent.lookup(db).container.krate;
-                item_tree = loc.id.item_tree(db);
-                let variant = &item_tree[loc.id.value];
-                (FieldParent::EnumVariant(loc.id.value), &variant.fields, krate)
+                let source = loc.source(db);
+                (source.value.field_list(), source.file_id, krate)
             }
             VariantId::StructId(it) => {
                 let loc = it.lookup(db);
                 let krate = loc.container.krate;
-                item_tree = loc.id.item_tree(db);
-                let struct_ = &item_tree[loc.id.value];
-                (FieldParent::Struct(loc.id.value), &struct_.fields, krate)
+                let source = loc.source(db);
+                (source.value.field_list(), source.file_id, krate)
             }
             VariantId::UnionId(it) => {
                 let loc = it.lookup(db);
                 let krate = loc.container.krate;
-                item_tree = loc.id.item_tree(db);
-                let union_ = &item_tree[loc.id.value];
-                (FieldParent::Union(loc.id.value), &union_.fields, krate)
+                let source = loc.source(db);
+                (
+                    source.value.record_field_list().map(ast::FieldList::RecordFieldList),
+                    source.file_id,
+                    krate,
+                )
             }
         };
+        let Some(fields) = fields else {
+            return Arc::new(res);
+        };
 
         let cfg_options = krate.cfg_options(db);
-
-        let mut idx = 0;
-        for (id, _field) in fields.iter().enumerate() {
-            let attrs = item_tree.attrs(db, krate, AttrOwner::make_field_indexed(parent, id));
-            if attrs.is_cfg_enabled(cfg_options) {
-                res.insert(Idx::from_raw(RawIdx::from(idx)), attrs);
-                idx += 1;
+        let span_map = db.span_map(file_id);
+
+        match fields {
+            ast::FieldList::RecordFieldList(fields) => {
+                let mut idx = 0;
+                for field in fields.fields() {
+                    let attrs =
+                        Attrs(RawAttrs::new_expanded(db, &field, span_map.as_ref(), cfg_options));
+                    if attrs.is_cfg_enabled(cfg_options).is_ok() {
+                        res.insert(Idx::from_raw(RawIdx::from(idx)), attrs);
+                        idx += 1;
+                    }
+                }
+            }
+            ast::FieldList::TupleFieldList(fields) => {
+                let mut idx = 0;
+                for field in fields.fields() {
+                    let attrs =
+                        Attrs(RawAttrs::new_expanded(db, &field, span_map.as_ref(), cfg_options));
+                    if attrs.is_cfg_enabled(cfg_options).is_ok() {
+                        res.insert(Idx::from_raw(RawIdx::from(idx)), attrs);
+                        idx += 1;
+                    }
+                }
             }
         }
 
+        res.shrink_to_fit();
         Arc::new(res)
     }
 }
@@ -167,11 +197,10 @@ impl Attrs {
     }
 
     #[inline]
-    pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> bool {
-        match self.cfg() {
-            None => true,
-            Some(cfg) => cfg_options.check(&cfg) != Some(false),
-        }
+    pub(crate) fn is_cfg_enabled(&self, cfg_options: &CfgOptions) -> Result<(), CfgExpr> {
+        self.cfgs().try_for_each(|cfg| {
+            if cfg_options.check(&cfg) != Some(false) { Ok(()) } else { Err(cfg) }
+        })
     }
 
     #[inline]
@@ -488,61 +517,59 @@ impl AttrsWithOwner {
     pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs {
         let _p = tracing::info_span!("attrs_query").entered();
         // FIXME: this should use `Trace` to avoid duplication in `source_map` below
-        let raw_attrs = match def {
+        match def {
             AttrDefId::ModuleId(module) => {
                 let def_map = module.def_map(db);
                 let mod_data = &def_map[module.local_id];
 
-                match mod_data.origin {
-                    ModuleOrigin::File { definition, declaration_tree_id, .. } => {
+                let raw_attrs = match mod_data.origin {
+                    ModuleOrigin::File { definition, declaration_tree_id, declaration, .. } => {
                         let decl_attrs = declaration_tree_id
                             .item_tree(db)
-                            .raw_attrs(AttrOwner::ModItem(declaration_tree_id.value.into()))
+                            .raw_attrs(declaration.upcast())
                             .clone();
                         let tree = db.file_item_tree(definition.into());
-                        let def_attrs = tree.raw_attrs(AttrOwner::TopLevel).clone();
+                        let def_attrs = tree.top_level_raw_attrs().clone();
                         decl_attrs.merge(def_attrs)
                     }
                     ModuleOrigin::CrateRoot { definition } => {
                         let tree = db.file_item_tree(definition.into());
-                        tree.raw_attrs(AttrOwner::TopLevel).clone()
+                        tree.top_level_raw_attrs().clone()
+                    }
+                    ModuleOrigin::Inline { definition_tree_id, definition } => {
+                        definition_tree_id.item_tree(db).raw_attrs(definition.upcast()).clone()
                     }
-                    ModuleOrigin::Inline { definition_tree_id, .. } => definition_tree_id
-                        .item_tree(db)
-                        .raw_attrs(AttrOwner::ModItem(definition_tree_id.value.into()))
-                        .clone(),
                     ModuleOrigin::BlockExpr { id, .. } => {
-                        let tree = db.block_item_tree(id);
-                        tree.raw_attrs(AttrOwner::TopLevel).clone()
+                        let tree = block_item_tree_query(db, id);
+                        tree.top_level_raw_attrs().clone()
                     }
-                }
-            }
-            AttrDefId::FieldId(it) => {
-                return db.fields_attrs(it.parent)[it.local_id].clone();
+                };
+                Attrs::expand_cfg_attr(db, module.krate, raw_attrs)
             }
-            AttrDefId::EnumVariantId(it) => attrs_from_item_tree_loc(db, it),
+            AttrDefId::FieldId(it) => db.fields_attrs(it.parent)[it.local_id].clone(),
+            AttrDefId::EnumVariantId(it) => attrs_from_ast_id_loc(db, it),
             AttrDefId::AdtId(it) => match it {
-                AdtId::StructId(it) => attrs_from_item_tree_loc(db, it),
-                AdtId::EnumId(it) => attrs_from_item_tree_loc(db, it),
-                AdtId::UnionId(it) => attrs_from_item_tree_loc(db, it),
+                AdtId::StructId(it) => attrs_from_ast_id_loc(db, it),
+                AdtId::EnumId(it) => attrs_from_ast_id_loc(db, it),
+                AdtId::UnionId(it) => attrs_from_ast_id_loc(db, it),
             },
-            AttrDefId::TraitId(it) => attrs_from_item_tree_loc(db, it),
-            AttrDefId::TraitAliasId(it) => attrs_from_item_tree_loc(db, it),
+            AttrDefId::TraitId(it) => attrs_from_ast_id_loc(db, it),
+            AttrDefId::TraitAliasId(it) => attrs_from_ast_id_loc(db, it),
             AttrDefId::MacroId(it) => match it {
-                MacroId::Macro2Id(it) => attrs_from_item_tree_loc(db, it),
-                MacroId::MacroRulesId(it) => attrs_from_item_tree_loc(db, it),
-                MacroId::ProcMacroId(it) => attrs_from_item_tree_loc(db, it),
+                MacroId::Macro2Id(it) => attrs_from_ast_id_loc(db, it),
+                MacroId::MacroRulesId(it) => attrs_from_ast_id_loc(db, it),
+                MacroId::ProcMacroId(it) => attrs_from_ast_id_loc(db, it),
             },
-            AttrDefId::ImplId(it) => attrs_from_item_tree_loc(db, it),
-            AttrDefId::ConstId(it) => attrs_from_item_tree_loc(db, it),
-            AttrDefId::StaticId(it) => attrs_from_item_tree_loc(db, it),
-            AttrDefId::FunctionId(it) => attrs_from_item_tree_loc(db, it),
-            AttrDefId::TypeAliasId(it) => attrs_from_item_tree_loc(db, it),
+            AttrDefId::ImplId(it) => attrs_from_ast_id_loc(db, it),
+            AttrDefId::ConstId(it) => attrs_from_ast_id_loc(db, it),
+            AttrDefId::StaticId(it) => attrs_from_ast_id_loc(db, it),
+            AttrDefId::FunctionId(it) => attrs_from_ast_id_loc(db, it),
+            AttrDefId::TypeAliasId(it) => attrs_from_ast_id_loc(db, it),
             AttrDefId::GenericParamId(it) => match it {
                 GenericParamId::ConstParamId(it) => {
                     let src = it.parent().child_source(db);
                     // FIXME: We should be never getting `None` here.
-                    return Attrs(match src.value.get(it.local_id()) {
+                    Attrs(match src.value.get(it.local_id()) {
                         Some(val) => RawAttrs::new_expanded(
                             db,
                             val,
@@ -550,12 +577,12 @@ impl AttrsWithOwner {
                             def.krate(db).cfg_options(db),
                         ),
                         None => RawAttrs::EMPTY,
-                    });
+                    })
                 }
                 GenericParamId::TypeParamId(it) => {
                     let src = it.parent().child_source(db);
                     // FIXME: We should be never getting `None` here.
-                    return Attrs(match src.value.get(it.local_id()) {
+                    Attrs(match src.value.get(it.local_id()) {
                         Some(val) => RawAttrs::new_expanded(
                             db,
                             val,
@@ -563,12 +590,12 @@ impl AttrsWithOwner {
                             def.krate(db).cfg_options(db),
                         ),
                         None => RawAttrs::EMPTY,
-                    });
+                    })
                 }
                 GenericParamId::LifetimeParamId(it) => {
                     let src = it.parent.child_source(db);
                     // FIXME: We should be never getting `None` here.
-                    return Attrs(match src.value.get(it.local_id) {
+                    Attrs(match src.value.get(it.local_id) {
                         Some(val) => RawAttrs::new_expanded(
                             db,
                             val,
@@ -576,16 +603,13 @@ impl AttrsWithOwner {
                             def.krate(db).cfg_options(db),
                         ),
                         None => RawAttrs::EMPTY,
-                    });
+                    })
                 }
             },
-            AttrDefId::ExternBlockId(it) => attrs_from_item_tree_loc(db, it),
-            AttrDefId::ExternCrateId(it) => attrs_from_item_tree_loc(db, it),
-            AttrDefId::UseId(it) => attrs_from_item_tree_loc(db, it),
-        };
-
-        let attrs = raw_attrs.expand_cfg_attr(db, def.krate(db));
-        Attrs(attrs)
+            AttrDefId::ExternBlockId(it) => attrs_from_ast_id_loc(db, it),
+            AttrDefId::ExternCrateId(it) => attrs_from_ast_id_loc(db, it),
+            AttrDefId::UseId(it) => attrs_from_ast_id_loc(db, it),
+        }
     }
 
     pub fn source_map(&self, db: &dyn DefDatabase) -> AttrSourceMap {
@@ -787,14 +811,15 @@ fn any_has_attrs<'db>(
     id.lookup(db).source(db).map(ast::AnyHasAttrs::new)
 }
 
-fn attrs_from_item_tree_loc<'db, N: ItemTreeNode>(
+fn attrs_from_ast_id_loc<'db, N: AstIdNode + HasAttrs>(
     db: &(dyn DefDatabase + 'db),
-    lookup: impl Lookup<Database = dyn DefDatabase, Data = impl ItemTreeLoc<Id = N>>,
-) -> RawAttrs {
-    let id = lookup.lookup(db).item_tree_id();
-    let tree = id.item_tree(db);
-    let attr_owner = N::attr_owner(id.value);
-    tree.raw_attrs(attr_owner).clone()
+    lookup: impl Lookup<Database = dyn DefDatabase, Data = impl AstIdLoc<Ast = N> + HasModule>,
+) -> Attrs {
+    let loc = lookup.lookup(db);
+    let source = loc.source(db);
+    let span_map = db.span_map(source.file_id);
+    let cfg_options = loc.krate(db).cfg_options(db);
+    Attrs(RawAttrs::new_expanded(db, &source.value, span_map.as_ref(), cfg_options))
 }
 
 pub(crate) fn fields_attrs_source_map(
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
index 4a9a3b12cfa..c618e4bdce7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
@@ -1,18 +1,20 @@
 //! Defines database & queries for name resolution.
 use base_db::{Crate, RootQueryDb, SourceDatabase};
 use either::Either;
-use hir_expand::{EditionedFileId, HirFileId, MacroCallId, MacroDefId, db::ExpandDatabase};
+use hir_expand::{
+    EditionedFileId, HirFileId, InFile, Lookup, MacroCallId, MacroDefId, MacroDefKind,
+    db::ExpandDatabase,
+};
 use intern::sym;
 use la_arena::ArenaMap;
 use syntax::{AstPtr, ast};
-use thin_vec::ThinVec;
 use triomphe::Arc;
 
 use crate::{
-    AttrDefId, BlockId, BlockLoc, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, EnumVariantId,
+    AssocItemId, AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, EnumVariantId,
     EnumVariantLoc, ExternBlockId, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId,
-    FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroId,
-    MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId,
+    FunctionLoc, GenericDefId, ImplId, ImplLoc, LocalFieldId, Macro2Id, Macro2Loc, MacroExpander,
+    MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ProcMacroId, ProcMacroLoc, StaticId,
     StaticLoc, StructId, StructLoc, TraitAliasId, TraitAliasLoc, TraitId, TraitLoc, TypeAliasId,
     TypeAliasLoc, UnionId, UnionLoc, UseId, UseLoc, VariantId,
     attr::{Attrs, AttrsWithOwner},
@@ -21,17 +23,13 @@ use crate::{
     },
     hir::generics::GenericParams,
     import_map::ImportMap,
-    item_tree::{AttrOwner, ItemTree},
+    item_tree::{ItemTree, file_item_tree_query},
     lang_item::{self, LangItem},
-    nameres::{
-        assoc::{ImplItems, TraitItems},
-        crate_def_map,
-        diagnostics::DefDiagnostics,
-    },
+    nameres::{assoc::TraitItems, crate_def_map, diagnostics::DefDiagnostics},
     signatures::{
-        ConstSignature, EnumSignature, EnumVariants, FunctionSignature, ImplSignature,
-        InactiveEnumVariantCode, StaticSignature, StructSignature, TraitAliasSignature,
-        TraitSignature, TypeAliasSignature, UnionSignature, VariantFields,
+        ConstSignature, EnumSignature, FunctionSignature, ImplSignature, StaticSignature,
+        StructSignature, TraitAliasSignature, TraitSignature, TypeAliasSignature, UnionSignature,
+        VariantFields,
     },
     tt,
     visibility::{self, Visibility},
@@ -93,9 +91,6 @@ pub trait InternDatabase: RootQueryDb {
     #[salsa::interned]
     fn intern_macro_rules(&self, loc: MacroRulesLoc) -> MacroRulesId;
     // // endregion: items
-
-    #[salsa::interned]
-    fn intern_block(&self, loc: BlockLoc) -> BlockId;
 }
 
 #[query_group::query_group]
@@ -105,11 +100,9 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase {
     fn expand_proc_attr_macros(&self) -> bool;
 
     /// Computes an [`ItemTree`] for the given file or macro expansion.
-    #[salsa::invoke(ItemTree::file_item_tree_query)]
-    fn file_item_tree(&self, file_id: HirFileId) -> Arc<ItemTree>;
-
-    #[salsa::invoke(ItemTree::block_item_tree_query)]
-    fn block_item_tree(&self, block_id: BlockId) -> Arc<ItemTree>;
+    #[salsa::invoke(file_item_tree_query)]
+    #[salsa::transparent]
+    fn file_item_tree(&self, file_id: HirFileId) -> &ItemTree;
 
     /// Turns a MacroId into a MacroDefId, describing the macro's definition post name resolution.
     #[salsa::invoke(macro_def)]
@@ -123,24 +116,6 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase {
         id: VariantId,
     ) -> (Arc<VariantFields>, Arc<ExpressionStoreSourceMap>);
 
-    #[salsa::tracked]
-    fn enum_variants(&self, id: EnumId) -> Arc<EnumVariants> {
-        self.enum_variants_with_diagnostics(id).0
-    }
-
-    #[salsa::invoke(EnumVariants::enum_variants_query)]
-    fn enum_variants_with_diagnostics(
-        &self,
-        id: EnumId,
-    ) -> (Arc<EnumVariants>, Option<Arc<ThinVec<InactiveEnumVariantCode>>>);
-
-    #[salsa::transparent]
-    #[salsa::invoke(ImplItems::impl_items_query)]
-    fn impl_items(&self, e: ImplId) -> Arc<ImplItems>;
-
-    #[salsa::invoke(ImplItems::impl_items_with_diagnostics_query)]
-    fn impl_items_with_diagnostics(&self, e: ImplId) -> (Arc<ImplItems>, DefDiagnostics);
-
     #[salsa::transparent]
     #[salsa::invoke(TraitItems::trait_items_query)]
     fn trait_items(&self, e: TraitId) -> Arc<TraitItems>;
@@ -323,16 +298,8 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase {
     #[salsa::invoke(visibility::field_visibilities_query)]
     fn field_visibilities(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Visibility>>;
 
-    // FIXME: unify function_visibility and const_visibility?
-
-    #[salsa::invoke(visibility::function_visibility_query)]
-    fn function_visibility(&self, def: FunctionId) -> Visibility;
-
-    #[salsa::invoke(visibility::const_visibility_query)]
-    fn const_visibility(&self, def: ConstId) -> Visibility;
-
-    #[salsa::invoke(visibility::type_alias_visibility_query)]
-    fn type_alias_visibility(&self, def: TypeAliasId) -> Visibility;
+    #[salsa::invoke(visibility::assoc_visibility_query)]
+    fn assoc_visibility(&self, def: AssocItemId) -> Visibility;
 
     // endregion:visibilities
 
@@ -368,7 +335,7 @@ fn include_macro_invoc(
 fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: Crate) -> bool {
     let file = crate_id.data(db).root_file_id(db);
     let item_tree = db.file_item_tree(file.into());
-    let attrs = item_tree.raw_attrs(AttrOwner::TopLevel);
+    let attrs = item_tree.top_level_raw_attrs();
     for attr in &**attrs {
         match attr.path().as_ident() {
             Some(ident) if *ident == sym::no_std => return true,
@@ -399,10 +366,6 @@ fn crate_supports_no_std(db: &dyn DefDatabase, crate_id: Crate) -> bool {
 }
 
 fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId {
-    use hir_expand::InFile;
-
-    use crate::{Lookup, MacroDefKind, MacroExpander};
-
     let kind = |expander, file_id, m| {
         let in_file = InFile::new(file_id, m);
         match expander {
@@ -418,11 +381,9 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId {
         MacroId::Macro2Id(it) => {
             let loc: Macro2Loc = it.lookup(db);
 
-            let item_tree = loc.id.item_tree(db);
-            let makro = &item_tree[loc.id.value];
             MacroDefId {
                 krate: loc.container.krate,
-                kind: kind(loc.expander, loc.id.file_id(), makro.ast_id.upcast()),
+                kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()),
                 local_inner: false,
                 allow_internal_unsafe: loc.allow_internal_unsafe,
                 edition: loc.edition,
@@ -431,11 +392,9 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId {
         MacroId::MacroRulesId(it) => {
             let loc: MacroRulesLoc = it.lookup(db);
 
-            let item_tree = loc.id.item_tree(db);
-            let makro = &item_tree[loc.id.value];
             MacroDefId {
                 krate: loc.container.krate,
-                kind: kind(loc.expander, loc.id.file_id(), makro.ast_id.upcast()),
+                kind: kind(loc.expander, loc.id.file_id, loc.id.value.upcast()),
                 local_inner: loc.flags.contains(MacroRulesLocFlags::LOCAL_INNER),
                 allow_internal_unsafe: loc
                     .flags
@@ -446,15 +405,9 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId {
         MacroId::ProcMacroId(it) => {
             let loc = it.lookup(db);
 
-            let item_tree = loc.id.item_tree(db);
-            let makro = &item_tree[loc.id.value];
             MacroDefId {
                 krate: loc.container.krate,
-                kind: MacroDefKind::ProcMacro(
-                    InFile::new(loc.id.file_id(), makro.ast_id),
-                    loc.expander,
-                    loc.kind,
-                ),
+                kind: MacroDefKind::ProcMacro(loc.id, loc.expander, loc.kind),
                 local_inner: false,
                 allow_internal_unsafe: false,
                 edition: loc.edition,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs
index 3823fb5a1e7..23b9712d1e6 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/expander.rs
@@ -6,6 +6,7 @@ use base_db::Crate;
 use cfg::CfgOptions;
 use drop_bomb::DropBomb;
 use hir_expand::AstId;
+use hir_expand::span_map::SpanMapRef;
 use hir_expand::{
     ExpandError, ExpandErrorKind, ExpandResult, HirFileId, InFile, Lookup, MacroCallId,
     eager::EagerCallBackFn, mod_path::ModPath, span_map::SpanMap,
@@ -223,9 +224,15 @@ impl Expander {
         }
     }
 
+    #[inline]
     pub(super) fn ast_id_map(&self) -> &AstIdMap {
         &self.ast_id_map
     }
+
+    #[inline]
+    pub(super) fn span_map(&self) -> SpanMapRef<'_> {
+        self.span_map.as_ref()
+    }
 }
 
 #[derive(Debug)]
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
index 29871f5e04d..03683ec9203 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
@@ -7,12 +7,14 @@ mod path;
 
 use std::mem;
 
+use base_db::FxIndexSet;
 use cfg::CfgOptions;
 use either::Either;
 use hir_expand::{
-    HirFileId, InFile, Lookup, MacroDefId,
+    HirFileId, InFile, Intern, MacroDefId,
     mod_path::tool_path,
     name::{AsName, Name},
+    span_map::SpanMapRef,
 };
 use intern::{Symbol, sym};
 use rustc_hash::FxHashMap;
@@ -30,8 +32,8 @@ use triomphe::Arc;
 use tt::TextRange;
 
 use crate::{
-    AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, ImplId, ItemTreeLoc,
-    MacroId, ModuleDefId, ModuleId, TraitAliasId, TraitId, TypeAliasId, UnresolvedMacro,
+    AdtId, BlockId, BlockLoc, DefWithBodyId, FunctionId, GenericDefId, ImplId, MacroId,
+    ModuleDefId, ModuleId, TraitAliasId, TraitId, TypeAliasId, UnresolvedMacro,
     builtin_type::BuiltinUint,
     db::DefDatabase,
     expr_store::{
@@ -65,8 +67,6 @@ use crate::{
 
 pub use self::path::hir_segment_to_ast_segment;
 
-type FxIndexSet<K> = indexmap::IndexSet<K, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
-
 pub(super) fn lower_body(
     db: &dyn DefDatabase,
     owner: DefWithBodyId,
@@ -564,6 +564,11 @@ impl ExprCollector<'_> {
         }
     }
 
+    #[inline]
+    pub(crate) fn span_map(&self) -> SpanMapRef<'_> {
+        self.expander.span_map()
+    }
+
     pub fn lower_lifetime_ref(&mut self, lifetime: ast::Lifetime) -> LifetimeRefId {
         // FIXME: Keyword check?
         let lifetime_ref = match &*lifetime.text() {
@@ -2141,26 +2146,10 @@ impl ExprCollector<'_> {
         block: ast::BlockExpr,
         mk_block: impl FnOnce(Option<BlockId>, Box<[Statement]>, Option<ExprId>) -> Expr,
     ) -> ExprId {
-        let block_has_items = {
-            let statement_has_item = block.statements().any(|stmt| match stmt {
-                ast::Stmt::Item(_) => true,
-                // Macro calls can be both items and expressions. The syntax library always treats
-                // them as expressions here, so we undo that.
-                ast::Stmt::ExprStmt(es) => matches!(es.expr(), Some(ast::Expr::MacroExpr(_))),
-                _ => false,
-            });
-            statement_has_item
-                || matches!(block.tail_expr(), Some(ast::Expr::MacroExpr(_)))
-                || (block.may_carry_attributes() && block.attrs().next().is_some())
-        };
-
-        let block_id = if block_has_items {
-            let file_local_id = self.expander.ast_id_map().ast_id(&block);
+        let block_id = self.expander.ast_id_map().ast_id_for_block(&block).map(|file_local_id| {
             let ast_id = self.expander.in_file(file_local_id);
-            Some(self.db.intern_block(BlockLoc { ast_id, module: self.module }))
-        } else {
-            None
-        };
+            BlockLoc { ast_id, module: self.module }.intern(self.db)
+        });
 
         let (module, def_map) =
             match block_id.map(|block_id| (block_def_map(self.db, block_id), block_id)) {
@@ -2260,11 +2249,8 @@ impl ExprCollector<'_> {
                     match resolved.take_values() {
                         Some(ModuleDefId::ConstId(_)) => (None, Pat::Path(name.into())),
                         Some(ModuleDefId::EnumVariantId(variant))
-                            if {
-                                let loc = variant.lookup(self.db);
-                                let tree = loc.item_tree_id().item_tree(self.db);
-                                tree[loc.id.value].shape != FieldsShape::Record
-                            } =>
+                        // FIXME: This can cause a cycle if the user is writing invalid code
+                            if self.db.variant_fields(variant.into()).shape != FieldsShape::Record =>
                         {
                             (None, Pat::Path(name.into()))
                         }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs
index f12a9b7a544..56c7655f9ea 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs
@@ -9,9 +9,10 @@ use std::{
 use hir_expand::{Lookup, mod_path::PathKind};
 use itertools::Itertools;
 use span::Edition;
+use syntax::ast::HasName;
 
 use crate::{
-    AdtId, DefWithBodyId, GenericDefId, ItemTreeLoc, TypeParamId, VariantId,
+    AdtId, DefWithBodyId, GenericDefId, TypeParamId, VariantId,
     expr_store::path::{GenericArg, GenericArgs},
     hir::{
         Array, BindingAnnotation, CaptureBy, ClosureKind, Literal, Movability, Statement,
@@ -19,6 +20,7 @@ use crate::{
     },
     lang_item::LangItemTarget,
     signatures::{FnFlags, FunctionSignature, StructSignature},
+    src::HasSource,
     type_ref::{ConstRef, LifetimeRef, Mutability, TraitBoundModifier, TypeBound, UseArgRef},
 };
 use crate::{LifetimeParamId, signatures::StructFlags};
@@ -48,6 +50,17 @@ pub enum LineFormat {
     Indentation,
 }
 
+fn item_name<Id, Loc>(db: &dyn DefDatabase, id: Id, default: &str) -> String
+where
+    Id: Lookup<Database = dyn DefDatabase, Data = Loc>,
+    Loc: HasSource,
+    Loc::Value: ast::HasName,
+{
+    let loc = id.lookup(db);
+    let source = loc.source(db);
+    source.value.name().map_or_else(|| default.to_owned(), |name| name.to_string())
+}
+
 pub fn print_body_hir(
     db: &dyn DefDatabase,
     body: &Body,
@@ -55,31 +68,14 @@ pub fn print_body_hir(
     edition: Edition,
 ) -> String {
     let header = match owner {
-        DefWithBodyId::FunctionId(it) => {
-            it.lookup(db).id.resolved(db, |it| format!("fn {}", it.name.display(db, edition)))
-        }
-        DefWithBodyId::StaticId(it) => it
-            .lookup(db)
-            .id
-            .resolved(db, |it| format!("static {} = ", it.name.display(db, edition))),
-        DefWithBodyId::ConstId(it) => it.lookup(db).id.resolved(db, |it| {
-            format!(
-                "const {} = ",
-                match &it.name {
-                    Some(name) => name.display(db, edition).to_string(),
-                    None => "_".to_owned(),
-                }
-            )
-        }),
-        DefWithBodyId::VariantId(it) => {
-            let loc = it.lookup(db);
-            let enum_loc = loc.parent.lookup(db);
-            format!(
-                "enum {}::{}",
-                enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition),
-                loc.id.item_tree(db)[loc.id.value].name.display(db, edition),
-            )
-        }
+        DefWithBodyId::FunctionId(it) => format!("fn {}", item_name(db, it, "<missing>")),
+        DefWithBodyId::StaticId(it) => format!("static {} = ", item_name(db, it, "<missing>")),
+        DefWithBodyId::ConstId(it) => format!("const {} = ", item_name(db, it, "_")),
+        DefWithBodyId::VariantId(it) => format!(
+            "enum {}::{}",
+            item_name(db, it.lookup(db).parent, "<missing>"),
+            item_name(db, it, "<missing>")
+        ),
     };
 
     let mut p = Printer {
@@ -116,22 +112,13 @@ pub fn print_body_hir(
 
 pub fn print_variant_body_hir(db: &dyn DefDatabase, owner: VariantId, edition: Edition) -> String {
     let header = match owner {
-        VariantId::StructId(it) => {
-            it.lookup(db).id.resolved(db, |it| format!("struct {}", it.name.display(db, edition)))
-        }
-        VariantId::EnumVariantId(enum_variant_id) => {
-            let loc = enum_variant_id.lookup(db);
-            let enum_loc = loc.parent.lookup(db);
-            format!(
-                "enum {}::{}",
-                enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition),
-                loc.id.item_tree(db)[loc.id.value].name.display(db, edition),
-            )
-        }
-        VariantId::UnionId(union_id) => union_id
-            .lookup(db)
-            .id
-            .resolved(db, |it| format!("union {}", it.name.display(db, edition))),
+        VariantId::StructId(it) => format!("struct {}", item_name(db, it, "<missing>")),
+        VariantId::EnumVariantId(it) => format!(
+            "enum {}::{}",
+            item_name(db, it.lookup(db).parent, "<missing>"),
+            item_name(db, it, "<missing>")
+        ),
+        VariantId::UnionId(it) => format!("union {}", item_name(db, it, "<missing>")),
     };
 
     let fields = db.variant_fields(owner);
@@ -154,9 +141,11 @@ pub fn print_variant_body_hir(db: &dyn DefDatabase, owner: VariantId, edition: E
         let FieldData { name, type_ref, visibility, is_unsafe } = data;
         match visibility {
             crate::item_tree::RawVisibility::Module(interned, _visibility_explicitness) => {
-                w!(p, "{}", interned.display(db, p.edition))
+                w!(p, "pub(in {})", interned.display(db, p.edition))
             }
             crate::item_tree::RawVisibility::Public => w!(p, "pub "),
+            crate::item_tree::RawVisibility::PubCrate => w!(p, "pub(crate) "),
+            crate::item_tree::RawVisibility::PubSelf(_) => w!(p, "pub(self) "),
         }
         if *is_unsafe {
             w!(p, "unsafe ");
@@ -1089,10 +1078,7 @@ impl Printer<'_> {
             w!(self, "builtin#lang(");
             macro_rules! write_name {
                 ($it:ident) => {{
-                    let loc = $it.lookup(self.db);
-                    let tree = loc.item_tree_id().item_tree(self.db);
-                    let name = &tree[loc.id.value].name;
-                    w!(self, "{}", name.display(self.db, self.edition));
+                    w!(self, "{}", item_name(self.db, $it, "<missing>"));
                 }};
             }
             match *it {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
index 5f7b510bba4..bb0b70bc5bf 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs
@@ -189,8 +189,8 @@ fn f() {
 }
     "#,
         expect![[r#"
-            BlockId(3c01) in BlockRelativeModuleId { block: Some(BlockId(3c00)), local_id: Idx::<ModuleData>(1) }
-            BlockId(3c00) in BlockRelativeModuleId { block: None, local_id: Idx::<ModuleData>(0) }
+            BlockIdLt { [salsa id]: Id(3c01) } in BlockRelativeModuleId { block: Some(BlockIdLt { [salsa id]: Id(3c00) }), local_id: Idx::<ModuleData>(1) }
+            BlockIdLt { [salsa id]: Id(3c00) } in BlockRelativeModuleId { block: None, local_id: Idx::<ModuleData>(0) }
             crate scope
         "#]],
     );
@@ -397,7 +397,6 @@ fn main() {
 fn underscore_import() {
     // This used to panic, because the default (private) visibility inside block expressions would
     // point into the containing `DefMap`, which visibilities should never be able to do.
-    cov_mark::check!(adjust_vis_in_block_def_map);
     check_at(
         r#"
 mod m {
@@ -457,7 +456,6 @@ fn foo() {
 #[test]
 fn is_visible_from_same_def_map() {
     // Regression test for https://github.com/rust-lang/rust-analyzer/issues/9481
-    cov_mark::check!(is_visible_from_same_block_def_map);
     check_at(
         r#"
 fn outer() {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
index bb75621c7e0..dccfff002f2 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
@@ -137,7 +137,7 @@ fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Opt
         let loc = variant.lookup(ctx.db);
         if let Some(mut path) = find_path_inner(ctx, ItemInNs::Types(loc.parent.into()), max_len) {
             path.push_segment(
-                ctx.db.enum_variants(loc.parent).variants[loc.index as usize].1.clone(),
+                loc.parent.enum_variants(ctx.db).variants[loc.index as usize].1.clone(),
             );
             return Some(path);
         }
@@ -615,6 +615,7 @@ fn find_local_import_locations(
                         cov_mark::hit!(discount_private_imports);
                         false
                     }
+                    Visibility::PubCrate(_) => true,
                     Visibility::Public => true,
                 };
 
@@ -1286,7 +1287,6 @@ $0
 
     #[test]
     fn explicit_private_imports_crate() {
-        cov_mark::check!(explicit_private_imports);
         check_found_path(
             r#"
 //- /main.rs
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
index 5362c0588db..efa43994685 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
@@ -13,13 +13,14 @@ use smallvec::{SmallVec, smallvec};
 use span::Edition;
 use stdx::format_to;
 use syntax::ast;
+use thin_vec::ThinVec;
 
 use crate::{
     AdtId, BuiltinType, ConstId, ExternBlockId, ExternCrateId, FxIndexMap, HasModule, ImplId,
     LocalModuleId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, UseId,
     db::DefDatabase,
     per_ns::{Item, MacrosItem, PerNs, TypesItem, ValuesItem},
-    visibility::{Visibility, VisibilityExplicitness},
+    visibility::Visibility,
 };
 
 #[derive(Debug, Default)]
@@ -155,22 +156,21 @@ pub struct ItemScope {
 
     /// The defs declared in this scope. Each def has a single scope where it is
     /// declared.
-    declarations: Vec<ModuleDefId>,
+    declarations: ThinVec<ModuleDefId>,
 
-    impls: Vec<ImplId>,
-    #[allow(clippy::box_collection)]
-    extern_blocks: Option<Box<Vec<ExternBlockId>>>,
-    unnamed_consts: Vec<ConstId>,
+    impls: ThinVec<ImplId>,
+    extern_blocks: ThinVec<ExternBlockId>,
+    unnamed_consts: ThinVec<ConstId>,
     /// Traits imported via `use Trait as _;`.
-    unnamed_trait_imports: FxHashMap<TraitId, Item<()>>,
+    unnamed_trait_imports: ThinVec<(TraitId, Item<()>)>,
 
     // the resolutions of the imports of this scope
     use_imports_types: FxHashMap<ImportOrExternCrate, ImportOrDef>,
     use_imports_values: FxHashMap<ImportOrGlob, ImportOrDef>,
     use_imports_macros: FxHashMap<ImportOrExternCrate, ImportOrDef>,
 
-    use_decls: Vec<UseId>,
-    extern_crate_decls: Vec<ExternCrateId>,
+    use_decls: ThinVec<UseId>,
+    extern_crate_decls: ThinVec<ExternCrateId>,
     /// Macros visible in current module in legacy textual scope
     ///
     /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first.
@@ -183,7 +183,7 @@ pub struct ItemScope {
     /// Module scoped macros will be inserted into `items` instead of here.
     // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
     // be all resolved to the last one defined if shadowing happens.
-    legacy_macros: FxHashMap<Name, SmallVec<[MacroId; 1]>>,
+    legacy_macros: FxHashMap<Name, SmallVec<[MacroId; 2]>>,
     /// The attribute macro invocations in this scope.
     attr_macros: FxHashMap<AstId<ast::Item>, MacroCallId>,
     /// The macro invocations in this scope.
@@ -198,7 +198,7 @@ struct DeriveMacroInvocation {
     attr_id: AttrId,
     /// The `#[derive]` call
     attr_call_id: MacroCallId,
-    derive_call_ids: SmallVec<[Option<MacroCallId>; 1]>,
+    derive_call_ids: SmallVec<[Option<MacroCallId>; 4]>,
 }
 
 pub(crate) static BUILTIN_SCOPE: LazyLock<FxIndexMap<Name, PerNs>> = LazyLock::new(|| {
@@ -322,7 +322,7 @@ impl ItemScope {
     }
 
     pub fn extern_blocks(&self) -> impl Iterator<Item = ExternBlockId> + '_ {
-        self.extern_blocks.iter().flat_map(|it| it.iter()).copied()
+        self.extern_blocks.iter().copied()
     }
 
     pub fn use_decls(&self) -> impl ExactSizeIterator<Item = UseId> + '_ {
@@ -435,7 +435,7 @@ impl ItemScope {
                 ModuleDefId::TraitId(t) => Some(t),
                 _ => None,
             })
-            .chain(self.unnamed_trait_imports.keys().copied())
+            .chain(self.unnamed_trait_imports.iter().map(|&(t, _)| t))
     }
 
     pub(crate) fn resolutions(&self) -> impl Iterator<Item = (Option<Name>, PerNs)> + '_ {
@@ -476,7 +476,7 @@ impl ItemScope {
     }
 
     pub(crate) fn define_extern_block(&mut self, extern_block: ExternBlockId) {
-        self.extern_blocks.get_or_insert_default().push(extern_block);
+        self.extern_blocks.push(extern_block);
     }
 
     pub(crate) fn define_extern_crate_decl(&mut self, extern_crate: ExternCrateId) {
@@ -564,7 +564,7 @@ impl ItemScope {
 
     // FIXME: This is only used in collection, we should move the relevant parts of it out of ItemScope
     pub(crate) fn unnamed_trait_vis(&self, tr: TraitId) -> Option<Visibility> {
-        self.unnamed_trait_imports.get(&tr).map(|trait_| trait_.vis)
+        self.unnamed_trait_imports.iter().find(|&&(t, _)| t == tr).map(|(_, trait_)| trait_.vis)
     }
 
     pub(crate) fn push_unnamed_trait(
@@ -573,7 +573,7 @@ impl ItemScope {
         vis: Visibility,
         import: Option<ImportId>,
     ) {
-        self.unnamed_trait_imports.insert(tr, Item { def: (), vis, import });
+        self.unnamed_trait_imports.push((tr, Item { def: (), vis, import }));
     }
 
     pub(crate) fn push_res_with_import(
@@ -720,33 +720,19 @@ impl ItemScope {
     }
 
     /// Marks everything that is not a procedural macro as private to `this_module`.
-    pub(crate) fn censor_non_proc_macros(&mut self, this_module: ModuleId) {
+    pub(crate) fn censor_non_proc_macros(&mut self, krate: Crate) {
         self.types
             .values_mut()
             .map(|def| &mut def.vis)
             .chain(self.values.values_mut().map(|def| &mut def.vis))
-            .chain(self.unnamed_trait_imports.values_mut().map(|def| &mut def.vis))
-            .for_each(|vis| match vis {
-                &mut Visibility::Module(_, visibility_explicitness) => {
-                    *vis = Visibility::Module(this_module, visibility_explicitness)
-                }
-                Visibility::Public => {
-                    *vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit)
-                }
-            });
+            .chain(self.unnamed_trait_imports.iter_mut().map(|(_, def)| &mut def.vis))
+            .for_each(|vis| *vis = Visibility::PubCrate(krate));
 
         for mac in self.macros.values_mut() {
             if matches!(mac.def, MacroId::ProcMacroId(_) if mac.import.is_none()) {
                 continue;
             }
-            match mac.vis {
-                Visibility::Module(_, visibility_explicitness) => {
-                    mac.vis = Visibility::Module(this_module, visibility_explicitness)
-                }
-                Visibility::Public => {
-                    mac.vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit)
-                }
-            }
+            mac.vis = Visibility::PubCrate(krate)
         }
     }
 
@@ -817,9 +803,7 @@ impl ItemScope {
             macro_invocations,
             extern_blocks,
         } = self;
-        if let Some(it) = extern_blocks {
-            it.shrink_to_fit();
-        }
+        extern_blocks.shrink_to_fit();
         types.shrink_to_fit();
         values.shrink_to_fit();
         macros.shrink_to_fit();
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
index 1b97eb72b6f..c6333398574 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
@@ -29,7 +29,6 @@
 //!
 //! In general, any item in the `ItemTree` stores its `AstId`, which allows mapping it back to its
 //! surface syntax.
-#![allow(unexpected_cfgs)]
 
 mod lower;
 mod pretty;
@@ -38,38 +37,40 @@ mod tests;
 
 use std::{
     fmt::{self, Debug},
-    hash::{Hash, Hasher},
-    ops::{Index, Range},
+    hash::Hash,
+    ops::Index,
     sync::OnceLock,
 };
 
 use ast::{AstNode, StructKind};
 use base_db::Crate;
 use hir_expand::{
-    ExpandTo, HirFileId, InFile,
+    ExpandTo, HirFileId,
     attrs::RawAttrs,
     mod_path::{ModPath, PathKind},
     name::Name,
 };
-use intern::{Interned, Symbol};
-use la_arena::{Arena, Idx, RawIdx};
+use intern::Interned;
+use la_arena::{Idx, RawIdx};
 use rustc_hash::FxHashMap;
-use smallvec::SmallVec;
 use span::{AstIdNode, Edition, FileAstId, SyntaxContext};
 use stdx::never;
 use syntax::{SyntaxKind, ast, match_ast};
+use thin_vec::ThinVec;
 use triomphe::Arc;
 
 use crate::{BlockId, Lookup, attr::Attrs, db::DefDatabase};
 
+pub(crate) use crate::item_tree::lower::{lower_use_tree, visibility_from_ast};
+
 #[derive(Copy, Clone, Eq, PartialEq)]
-pub struct RawVisibilityId(u32);
+pub(crate) struct RawVisibilityId(u32);
 
 impl RawVisibilityId {
-    pub const PUB: Self = RawVisibilityId(u32::MAX);
-    pub const PRIV_IMPLICIT: Self = RawVisibilityId(u32::MAX - 1);
-    pub const PRIV_EXPLICIT: Self = RawVisibilityId(u32::MAX - 2);
-    pub const PUB_CRATE: Self = RawVisibilityId(u32::MAX - 3);
+    const PUB: Self = RawVisibilityId(u32::MAX);
+    const PRIV_IMPLICIT: Self = RawVisibilityId(u32::MAX - 1);
+    const PRIV_EXPLICIT: Self = RawVisibilityId(u32::MAX - 2);
+    const PUB_CRATE: Self = RawVisibilityId(u32::MAX - 3);
 }
 
 impl fmt::Debug for RawVisibilityId {
@@ -85,112 +86,136 @@ impl fmt::Debug for RawVisibilityId {
     }
 }
 
-/// The item tree of a source file.
-#[derive(Debug, Default, Eq, PartialEq)]
-pub struct ItemTree {
-    top_level: SmallVec<[ModItem; 1]>,
-    attrs: FxHashMap<AttrOwner, RawAttrs>,
-
-    data: Option<Box<ItemTreeData>>,
-}
-
-impl ItemTree {
-    pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
-        let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered();
-        static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new();
-
-        let ctx = lower::Ctx::new(db, file_id);
-        let syntax = db.parse_or_expand(file_id);
-        let mut top_attrs = None;
-        let mut item_tree = match_ast! {
-            match syntax {
-                ast::SourceFile(file) => {
-                    top_attrs = Some(RawAttrs::new(db, &file, ctx.span_map()));
-                    ctx.lower_module_items(&file)
-                },
-                ast::MacroItems(items) => {
-                    ctx.lower_module_items(&items)
-                },
-                ast::MacroStmts(stmts) => {
-                    // The produced statements can include items, which should be added as top-level
-                    // items.
-                    ctx.lower_macro_stmts(stmts)
-                },
-                _ => {
-                    if never!(syntax.kind() == SyntaxKind::ERROR, "{:?} from {:?} {}", file_id, syntax, syntax) {
-                        return Default::default();
-                    }
-                    panic!("cannot create item tree for file {file_id:?} from {syntax:?} {syntax}");
-                },
-            }
-        };
+#[salsa_macros::tracked(returns(deref))]
+pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc<ItemTree> {
+    let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered();
+    static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new();
 
-        if let Some(attrs) = top_attrs {
-            item_tree.attrs.insert(AttrOwner::TopLevel, attrs);
+    let ctx = lower::Ctx::new(db, file_id);
+    let syntax = db.parse_or_expand(file_id);
+    let mut item_tree = match_ast! {
+        match syntax {
+            ast::SourceFile(file) => {
+                let top_attrs = RawAttrs::new(db, &file, ctx.span_map());
+                let mut item_tree = ctx.lower_module_items(&file);
+                item_tree.top_attrs = top_attrs;
+                item_tree
+            },
+            ast::MacroItems(items) => {
+                ctx.lower_module_items(&items)
+            },
+            ast::MacroStmts(stmts) => {
+                // The produced statements can include items, which should be added as top-level
+                // items.
+                ctx.lower_macro_stmts(stmts)
+            },
+            _ => {
+                if never!(syntax.kind() == SyntaxKind::ERROR, "{:?} from {:?} {}", file_id, syntax, syntax) {
+                    return Default::default();
+                }
+                panic!("cannot create item tree for file {file_id:?} from {syntax:?} {syntax}");
+            },
         }
-        if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty()
-        {
-            EMPTY
-                .get_or_init(|| {
-                    Arc::new(ItemTree {
-                        top_level: SmallVec::new_const(),
-                        attrs: FxHashMap::default(),
-                        data: None,
-                    })
+    };
+    let ItemTree { top_level, top_attrs, attrs, vis, big_data, small_data } = &item_tree;
+    if small_data.is_empty()
+        && big_data.is_empty()
+        && top_level.is_empty()
+        && attrs.is_empty()
+        && top_attrs.is_empty()
+        && vis.arena.is_empty()
+    {
+        EMPTY
+            .get_or_init(|| {
+                Arc::new(ItemTree {
+                    top_level: Box::new([]),
+                    attrs: FxHashMap::default(),
+                    small_data: FxHashMap::default(),
+                    big_data: FxHashMap::default(),
+                    top_attrs: RawAttrs::EMPTY,
+                    vis: ItemVisibilities { arena: ThinVec::new() },
                 })
-                .clone()
-        } else {
-            item_tree.shrink_to_fit();
-            Arc::new(item_tree)
-        }
-    }
-
-    pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> {
-        let _p = tracing::info_span!("block_item_tree_query", ?block).entered();
-        static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new();
-
-        let loc = block.lookup(db);
-        let block = loc.ast_id.to_node(db);
-
-        let ctx = lower::Ctx::new(db, loc.ast_id.file_id);
-        let mut item_tree = ctx.lower_block(&block);
-        if item_tree.data.is_none() && item_tree.top_level.is_empty() && item_tree.attrs.is_empty()
-        {
-            EMPTY
-                .get_or_init(|| {
-                    Arc::new(ItemTree {
-                        top_level: SmallVec::new_const(),
-                        attrs: FxHashMap::default(),
-                        data: None,
-                    })
+            })
+            .clone()
+    } else {
+        item_tree.shrink_to_fit();
+        Arc::new(item_tree)
+    }
+}
+
+#[salsa_macros::tracked(returns(deref))]
+pub(crate) fn block_item_tree_query(db: &dyn DefDatabase, block: BlockId) -> Arc<ItemTree> {
+    let _p = tracing::info_span!("block_item_tree_query", ?block).entered();
+    static EMPTY: OnceLock<Arc<ItemTree>> = OnceLock::new();
+
+    let loc = block.lookup(db);
+    let block = loc.ast_id.to_node(db);
+
+    let ctx = lower::Ctx::new(db, loc.ast_id.file_id);
+    let mut item_tree = ctx.lower_block(&block);
+    let ItemTree { top_level, top_attrs, attrs, vis, big_data, small_data } = &item_tree;
+    if small_data.is_empty()
+        && big_data.is_empty()
+        && top_level.is_empty()
+        && attrs.is_empty()
+        && top_attrs.is_empty()
+        && vis.arena.is_empty()
+    {
+        EMPTY
+            .get_or_init(|| {
+                Arc::new(ItemTree {
+                    top_level: Box::new([]),
+                    attrs: FxHashMap::default(),
+                    small_data: FxHashMap::default(),
+                    big_data: FxHashMap::default(),
+                    top_attrs: RawAttrs::EMPTY,
+                    vis: ItemVisibilities { arena: ThinVec::new() },
                 })
-                .clone()
-        } else {
-            item_tree.shrink_to_fit();
-            Arc::new(item_tree)
-        }
+            })
+            .clone()
+    } else {
+        item_tree.shrink_to_fit();
+        Arc::new(item_tree)
     }
+}
+/// The item tree of a source file.
+#[derive(Debug, Default, Eq, PartialEq)]
+pub struct ItemTree {
+    top_level: Box<[ModItemId]>,
+    top_attrs: RawAttrs,
+    attrs: FxHashMap<FileAstId<ast::Item>, RawAttrs>,
+    vis: ItemVisibilities,
+    big_data: FxHashMap<FileAstId<ast::Item>, BigModItem>,
+    small_data: FxHashMap<FileAstId<ast::Item>, SmallModItem>,
+}
 
+impl ItemTree {
     /// Returns an iterator over all items located at the top level of the `HirFileId` this
     /// `ItemTree` was created from.
-    pub fn top_level_items(&self) -> &[ModItem] {
+    pub(crate) fn top_level_items(&self) -> &[ModItemId] {
         &self.top_level
     }
 
     /// Returns the inner attributes of the source file.
-    pub fn top_level_attrs(&self, db: &dyn DefDatabase, krate: Crate) -> Attrs {
-        Attrs::expand_cfg_attr(
-            db,
-            krate,
-            self.attrs.get(&AttrOwner::TopLevel).unwrap_or(&RawAttrs::EMPTY).clone(),
-        )
+    pub(crate) fn top_level_raw_attrs(&self) -> &RawAttrs {
+        &self.top_attrs
+    }
+
+    /// Returns the inner attributes of the source file.
+    pub(crate) fn top_level_attrs(&self, db: &dyn DefDatabase, krate: Crate) -> Attrs {
+        Attrs::expand_cfg_attr(db, krate, self.top_attrs.clone())
     }
 
-    pub(crate) fn raw_attrs(&self, of: AttrOwner) -> &RawAttrs {
+    pub(crate) fn raw_attrs(&self, of: FileAstId<ast::Item>) -> &RawAttrs {
         self.attrs.get(&of).unwrap_or(&RawAttrs::EMPTY)
     }
 
-    pub(crate) fn attrs(&self, db: &dyn DefDatabase, krate: Crate, of: AttrOwner) -> Attrs {
+    pub(crate) fn attrs(
+        &self,
+        db: &dyn DefDatabase,
+        krate: Crate,
+        of: FileAstId<ast::Item>,
+    ) -> Attrs {
         Attrs::expand_cfg_attr(db, krate, self.raw_attrs(of).clone())
     }
 
@@ -198,131 +223,79 @@ impl ItemTree {
     ///
     /// For more detail, see [`ItemTreeDataStats`].
     pub fn item_tree_stats(&self) -> ItemTreeDataStats {
-        match self.data {
-            Some(ref data) => ItemTreeDataStats {
-                traits: data.traits.len(),
-                impls: data.impls.len(),
-                mods: data.mods.len(),
-                macro_calls: data.macro_calls.len(),
-                macro_rules: data.macro_rules.len(),
-            },
-            None => ItemTreeDataStats::default(),
+        let mut traits = 0;
+        let mut impls = 0;
+        let mut mods = 0;
+        let mut macro_calls = 0;
+        let mut macro_rules = 0;
+        for item in self.small_data.values() {
+            match item {
+                SmallModItem::Trait(_) => traits += 1,
+                SmallModItem::Impl(_) => impls += 1,
+                SmallModItem::MacroRules(_) => macro_rules += 1,
+                SmallModItem::MacroCall(_) => macro_calls += 1,
+                _ => {}
+            }
+        }
+        for item in self.big_data.values() {
+            match item {
+                BigModItem::Mod(_) => mods += 1,
+                _ => {}
+            }
         }
+        ItemTreeDataStats { traits, impls, mods, macro_calls, macro_rules }
     }
 
     pub fn pretty_print(&self, db: &dyn DefDatabase, edition: Edition) -> String {
         pretty::print_item_tree(db, self, edition)
     }
 
-    fn data(&self) -> &ItemTreeData {
-        self.data.as_ref().expect("attempted to access data of empty ItemTree")
-    }
-
-    fn data_mut(&mut self) -> &mut ItemTreeData {
-        self.data.get_or_insert_with(Box::default)
-    }
-
     fn shrink_to_fit(&mut self) {
-        let ItemTree { top_level, attrs, data } = self;
-        top_level.shrink_to_fit();
+        let ItemTree { top_level: _, attrs, big_data, small_data, vis: _, top_attrs: _ } = self;
         attrs.shrink_to_fit();
-        if let Some(data) = data {
-            let ItemTreeData {
-                uses,
-                extern_crates,
-                extern_blocks,
-                functions,
-                structs,
-                unions,
-                enums,
-                variants,
-                consts,
-                statics,
-                traits,
-                trait_aliases,
-                impls,
-                type_aliases,
-                mods,
-                macro_calls,
-                macro_rules,
-                macro_defs,
-                vis,
-            } = &mut **data;
-
-            uses.shrink_to_fit();
-            extern_crates.shrink_to_fit();
-            extern_blocks.shrink_to_fit();
-            functions.shrink_to_fit();
-            structs.shrink_to_fit();
-            unions.shrink_to_fit();
-            enums.shrink_to_fit();
-            variants.shrink_to_fit();
-            consts.shrink_to_fit();
-            statics.shrink_to_fit();
-            traits.shrink_to_fit();
-            trait_aliases.shrink_to_fit();
-            impls.shrink_to_fit();
-            type_aliases.shrink_to_fit();
-            mods.shrink_to_fit();
-            macro_calls.shrink_to_fit();
-            macro_rules.shrink_to_fit();
-            macro_defs.shrink_to_fit();
-
-            vis.arena.shrink_to_fit();
-        }
+        big_data.shrink_to_fit();
+        small_data.shrink_to_fit();
     }
 }
 
 #[derive(Default, Debug, Eq, PartialEq)]
 struct ItemVisibilities {
-    arena: Arena<RawVisibility>,
+    arena: ThinVec<RawVisibility>,
 }
 
-impl ItemVisibilities {
-    fn alloc(&mut self, vis: RawVisibility) -> RawVisibilityId {
-        match &vis {
-            RawVisibility::Public => RawVisibilityId::PUB,
-            RawVisibility::Module(path, explicitiy) if path.segments().is_empty() => {
-                match (path.kind, explicitiy) {
-                    (PathKind::SELF, VisibilityExplicitness::Explicit) => {
-                        RawVisibilityId::PRIV_EXPLICIT
-                    }
-                    (PathKind::SELF, VisibilityExplicitness::Implicit) => {
-                        RawVisibilityId::PRIV_IMPLICIT
-                    }
-                    (PathKind::Crate, _) => RawVisibilityId::PUB_CRATE,
-                    _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
-                }
-            }
-            _ => RawVisibilityId(self.arena.alloc(vis).into_raw().into()),
-        }
-    }
+#[derive(Debug, Clone, Eq, PartialEq)]
+enum SmallModItem {
+    Const(Const),
+    Enum(Enum),
+    ExternBlock(ExternBlock),
+    Function(Function),
+    Impl(Impl),
+    Macro2(Macro2),
+    MacroCall(MacroCall),
+    MacroRules(MacroRules),
+    Static(Static),
+    Struct(Struct),
+    Trait(Trait),
+    TraitAlias(TraitAlias),
+    TypeAlias(TypeAlias),
+    Union(Union),
 }
 
-#[derive(Default, Debug, Eq, PartialEq)]
-struct ItemTreeData {
-    uses: Arena<Use>,
-    extern_crates: Arena<ExternCrate>,
-    extern_blocks: Arena<ExternBlock>,
-    functions: Arena<Function>,
-    structs: Arena<Struct>,
-    unions: Arena<Union>,
-    enums: Arena<Enum>,
-    variants: Arena<Variant>,
-    consts: Arena<Const>,
-    statics: Arena<Static>,
-    traits: Arena<Trait>,
-    trait_aliases: Arena<TraitAlias>,
-    impls: Arena<Impl>,
-    type_aliases: Arena<TypeAlias>,
-    mods: Arena<Mod>,
-    macro_calls: Arena<MacroCall>,
-    macro_rules: Arena<MacroRules>,
-    macro_defs: Arena<Macro2>,
-
-    vis: ItemVisibilities,
+#[derive(Debug, Clone, Eq, PartialEq)]
+enum BigModItem {
+    ExternCrate(ExternCrate),
+    Mod(Mod),
+    Use(Use),
 }
 
+// `ModItem` is stored a bunch in `ItemTree`'s so we pay the max for each item. It should stay as
+// small as possible which is why we split them in two, most common ones are 3 usize but some rarer
+// ones are 5.
+#[cfg(target_pointer_width = "64")]
+const _: [(); std::mem::size_of::<BigModItem>()] = [(); std::mem::size_of::<[usize; 5]>()];
+#[cfg(target_pointer_width = "64")]
+const _: [(); std::mem::size_of::<SmallModItem>()] = [(); std::mem::size_of::<[usize; 3]>()];
+
 #[derive(Default, Debug, Eq, PartialEq)]
 pub struct ItemTreeDataStats {
     pub traits: usize,
@@ -332,100 +305,13 @@ pub struct ItemTreeDataStats {
     pub macro_rules: usize,
 }
 
-#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
-pub enum AttrOwner {
-    /// Attributes on an item.
-    ModItem(ModItem),
-    /// Inner attributes of the source file.
-    TopLevel,
-
-    Variant(FileItemTreeId<Variant>),
-    // while not relevant to early name resolution, fields can contain visibility
-    Field(FieldParent, ItemTreeFieldId),
-}
-
-impl AttrOwner {
-    pub fn make_field_indexed(parent: FieldParent, idx: usize) -> Self {
-        AttrOwner::Field(parent, ItemTreeFieldId::from_raw(RawIdx::from_u32(idx as u32)))
-    }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub enum FieldParent {
-    Struct(FileItemTreeId<Struct>),
-    Union(FileItemTreeId<Union>),
-    EnumVariant(FileItemTreeId<Variant>),
-}
-
-pub type ItemTreeFieldId = Idx<Field>;
-
-macro_rules! from_attrs {
-    ( $( $var:ident($t:ty) ),+ $(,)? ) => {
-        $(
-            impl From<$t> for AttrOwner {
-                fn from(t: $t) -> AttrOwner {
-                    AttrOwner::$var(t)
-                }
-            }
-        )+
-    };
-}
-
-from_attrs!(ModItem(ModItem), Variant(FileItemTreeId<Variant>));
-
 /// Trait implemented by all nodes in the item tree.
-pub trait ItemTreeNode: Clone {
+pub(crate) trait ItemTreeNode: Clone {
     type Source: AstIdNode;
-
-    fn ast_id(&self) -> FileAstId<Self::Source>;
-
-    /// Looks up an instance of `Self` in an item tree.
-    fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self;
-    fn attr_owner(id: FileItemTreeId<Self>) -> AttrOwner;
-}
-
-pub struct FileItemTreeId<N>(Idx<N>);
-
-impl<N> FileItemTreeId<N> {
-    pub fn range_iter(range: Range<Self>) -> impl Iterator<Item = Self> + Clone {
-        (range.start.index().into_raw().into_u32()..range.end.index().into_raw().into_u32())
-            .map(RawIdx::from_u32)
-            .map(Idx::from_raw)
-            .map(Self)
-    }
-}
-
-impl<N> FileItemTreeId<N> {
-    pub fn index(&self) -> Idx<N> {
-        self.0
-    }
-}
-
-impl<N> Clone for FileItemTreeId<N> {
-    fn clone(&self) -> Self {
-        *self
-    }
-}
-impl<N> Copy for FileItemTreeId<N> {}
-
-impl<N> PartialEq for FileItemTreeId<N> {
-    fn eq(&self, other: &FileItemTreeId<N>) -> bool {
-        self.0 == other.0
-    }
-}
-impl<N> Eq for FileItemTreeId<N> {}
-
-impl<N> Hash for FileItemTreeId<N> {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        self.0.hash(state)
-    }
 }
 
-impl<N> fmt::Debug for FileItemTreeId<N> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.0.fmt(f)
-    }
-}
+#[allow(type_alias_bounds)]
+pub(crate) type ItemTreeAstId<T: ItemTreeNode> = FileAstId<T::Source>;
 
 /// Identifies a particular [`ItemTree`].
 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
@@ -435,100 +321,48 @@ pub struct TreeId {
 }
 
 impl TreeId {
-    pub fn new(file: HirFileId, block: Option<BlockId>) -> Self {
+    pub(crate) fn new(file: HirFileId, block: Option<BlockId>) -> Self {
         Self { file, block }
     }
 
-    pub fn item_tree(&self, db: &dyn DefDatabase) -> Arc<ItemTree> {
+    pub(crate) fn item_tree<'db>(&self, db: &'db dyn DefDatabase) -> &'db ItemTree {
         match self.block {
-            Some(block) => db.block_item_tree(block),
-            None => db.file_item_tree(self.file),
+            Some(block) => block_item_tree_query(db, block),
+            None => file_item_tree_query(db, self.file),
         }
     }
 
+    #[inline]
     pub fn file_id(self) -> HirFileId {
         self.file
     }
 
-    pub fn is_block(self) -> bool {
+    pub(crate) fn is_block(self) -> bool {
         self.block.is_some()
     }
 }
 
-#[derive(Debug)]
-pub struct ItemTreeId<N> {
-    tree: TreeId,
-    pub value: FileItemTreeId<N>,
-}
-
-impl<N> ItemTreeId<N> {
-    pub fn new(tree: TreeId, idx: FileItemTreeId<N>) -> Self {
-        Self { tree, value: idx }
-    }
-
-    pub fn file_id(self) -> HirFileId {
-        self.tree.file
-    }
-
-    pub fn tree_id(self) -> TreeId {
-        self.tree
-    }
-
-    pub fn item_tree(self, db: &dyn DefDatabase) -> Arc<ItemTree> {
-        self.tree.item_tree(db)
-    }
-
-    pub fn resolved<R>(self, db: &dyn DefDatabase, cb: impl FnOnce(&N) -> R) -> R
-    where
-        ItemTree: Index<FileItemTreeId<N>, Output = N>,
-    {
-        cb(&self.tree.item_tree(db)[self.value])
-    }
-}
-
-impl<N> Copy for ItemTreeId<N> {}
-impl<N> Clone for ItemTreeId<N> {
-    fn clone(&self) -> Self {
-        *self
-    }
-}
-
-impl<N> PartialEq for ItemTreeId<N> {
-    fn eq(&self, other: &Self) -> bool {
-        self.tree == other.tree && self.value == other.value
-    }
-}
-
-impl<N> Eq for ItemTreeId<N> {}
-
-impl<N> Hash for ItemTreeId<N> {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        self.tree.hash(state);
-        self.value.hash(state);
-    }
-}
-
 macro_rules! mod_items {
-    ( $( $typ:ident in $fld:ident -> $ast:ty ),+ $(,)? ) => {
+    ($mod_item:ident -> $( $typ:ident in $fld:ident -> $ast:ty ),+ $(,)? ) => {
         #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-        pub enum ModItem {
+        pub(crate) enum $mod_item {
             $(
-                $typ(FileItemTreeId<$typ>),
+                $typ(FileAstId<$ast>),
             )+
         }
 
-        impl ModItem {
-            pub fn ast_id(&self, tree: &ItemTree) -> FileAstId<ast::Item> {
+        impl $mod_item {
+            pub(crate) fn ast_id(self) -> FileAstId<ast::Item> {
                 match self {
-                    $(ModItem::$typ(it) => tree[it.index()].ast_id().upcast()),+
+                    $($mod_item::$typ(it) => it.upcast()),+
                 }
             }
         }
 
         $(
-            impl From<FileItemTreeId<$typ>> for ModItem {
-                fn from(id: FileItemTreeId<$typ>) -> ModItem {
-                    ModItem::$typ(id)
+            impl From<FileAstId<$ast>> for $mod_item {
+                fn from(id: FileAstId<$ast>) -> $mod_item {
+                    ModItemId::$typ(id)
                 }
             }
         )+
@@ -536,25 +370,19 @@ macro_rules! mod_items {
         $(
             impl ItemTreeNode for $typ {
                 type Source = $ast;
-
-                fn ast_id(&self) -> FileAstId<Self::Source> {
-                    self.ast_id
-                }
-
-                fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self {
-                    &tree.data().$fld[index]
-                }
-
-                fn attr_owner(id: FileItemTreeId<Self>) -> AttrOwner {
-                    AttrOwner::ModItem(ModItem::$typ(id))
-                }
             }
 
-            impl Index<Idx<$typ>> for ItemTree {
+            impl Index<FileAstId<$ast>> for ItemTree {
                 type Output = $typ;
 
-                fn index(&self, index: Idx<$typ>) -> &Self::Output {
-                    &self.data().$fld[index]
+                #[allow(unused_imports)]
+                fn index(&self, index: FileAstId<$ast>) -> &Self::Output {
+                    use BigModItem::*;
+                    use SmallModItem::*;
+                    match &self.$fld[&index.upcast()] {
+                        $typ(item) => item,
+                        _ => panic!("expected item of type `{}` at index `{:?}`", stringify!($typ), index),
+                    }
                 }
             }
         )+
@@ -562,94 +390,59 @@ macro_rules! mod_items {
 }
 
 mod_items! {
-    Use in uses -> ast::Use,
-    ExternCrate in extern_crates -> ast::ExternCrate,
-    ExternBlock in extern_blocks -> ast::ExternBlock,
-    Function in functions -> ast::Fn,
-    Struct in structs -> ast::Struct,
-    Union in unions -> ast::Union,
-    Enum in enums -> ast::Enum,
-    Const in consts -> ast::Const,
-    Static in statics -> ast::Static,
-    Trait in traits -> ast::Trait,
-    TraitAlias in trait_aliases -> ast::TraitAlias,
-    Impl in impls -> ast::Impl,
-    TypeAlias in type_aliases -> ast::TypeAlias,
-    Mod in mods -> ast::Module,
-    MacroCall in macro_calls -> ast::MacroCall,
-    MacroRules in macro_rules -> ast::MacroRules,
-    Macro2 in macro_defs -> ast::MacroDef,
+ModItemId ->
+    Const in small_data -> ast::Const,
+    Enum in small_data -> ast::Enum,
+    ExternBlock in small_data -> ast::ExternBlock,
+    ExternCrate in big_data -> ast::ExternCrate,
+    Function in small_data -> ast::Fn,
+    Impl in small_data -> ast::Impl,
+    Macro2 in small_data -> ast::MacroDef,
+    MacroCall in small_data -> ast::MacroCall,
+    MacroRules in small_data -> ast::MacroRules,
+    Mod in big_data -> ast::Module,
+    Static in small_data -> ast::Static,
+    Struct in small_data -> ast::Struct,
+    Trait in small_data -> ast::Trait,
+    TraitAlias in small_data -> ast::TraitAlias,
+    TypeAlias in small_data -> ast::TypeAlias,
+    Union in small_data -> ast::Union,
+    Use in big_data -> ast::Use,
 }
 
 impl Index<RawVisibilityId> for ItemTree {
     type Output = RawVisibility;
     fn index(&self, index: RawVisibilityId) -> &Self::Output {
         static VIS_PUB: RawVisibility = RawVisibility::Public;
-        static VIS_PRIV_IMPLICIT: OnceLock<RawVisibility> = OnceLock::new();
-        static VIS_PRIV_EXPLICIT: OnceLock<RawVisibility> = OnceLock::new();
-        static VIS_PUB_CRATE: OnceLock<RawVisibility> = OnceLock::new();
+        static VIS_PRIV_IMPLICIT: RawVisibility =
+            RawVisibility::PubSelf(VisibilityExplicitness::Implicit);
+        static VIS_PRIV_EXPLICIT: RawVisibility =
+            RawVisibility::PubSelf(VisibilityExplicitness::Explicit);
+        static VIS_PUB_CRATE: RawVisibility = RawVisibility::PubCrate;
 
         match index {
-            RawVisibilityId::PRIV_IMPLICIT => VIS_PRIV_IMPLICIT.get_or_init(|| {
-                RawVisibility::Module(
-                    Interned::new(ModPath::from_kind(PathKind::SELF)),
-                    VisibilityExplicitness::Implicit,
-                )
-            }),
-            RawVisibilityId::PRIV_EXPLICIT => VIS_PRIV_EXPLICIT.get_or_init(|| {
-                RawVisibility::Module(
-                    Interned::new(ModPath::from_kind(PathKind::SELF)),
-                    VisibilityExplicitness::Explicit,
-                )
-            }),
+            RawVisibilityId::PRIV_IMPLICIT => &VIS_PRIV_IMPLICIT,
+            RawVisibilityId::PRIV_EXPLICIT => &VIS_PRIV_EXPLICIT,
             RawVisibilityId::PUB => &VIS_PUB,
-            RawVisibilityId::PUB_CRATE => VIS_PUB_CRATE.get_or_init(|| {
-                RawVisibility::Module(
-                    Interned::new(ModPath::from_kind(PathKind::Crate)),
-                    VisibilityExplicitness::Explicit,
-                )
-            }),
-            _ => &self.data().vis.arena[Idx::from_raw(index.0.into())],
+            RawVisibilityId::PUB_CRATE => &VIS_PUB_CRATE,
+            _ => &self.vis.arena[index.0 as usize],
         }
     }
 }
 
-impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
-    type Output = N;
-    fn index(&self, id: FileItemTreeId<N>) -> &N {
-        N::lookup(self, id.index())
-    }
-}
-
-impl ItemTreeNode for Variant {
-    type Source = ast::Variant;
-
-    fn ast_id(&self) -> FileAstId<Self::Source> {
-        self.ast_id
-    }
-
-    fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self {
-        &tree.data().variants[index]
-    }
-
-    fn attr_owner(id: FileItemTreeId<Self>) -> AttrOwner {
-        AttrOwner::Variant(id)
-    }
-}
-
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Use {
-    pub visibility: RawVisibilityId,
-    pub ast_id: FileAstId<ast::Use>,
-    pub use_tree: UseTree,
+    pub(crate) visibility: RawVisibilityId,
+    pub(crate) use_tree: UseTree,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct UseTree {
-    pub index: Idx<ast::UseTree>,
     kind: UseTreeKind,
 }
 
+// FIXME: Would be nice to encode `None` into this
+// We could just use a `Name` where `_` well means `_` ..
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub enum ImportAlias {
     /// Unnamed alias, as in `use Foo as _;`
@@ -703,55 +496,37 @@ pub enum UseTreeKind {
 pub struct ExternCrate {
     pub name: Name,
     pub alias: Option<ImportAlias>,
-    pub visibility: RawVisibilityId,
-    pub ast_id: FileAstId<ast::ExternCrate>,
+    pub(crate) visibility: RawVisibilityId,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct ExternBlock {
-    pub abi: Option<Symbol>,
-    pub ast_id: FileAstId<ast::ExternBlock>,
-    pub children: Box<[ModItem]>,
+    pub(crate) children: Box<[ModItemId]>,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Function {
     pub name: Name,
-    pub visibility: RawVisibilityId,
-    pub ast_id: FileAstId<ast::Fn>,
+    pub(crate) visibility: RawVisibilityId,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Struct {
     pub name: Name,
-    pub visibility: RawVisibilityId,
-    pub fields: Box<[Field]>,
+    pub(crate) visibility: RawVisibilityId,
     pub shape: FieldsShape,
-    pub ast_id: FileAstId<ast::Struct>,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Union {
     pub name: Name,
-    pub visibility: RawVisibilityId,
-    pub fields: Box<[Field]>,
-    pub ast_id: FileAstId<ast::Union>,
+    pub(crate) visibility: RawVisibilityId,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Enum {
     pub name: Name,
-    pub visibility: RawVisibilityId,
-    pub variants: Range<FileItemTreeId<Variant>>,
-    pub ast_id: FileAstId<ast::Enum>,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct Variant {
-    pub name: Name,
-    pub fields: Box<[Field]>,
-    pub shape: FieldsShape,
-    pub ast_id: FileAstId<ast::Variant>,
+    pub(crate) visibility: RawVisibilityId,
 }
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -762,11 +537,15 @@ pub enum FieldsShape {
 }
 
 /// Visibility of an item, not yet resolved.
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum RawVisibility {
     /// `pub(in module)`, `pub(crate)` or `pub(super)`. Also private, which is
     /// equivalent to `pub(self)`.
     Module(Interned<ModPath>, VisibilityExplicitness),
+    /// `pub(self)`.
+    PubSelf(VisibilityExplicitness),
+    /// `pub(crate)`.
+    PubCrate,
     /// `pub`.
     Public,
 }
@@ -785,71 +564,51 @@ impl VisibilityExplicitness {
     }
 }
 
-// FIXME: Remove this from item tree?
-/// A single field of an enum variant or struct
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct Field {
-    pub name: Name,
-    pub visibility: RawVisibilityId,
-    // FIXME: Not an item tree property
-    pub is_unsafe: bool,
-}
-
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Const {
     /// `None` for `const _: () = ();`
     pub name: Option<Name>,
-    pub visibility: RawVisibilityId,
-    pub ast_id: FileAstId<ast::Const>,
+    pub(crate) visibility: RawVisibilityId,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Static {
     pub name: Name,
-    pub visibility: RawVisibilityId,
-    pub ast_id: FileAstId<ast::Static>,
+    pub(crate) visibility: RawVisibilityId,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Trait {
     pub name: Name,
-    pub visibility: RawVisibilityId,
-    pub items: Box<[AssocItem]>,
-    pub ast_id: FileAstId<ast::Trait>,
+    pub(crate) visibility: RawVisibilityId,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct TraitAlias {
     pub name: Name,
-    pub visibility: RawVisibilityId,
-    pub ast_id: FileAstId<ast::TraitAlias>,
+    pub(crate) visibility: RawVisibilityId,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
-pub struct Impl {
-    pub items: Box<[AssocItem]>,
-    pub ast_id: FileAstId<ast::Impl>,
-}
+pub struct Impl {}
 
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct TypeAlias {
     pub name: Name,
-    pub visibility: RawVisibilityId,
-    pub ast_id: FileAstId<ast::TypeAlias>,
+    pub(crate) visibility: RawVisibilityId,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Mod {
     pub name: Name,
-    pub visibility: RawVisibilityId,
-    pub kind: ModKind,
-    pub ast_id: FileAstId<ast::Module>,
+    pub(crate) visibility: RawVisibilityId,
+    pub(crate) kind: ModKind,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
-pub enum ModKind {
+pub(crate) enum ModKind {
     /// `mod m { ... }`
-    Inline { items: Box<[ModItem]> },
+    Inline { items: Box<[ModItemId]> },
     /// `mod m;`
     Outline,
 }
@@ -858,7 +617,6 @@ pub enum ModKind {
 pub struct MacroCall {
     /// Path to the called macro.
     pub path: Interned<ModPath>,
-    pub ast_id: FileAstId<ast::MacroCall>,
     pub expand_to: ExpandTo,
     pub ctxt: SyntaxContext,
 }
@@ -867,52 +625,13 @@ pub struct MacroCall {
 pub struct MacroRules {
     /// The name of the declared macro.
     pub name: Name,
-    pub ast_id: FileAstId<ast::MacroRules>,
 }
 
 /// "Macros 2.0" macro definition.
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub struct Macro2 {
     pub name: Name,
-    pub visibility: RawVisibilityId,
-    pub ast_id: FileAstId<ast::MacroDef>,
-}
-
-impl Use {
-    /// Maps a `UseTree` contained in this import back to its AST node.
-    pub fn use_tree_to_ast(
-        &self,
-        db: &dyn DefDatabase,
-        file_id: HirFileId,
-        index: Idx<ast::UseTree>,
-    ) -> ast::UseTree {
-        // Re-lower the AST item and get the source map.
-        // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`.
-        let ast = InFile::new(file_id, self.ast_id).to_node(db);
-        let ast_use_tree = ast.use_tree().expect("missing `use_tree`");
-        let (_, source_map) = lower::lower_use_tree(db, ast_use_tree, &mut |range| {
-            db.span_map(file_id).span_for_range(range).ctx
-        })
-        .expect("failed to lower use tree");
-        source_map[index].clone()
-    }
-
-    /// Maps a `UseTree` contained in this import back to its AST node.
-    pub fn use_tree_source_map(
-        &self,
-        db: &dyn DefDatabase,
-        file_id: HirFileId,
-    ) -> Arena<ast::UseTree> {
-        // Re-lower the AST item and get the source map.
-        // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`.
-        let ast = InFile::new(file_id, self.ast_id).to_node(db);
-        let ast_use_tree = ast.use_tree().expect("missing `use_tree`");
-        lower::lower_use_tree(db, ast_use_tree, &mut |range| {
-            db.span_map(file_id).span_for_range(range).ctx
-        })
-        .expect("failed to lower use tree")
-        .1
-    }
+    pub(crate) visibility: RawVisibilityId,
 }
 
 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
@@ -925,15 +644,17 @@ pub enum ImportKind {
     TypeOnly,
 }
 
-impl UseTree {
+impl Use {
     /// Expands the `UseTree` into individually imported `ModPath`s.
     pub fn expand(
         &self,
         mut cb: impl FnMut(Idx<ast::UseTree>, ModPath, ImportKind, Option<ImportAlias>),
     ) {
-        self.expand_impl(None, &mut cb)
+        self.use_tree.expand_impl(None, &mut 0, &mut cb)
     }
+}
 
+impl UseTree {
     /// The [`UseTreeKind`] of this `UseTree`.
     pub fn kind(&self) -> &UseTreeKind {
         &self.kind
@@ -942,6 +663,7 @@ impl UseTree {
     fn expand_impl(
         &self,
         prefix: Option<ModPath>,
+        counting_index: &mut u32,
         cb: &mut impl FnMut(Idx<ast::UseTree>, ModPath, ImportKind, Option<ImportAlias>),
     ) {
         fn concat_mod_paths(
@@ -977,17 +699,27 @@ impl UseTree {
         match &self.kind {
             UseTreeKind::Single { path, alias } => {
                 if let Some((path, kind)) = concat_mod_paths(prefix, path) {
-                    cb(self.index, path, kind, alias.clone());
+                    cb(Idx::from_raw(RawIdx::from_u32(*counting_index)), path, kind, alias.clone());
                 }
             }
             UseTreeKind::Glob { path: Some(path) } => {
                 if let Some((path, _)) = concat_mod_paths(prefix, path) {
-                    cb(self.index, path, ImportKind::Glob, None);
+                    cb(
+                        Idx::from_raw(RawIdx::from_u32(*counting_index)),
+                        path,
+                        ImportKind::Glob,
+                        None,
+                    );
                 }
             }
             UseTreeKind::Glob { path: None } => {
                 if let Some(prefix) = prefix {
-                    cb(self.index, prefix, ImportKind::Glob, None);
+                    cb(
+                        Idx::from_raw(RawIdx::from_u32(*counting_index)),
+                        prefix,
+                        ImportKind::Glob,
+                        None,
+                    );
                 }
             }
             UseTreeKind::Prefixed { prefix: additional_prefix, list } => {
@@ -999,82 +731,10 @@ impl UseTree {
                     None => prefix,
                 };
                 for tree in &**list {
-                    tree.expand_impl(prefix.clone(), cb);
+                    *counting_index += 1;
+                    tree.expand_impl(prefix.clone(), counting_index, cb);
                 }
             }
         }
     }
 }
-
-macro_rules! impl_froms {
-    ($e:ident { $($v:ident ($t:ty)),* $(,)? }) => {
-        $(
-            impl From<$t> for $e {
-                fn from(it: $t) -> $e {
-                    $e::$v(it)
-                }
-            }
-        )*
-    }
-}
-
-impl ModItem {
-    pub fn as_assoc_item(&self) -> Option<AssocItem> {
-        match self {
-            ModItem::Use(_)
-            | ModItem::ExternCrate(_)
-            | ModItem::ExternBlock(_)
-            | ModItem::Struct(_)
-            | ModItem::Union(_)
-            | ModItem::Enum(_)
-            | ModItem::Static(_)
-            | ModItem::Trait(_)
-            | ModItem::TraitAlias(_)
-            | ModItem::Impl(_)
-            | ModItem::Mod(_)
-            | ModItem::MacroRules(_)
-            | ModItem::Macro2(_) => None,
-            &ModItem::MacroCall(call) => Some(AssocItem::MacroCall(call)),
-            &ModItem::Const(konst) => Some(AssocItem::Const(konst)),
-            &ModItem::TypeAlias(alias) => Some(AssocItem::TypeAlias(alias)),
-            &ModItem::Function(func) => Some(AssocItem::Function(func)),
-        }
-    }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub enum AssocItem {
-    Function(FileItemTreeId<Function>),
-    TypeAlias(FileItemTreeId<TypeAlias>),
-    Const(FileItemTreeId<Const>),
-    MacroCall(FileItemTreeId<MacroCall>),
-}
-
-impl_froms!(AssocItem {
-    Function(FileItemTreeId<Function>),
-    TypeAlias(FileItemTreeId<TypeAlias>),
-    Const(FileItemTreeId<Const>),
-    MacroCall(FileItemTreeId<MacroCall>),
-});
-
-impl From<AssocItem> for ModItem {
-    fn from(item: AssocItem) -> Self {
-        match item {
-            AssocItem::Function(it) => it.into(),
-            AssocItem::TypeAlias(it) => it.into(),
-            AssocItem::Const(it) => it.into(),
-            AssocItem::MacroCall(it) => it.into(),
-        }
-    }
-}
-
-impl AssocItem {
-    pub fn ast_id(self, tree: &ItemTree) -> FileAstId<ast::AssocItem> {
-        match self {
-            AssocItem::Function(id) => tree[id].ast_id.upcast(),
-            AssocItem::TypeAlias(id) => tree[id].ast_id.upcast(),
-            AssocItem::Const(id) => tree[id].ast_id.upcast(),
-            AssocItem::MacroCall(id) => tree[id].ast_id.upcast(),
-        }
-    }
-}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
index b490e1683c0..f3273667158 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
@@ -2,42 +2,40 @@
 
 use std::{cell::OnceCell, collections::hash_map::Entry};
 
+use base_db::FxIndexSet;
 use hir_expand::{
     HirFileId,
     mod_path::PathKind,
     name::AsName,
     span_map::{SpanMap, SpanMapRef},
 };
-use intern::{Symbol, sym};
 use la_arena::Arena;
-use span::{AstIdMap, SyntaxContext};
+use span::{AstIdMap, FileAstId, SyntaxContext};
 use syntax::{
     AstNode,
-    ast::{self, HasModuleItem, HasName, IsString},
+    ast::{self, HasModuleItem, HasName},
 };
 use triomphe::Arc;
 
 use crate::{
     db::DefDatabase,
     item_tree::{
-        AssocItem, AttrOwner, Const, Enum, ExternBlock, ExternCrate, Field, FieldParent,
-        FieldsShape, FileItemTreeId, Function, Idx, Impl, ImportAlias, Interned, ItemTree,
-        ItemTreeData, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, ModPath, Name, Range,
-        RawAttrs, RawIdx, RawVisibility, RawVisibilityId, Static, Struct, StructKind, Trait,
-        TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind, Variant, VisibilityExplicitness,
+        BigModItem, Const, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl,
+        ImportAlias, Interned, ItemTree, ItemTreeAstId, Macro2, MacroCall, MacroRules, Mod,
+        ModItemId, ModKind, ModPath, RawAttrs, RawVisibility, RawVisibilityId, SmallModItem,
+        Static, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind,
+        VisibilityExplicitness,
     },
 };
 
-fn id<N>(index: Idx<N>) -> FileItemTreeId<N> {
-    FileItemTreeId(index)
-}
-
 pub(super) struct Ctx<'a> {
     db: &'a dyn DefDatabase,
     tree: ItemTree,
     source_ast_id_map: Arc<AstIdMap>,
     span_map: OnceCell<SpanMap>,
     file: HirFileId,
+    top_level: Vec<ModItemId>,
+    visibilities: FxIndexSet<RawVisibility>,
 }
 
 impl<'a> Ctx<'a> {
@@ -48,6 +46,8 @@ impl<'a> Ctx<'a> {
             source_ast_id_map: db.ast_id_map(file),
             file,
             span_map: OnceCell::new(),
+            visibilities: FxIndexSet::default(),
+            top_level: Vec::new(),
         }
     }
 
@@ -56,13 +56,14 @@ impl<'a> Ctx<'a> {
     }
 
     pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree {
-        self.tree.top_level =
-            item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect();
+        self.top_level = item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect();
+        self.tree.vis.arena = self.visibilities.into_iter().collect();
+        self.tree.top_level = self.top_level.into_boxed_slice();
         self.tree
     }
 
     pub(super) fn lower_macro_stmts(mut self, stmts: ast::MacroStmts) -> ItemTree {
-        self.tree.top_level = stmts
+        self.top_level = stmts
             .statements()
             .filter_map(|stmt| {
                 match stmt {
@@ -86,17 +87,19 @@ impl<'a> Ctx<'a> {
             if let Some(call) = tail_macro.macro_call() {
                 cov_mark::hit!(macro_stmt_with_trailing_macro_expr);
                 if let Some(mod_item) = self.lower_mod_item(&call.into()) {
-                    self.tree.top_level.push(mod_item);
+                    self.top_level.push(mod_item);
                 }
             }
         }
 
+        self.tree.vis.arena = self.visibilities.into_iter().collect();
+        self.tree.top_level = self.top_level.into_boxed_slice();
         self.tree
     }
 
     pub(super) fn lower_block(mut self, block: &ast::BlockExpr) -> ItemTree {
-        self.tree.attrs.insert(AttrOwner::TopLevel, RawAttrs::new(self.db, block, self.span_map()));
-        self.tree.top_level = block
+        self.tree.top_attrs = RawAttrs::new(self.db, block, self.span_map());
+        self.top_level = block
             .statements()
             .filter_map(|stmt| match stmt {
                 ast::Stmt::Item(item) => self.lower_mod_item(&item),
@@ -112,20 +115,17 @@ impl<'a> Ctx<'a> {
         if let Some(ast::Expr::MacroExpr(expr)) = block.tail_expr() {
             if let Some(call) = expr.macro_call() {
                 if let Some(mod_item) = self.lower_mod_item(&call.into()) {
-                    self.tree.top_level.push(mod_item);
+                    self.top_level.push(mod_item);
                 }
             }
         }
-
+        self.tree.vis.arena = self.visibilities.into_iter().collect();
+        self.tree.top_level = self.top_level.into_boxed_slice();
         self.tree
     }
 
-    fn data(&mut self) -> &mut ItemTreeData {
-        self.tree.data_mut()
-    }
-
-    fn lower_mod_item(&mut self, item: &ast::Item) -> Option<ModItem> {
-        let mod_item: ModItem = match item {
+    fn lower_mod_item(&mut self, item: &ast::Item) -> Option<ModItemId> {
+        let mod_item: ModItemId = match item {
             ast::Item::Struct(ast) => self.lower_struct(ast)?.into(),
             ast::Item::Union(ast) => self.lower_union(ast)?.into(),
             ast::Item::Enum(ast) => self.lower_enum(ast)?.into(),
@@ -145,12 +145,12 @@ impl<'a> Ctx<'a> {
             ast::Item::ExternBlock(ast) => self.lower_extern_block(ast).into(),
         };
         let attrs = RawAttrs::new(self.db, item, self.span_map());
-        self.add_attrs(mod_item.into(), attrs);
+        self.add_attrs(mod_item.ast_id(), attrs);
 
         Some(mod_item)
     }
 
-    fn add_attrs(&mut self, item: AttrOwner, attrs: RawAttrs) {
+    fn add_attrs(&mut self, item: FileAstId<ast::Item>, attrs: RawAttrs) {
         if !attrs.is_empty() {
             match self.tree.attrs.entry(item) {
                 Entry::Occupied(mut entry) => {
@@ -163,208 +163,78 @@ impl<'a> Ctx<'a> {
         }
     }
 
-    fn lower_assoc_item(&mut self, item_node: &ast::AssocItem) -> Option<AssocItem> {
-        let item: AssocItem = match item_node {
-            ast::AssocItem::Fn(ast) => self.lower_function(ast).map(Into::into),
-            ast::AssocItem::TypeAlias(ast) => self.lower_type_alias(ast).map(Into::into),
-            ast::AssocItem::Const(ast) => Some(self.lower_const(ast).into()),
-            ast::AssocItem::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
-        }?;
-        let attrs = RawAttrs::new(self.db, item_node, self.span_map());
-        self.add_attrs(
-            match item {
-                AssocItem::Function(it) => AttrOwner::ModItem(ModItem::Function(it)),
-                AssocItem::TypeAlias(it) => AttrOwner::ModItem(ModItem::TypeAlias(it)),
-                AssocItem::Const(it) => AttrOwner::ModItem(ModItem::Const(it)),
-                AssocItem::MacroCall(it) => AttrOwner::ModItem(ModItem::MacroCall(it)),
-            },
-            attrs,
-        );
-        Some(item)
-    }
-
-    fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<FileItemTreeId<Struct>> {
+    fn lower_struct(&mut self, strukt: &ast::Struct) -> Option<ItemTreeAstId<Struct>> {
         let visibility = self.lower_visibility(strukt);
         let name = strukt.name()?.as_name();
         let ast_id = self.source_ast_id_map.ast_id(strukt);
-        let (fields, kind, attrs) = self.lower_fields(&strukt.kind());
-        let res = Struct { name, visibility, fields, shape: kind, ast_id };
-        let id = id(self.data().structs.alloc(res));
-
-        for (idx, attr) in attrs {
-            self.add_attrs(
-                AttrOwner::Field(
-                    FieldParent::Struct(id),
-                    Idx::from_raw(RawIdx::from_u32(idx as u32)),
-                ),
-                attr,
-            );
-        }
-        Some(id)
-    }
+        let shape = adt_shape(strukt.kind());
+        let res = Struct { name, visibility, shape };
+        self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Struct(res));
 
-    fn lower_fields(
-        &mut self,
-        strukt_kind: &ast::StructKind,
-    ) -> (Box<[Field]>, FieldsShape, Vec<(usize, RawAttrs)>) {
-        match strukt_kind {
-            ast::StructKind::Record(it) => {
-                let mut fields = vec![];
-                let mut attrs = vec![];
-
-                for (i, field) in it.fields().enumerate() {
-                    let data = self.lower_record_field(&field);
-                    fields.push(data);
-                    let attr = RawAttrs::new(self.db, &field, self.span_map());
-                    if !attr.is_empty() {
-                        attrs.push((i, attr))
-                    }
-                }
-                (fields.into(), FieldsShape::Record, attrs)
-            }
-            ast::StructKind::Tuple(it) => {
-                let mut fields = vec![];
-                let mut attrs = vec![];
-
-                for (i, field) in it.fields().enumerate() {
-                    let data = self.lower_tuple_field(i, &field);
-                    fields.push(data);
-                    let attr = RawAttrs::new(self.db, &field, self.span_map());
-                    if !attr.is_empty() {
-                        attrs.push((i, attr))
-                    }
-                }
-                (fields.into(), FieldsShape::Tuple, attrs)
-            }
-            ast::StructKind::Unit => (Box::default(), FieldsShape::Unit, Vec::default()),
-        }
-    }
-
-    fn lower_record_field(&mut self, field: &ast::RecordField) -> Field {
-        let name = match field.name() {
-            Some(name) => name.as_name(),
-            None => Name::missing(),
-        };
-        let visibility = self.lower_visibility(field);
-
-        Field { name, visibility, is_unsafe: field.unsafe_token().is_some() }
+        Some(ast_id)
     }
 
-    fn lower_tuple_field(&mut self, idx: usize, field: &ast::TupleField) -> Field {
-        let name = Name::new_tuple_field(idx);
-        let visibility = self.lower_visibility(field);
-        Field { name, visibility, is_unsafe: false }
-    }
-
-    fn lower_union(&mut self, union: &ast::Union) -> Option<FileItemTreeId<Union>> {
+    fn lower_union(&mut self, union: &ast::Union) -> Option<ItemTreeAstId<Union>> {
         let visibility = self.lower_visibility(union);
         let name = union.name()?.as_name();
         let ast_id = self.source_ast_id_map.ast_id(union);
-        let (fields, _, attrs) = match union.record_field_list() {
-            Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)),
-            None => (Box::default(), FieldsShape::Record, Vec::default()),
-        };
-        let res = Union { name, visibility, fields, ast_id };
-        let id = id(self.data().unions.alloc(res));
-        for (idx, attr) in attrs {
-            self.add_attrs(
-                AttrOwner::Field(
-                    FieldParent::Union(id),
-                    Idx::from_raw(RawIdx::from_u32(idx as u32)),
-                ),
-                attr,
-            );
-        }
-        Some(id)
+        let res = Union { name, visibility };
+        self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Union(res));
+        Some(ast_id)
     }
 
-    fn lower_enum(&mut self, enum_: &ast::Enum) -> Option<FileItemTreeId<Enum>> {
+    fn lower_enum(&mut self, enum_: &ast::Enum) -> Option<ItemTreeAstId<Enum>> {
         let visibility = self.lower_visibility(enum_);
         let name = enum_.name()?.as_name();
         let ast_id = self.source_ast_id_map.ast_id(enum_);
-        let variants = match &enum_.variant_list() {
-            Some(variant_list) => self.lower_variants(variant_list),
-            None => {
-                FileItemTreeId(self.next_variant_idx())..FileItemTreeId(self.next_variant_idx())
-            }
-        };
-        let res = Enum { name, visibility, variants, ast_id };
-        let id = id(self.data().enums.alloc(res));
-        Some(id)
+        let res = Enum { name, visibility };
+        self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Enum(res));
+        Some(ast_id)
     }
 
-    fn lower_variants(&mut self, variants: &ast::VariantList) -> Range<FileItemTreeId<Variant>> {
-        let start = self.next_variant_idx();
-        for variant in variants.variants() {
-            let idx = self.lower_variant(&variant);
-            self.add_attrs(id(idx).into(), RawAttrs::new(self.db, &variant, self.span_map()));
-        }
-        let end = self.next_variant_idx();
-        FileItemTreeId(start)..FileItemTreeId(end)
-    }
-
-    fn lower_variant(&mut self, variant: &ast::Variant) -> Idx<Variant> {
-        let name = match variant.name() {
-            Some(name) => name.as_name(),
-            None => Name::missing(),
-        };
-        let (fields, kind, attrs) = self.lower_fields(&variant.kind());
-        let ast_id = self.source_ast_id_map.ast_id(variant);
-        let res = Variant { name, fields, shape: kind, ast_id };
-        let id = self.data().variants.alloc(res);
-        for (idx, attr) in attrs {
-            self.add_attrs(
-                AttrOwner::Field(
-                    FieldParent::EnumVariant(FileItemTreeId(id)),
-                    Idx::from_raw(RawIdx::from_u32(idx as u32)),
-                ),
-                attr,
-            );
-        }
-        id
-    }
-
-    fn lower_function(&mut self, func: &ast::Fn) -> Option<FileItemTreeId<Function>> {
+    fn lower_function(&mut self, func: &ast::Fn) -> Option<ItemTreeAstId<Function>> {
         let visibility = self.lower_visibility(func);
         let name = func.name()?.as_name();
 
         let ast_id = self.source_ast_id_map.ast_id(func);
 
-        let res = Function { name, visibility, ast_id };
+        let res = Function { name, visibility };
 
-        let id = id(self.data().functions.alloc(res));
-        Some(id)
+        self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Function(res));
+        Some(ast_id)
     }
 
     fn lower_type_alias(
         &mut self,
         type_alias: &ast::TypeAlias,
-    ) -> Option<FileItemTreeId<TypeAlias>> {
+    ) -> Option<ItemTreeAstId<TypeAlias>> {
         let name = type_alias.name()?.as_name();
         let visibility = self.lower_visibility(type_alias);
         let ast_id = self.source_ast_id_map.ast_id(type_alias);
-        let res = TypeAlias { name, visibility, ast_id };
-        let id = id(self.data().type_aliases.alloc(res));
-        Some(id)
+        let res = TypeAlias { name, visibility };
+        self.tree.small_data.insert(ast_id.upcast(), SmallModItem::TypeAlias(res));
+        Some(ast_id)
     }
 
-    fn lower_static(&mut self, static_: &ast::Static) -> Option<FileItemTreeId<Static>> {
+    fn lower_static(&mut self, static_: &ast::Static) -> Option<ItemTreeAstId<Static>> {
         let name = static_.name()?.as_name();
         let visibility = self.lower_visibility(static_);
         let ast_id = self.source_ast_id_map.ast_id(static_);
-        let res = Static { name, visibility, ast_id };
-        Some(id(self.data().statics.alloc(res)))
+        let res = Static { name, visibility };
+        self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Static(res));
+        Some(ast_id)
     }
 
-    fn lower_const(&mut self, konst: &ast::Const) -> FileItemTreeId<Const> {
+    fn lower_const(&mut self, konst: &ast::Const) -> ItemTreeAstId<Const> {
         let name = konst.name().map(|it| it.as_name());
         let visibility = self.lower_visibility(konst);
         let ast_id = self.source_ast_id_map.ast_id(konst);
-        let res = Const { name, visibility, ast_id };
-        id(self.data().consts.alloc(res))
+        let res = Const { name, visibility };
+        self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Const(res));
+        ast_id
     }
 
-    fn lower_module(&mut self, module: &ast::Module) -> Option<FileItemTreeId<Mod>> {
+    fn lower_module(&mut self, module: &ast::Module) -> Option<ItemTreeAstId<Mod>> {
         let name = module.name()?.as_name();
         let visibility = self.lower_visibility(module);
         let kind = if module.semicolon_token().is_some() {
@@ -381,70 +251,59 @@ impl<'a> Ctx<'a> {
             }
         };
         let ast_id = self.source_ast_id_map.ast_id(module);
-        let res = Mod { name, visibility, kind, ast_id };
-        Some(id(self.data().mods.alloc(res)))
+        let res = Mod { name, visibility, kind };
+        self.tree.big_data.insert(ast_id.upcast(), BigModItem::Mod(res));
+        Some(ast_id)
     }
 
-    fn lower_trait(&mut self, trait_def: &ast::Trait) -> Option<FileItemTreeId<Trait>> {
+    fn lower_trait(&mut self, trait_def: &ast::Trait) -> Option<ItemTreeAstId<Trait>> {
         let name = trait_def.name()?.as_name();
         let visibility = self.lower_visibility(trait_def);
         let ast_id = self.source_ast_id_map.ast_id(trait_def);
 
-        let items = trait_def
-            .assoc_item_list()
-            .into_iter()
-            .flat_map(|list| list.assoc_items())
-            .filter_map(|item_node| self.lower_assoc_item(&item_node))
-            .collect();
-
-        let def = Trait { name, visibility, items, ast_id };
-        let id = id(self.data().traits.alloc(def));
-        Some(id)
+        let def = Trait { name, visibility };
+        self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Trait(def));
+        Some(ast_id)
     }
 
     fn lower_trait_alias(
         &mut self,
         trait_alias_def: &ast::TraitAlias,
-    ) -> Option<FileItemTreeId<TraitAlias>> {
+    ) -> Option<ItemTreeAstId<TraitAlias>> {
         let name = trait_alias_def.name()?.as_name();
         let visibility = self.lower_visibility(trait_alias_def);
         let ast_id = self.source_ast_id_map.ast_id(trait_alias_def);
 
-        let alias = TraitAlias { name, visibility, ast_id };
-        let id = id(self.data().trait_aliases.alloc(alias));
-        Some(id)
+        let alias = TraitAlias { name, visibility };
+        self.tree.small_data.insert(ast_id.upcast(), SmallModItem::TraitAlias(alias));
+        Some(ast_id)
     }
 
-    fn lower_impl(&mut self, impl_def: &ast::Impl) -> FileItemTreeId<Impl> {
+    fn lower_impl(&mut self, impl_def: &ast::Impl) -> ItemTreeAstId<Impl> {
         let ast_id = self.source_ast_id_map.ast_id(impl_def);
-        // We cannot use `assoc_items()` here as that does not include macro calls.
-        let items = impl_def
-            .assoc_item_list()
-            .into_iter()
-            .flat_map(|it| it.assoc_items())
-            .filter_map(|item| self.lower_assoc_item(&item))
-            .collect();
         // Note that trait impls don't get implicit `Self` unlike traits, because here they are a
         // type alias rather than a type parameter, so this is handled by the resolver.
-        let res = Impl { items, ast_id };
-        id(self.data().impls.alloc(res))
+        let res = Impl {};
+        self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Impl(res));
+        ast_id
     }
 
-    fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Use>> {
+    fn lower_use(&mut self, use_item: &ast::Use) -> Option<ItemTreeAstId<Use>> {
         let visibility = self.lower_visibility(use_item);
         let ast_id = self.source_ast_id_map.ast_id(use_item);
         let (use_tree, _) = lower_use_tree(self.db, use_item.use_tree()?, &mut |range| {
             self.span_map().span_for_range(range).ctx
         })?;
 
-        let res = Use { visibility, ast_id, use_tree };
-        Some(id(self.data().uses.alloc(res)))
+        let res = Use { visibility, use_tree };
+        self.tree.big_data.insert(ast_id.upcast(), BigModItem::Use(res));
+        Some(ast_id)
     }
 
     fn lower_extern_crate(
         &mut self,
         extern_crate: &ast::ExternCrate,
-    ) -> Option<FileItemTreeId<ExternCrate>> {
+    ) -> Option<ItemTreeAstId<ExternCrate>> {
         let name = extern_crate.name_ref()?.as_name();
         let alias = extern_crate.rename().map(|a| {
             a.name().map(|it| it.as_name()).map_or(ImportAlias::Underscore, ImportAlias::Alias)
@@ -452,11 +311,12 @@ impl<'a> Ctx<'a> {
         let visibility = self.lower_visibility(extern_crate);
         let ast_id = self.source_ast_id_map.ast_id(extern_crate);
 
-        let res = ExternCrate { name, alias, visibility, ast_id };
-        Some(id(self.data().extern_crates.alloc(res)))
+        let res = ExternCrate { name, alias, visibility };
+        self.tree.big_data.insert(ast_id.upcast(), BigModItem::ExternCrate(res));
+        Some(ast_id)
     }
 
-    fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> {
+    fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<ItemTreeAstId<MacroCall>> {
         let span_map = self.span_map();
         let path = m.path()?;
         let range = path.syntax().text_range();
@@ -465,31 +325,33 @@ impl<'a> Ctx<'a> {
         })?);
         let ast_id = self.source_ast_id_map.ast_id(m);
         let expand_to = hir_expand::ExpandTo::from_call_site(m);
-        let res = MacroCall { path, ast_id, expand_to, ctxt: span_map.span_for_range(range).ctx };
-        Some(id(self.data().macro_calls.alloc(res)))
+        let res = MacroCall { path, expand_to, ctxt: span_map.span_for_range(range).ctx };
+        self.tree.small_data.insert(ast_id.upcast(), SmallModItem::MacroCall(res));
+        Some(ast_id)
     }
 
-    fn lower_macro_rules(&mut self, m: &ast::MacroRules) -> Option<FileItemTreeId<MacroRules>> {
+    fn lower_macro_rules(&mut self, m: &ast::MacroRules) -> Option<ItemTreeAstId<MacroRules>> {
         let name = m.name()?;
         let ast_id = self.source_ast_id_map.ast_id(m);
 
-        let res = MacroRules { name: name.as_name(), ast_id };
-        Some(id(self.data().macro_rules.alloc(res)))
+        let res = MacroRules { name: name.as_name() };
+        self.tree.small_data.insert(ast_id.upcast(), SmallModItem::MacroRules(res));
+        Some(ast_id)
     }
 
-    fn lower_macro_def(&mut self, m: &ast::MacroDef) -> Option<FileItemTreeId<Macro2>> {
+    fn lower_macro_def(&mut self, m: &ast::MacroDef) -> Option<ItemTreeAstId<Macro2>> {
         let name = m.name()?;
 
         let ast_id = self.source_ast_id_map.ast_id(m);
         let visibility = self.lower_visibility(m);
 
-        let res = Macro2 { name: name.as_name(), ast_id, visibility };
-        Some(id(self.data().macro_defs.alloc(res)))
+        let res = Macro2 { name: name.as_name(), visibility };
+        self.tree.small_data.insert(ast_id.upcast(), SmallModItem::Macro2(res));
+        Some(ast_id)
     }
 
-    fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> FileItemTreeId<ExternBlock> {
+    fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> ItemTreeAstId<ExternBlock> {
         let ast_id = self.source_ast_id_map.ast_id(block);
-        let abi = block.abi().map(lower_abi);
         let children: Box<[_]> = block.extern_item_list().map_or(Box::new([]), |list| {
             list.extern_items()
                 .filter_map(|item| {
@@ -497,42 +359,44 @@ impl<'a> Ctx<'a> {
                     // (in other words, the knowledge that they're in an extern block must not be used).
                     // This is because an extern block can contain macros whose ItemTree's top-level items
                     // should be considered to be in an extern block too.
-                    let mod_item: ModItem = match &item {
+                    let mod_item: ModItemId = match &item {
                         ast::ExternItem::Fn(ast) => self.lower_function(ast)?.into(),
                         ast::ExternItem::Static(ast) => self.lower_static(ast)?.into(),
                         ast::ExternItem::TypeAlias(ty) => self.lower_type_alias(ty)?.into(),
                         ast::ExternItem::MacroCall(call) => self.lower_macro_call(call)?.into(),
                     };
                     let attrs = RawAttrs::new(self.db, &item, self.span_map());
-                    self.add_attrs(mod_item.into(), attrs);
+                    self.add_attrs(mod_item.ast_id(), attrs);
                     Some(mod_item)
                 })
                 .collect()
         });
 
-        let res = ExternBlock { abi, ast_id, children };
-        id(self.data().extern_blocks.alloc(res))
+        let res = ExternBlock { children };
+        self.tree.small_data.insert(ast_id.upcast(), SmallModItem::ExternBlock(res));
+        ast_id
     }
 
     fn lower_visibility(&mut self, item: &dyn ast::HasVisibility) -> RawVisibilityId {
         let vis = visibility_from_ast(self.db, item.visibility(), &mut |range| {
             self.span_map().span_for_range(range).ctx
         });
-        self.data().vis.alloc(vis)
-    }
-
-    fn next_variant_idx(&self) -> Idx<Variant> {
-        Idx::from_raw(RawIdx::from(
-            self.tree.data.as_ref().map_or(0, |data| data.variants.len() as u32),
-        ))
-    }
-}
-
-fn lower_abi(abi: ast::Abi) -> Symbol {
-    match abi.abi_string() {
-        Some(tok) => Symbol::intern(tok.text_without_quotes()),
-        // `extern` default to be `extern "C"`.
-        _ => sym::C,
+        match &vis {
+            RawVisibility::Public => RawVisibilityId::PUB,
+            RawVisibility::Module(path, explicitness) if path.segments().is_empty() => {
+                match (path.kind, explicitness) {
+                    (PathKind::SELF, VisibilityExplicitness::Explicit) => {
+                        RawVisibilityId::PRIV_EXPLICIT
+                    }
+                    (PathKind::SELF, VisibilityExplicitness::Implicit) => {
+                        RawVisibilityId::PRIV_IMPLICIT
+                    }
+                    (PathKind::Crate, _) => RawVisibilityId::PUB_CRATE,
+                    _ => RawVisibilityId(self.visibilities.insert_full(vis).0 as u32),
+                }
+            }
+            _ => RawVisibilityId(self.visibilities.insert_full(vis).0 as u32),
+        }
     }
 }
 
@@ -561,17 +425,15 @@ impl UseTreeLowering<'_> {
                 }
             };
 
+            self.mapping.alloc(tree.clone());
             let list = use_tree_list
                 .use_trees()
                 .filter_map(|tree| self.lower_use_tree(tree, span_for_range))
                 .collect();
 
-            Some(
-                self.use_tree(
-                    UseTreeKind::Prefixed { prefix: prefix.map(Interned::new), list },
-                    tree,
-                ),
-            )
+            Some(UseTree {
+                kind: UseTreeKind::Prefixed { prefix: prefix.map(Interned::new), list },
+            })
         } else {
             let is_glob = tree.star_token().is_some();
             let path = match tree.path() {
@@ -590,23 +452,20 @@ impl UseTreeLowering<'_> {
                     if path.is_none() {
                         cov_mark::hit!(glob_enum_group);
                     }
-                    Some(self.use_tree(UseTreeKind::Glob { path: path.map(Interned::new) }, tree))
+                    self.mapping.alloc(tree.clone());
+                    Some(UseTree { kind: UseTreeKind::Glob { path: path.map(Interned::new) } })
                 }
                 // Globs can't be renamed
                 (_, Some(_), true) | (None, None, false) => None,
                 // `bla::{ as Name}` is invalid
                 (None, Some(_), false) => None,
-                (Some(path), alias, false) => Some(
-                    self.use_tree(UseTreeKind::Single { path: Interned::new(path), alias }, tree),
-                ),
+                (Some(path), alias, false) => {
+                    self.mapping.alloc(tree.clone());
+                    Some(UseTree { kind: UseTreeKind::Single { path: Interned::new(path), alias } })
+                }
             }
         }
     }
-
-    fn use_tree(&mut self, kind: UseTreeKind, ast: ast::UseTree) -> UseTree {
-        let index = self.mapping.alloc(ast);
-        UseTree { index, kind }
-    }
 }
 
 pub(crate) fn lower_use_tree(
@@ -626,7 +485,7 @@ fn private_vis() -> RawVisibility {
     )
 }
 
-fn visibility_from_ast(
+pub(crate) fn visibility_from_ast(
     db: &dyn DefDatabase,
     node: Option<ast::Visibility>,
     span_for_range: &mut dyn FnMut(::tt::TextRange) -> SyntaxContext,
@@ -647,3 +506,11 @@ fn visibility_from_ast(
     };
     RawVisibility::Module(Interned::new(path), VisibilityExplicitness::Explicit)
 }
+
+fn adt_shape(kind: StructKind) -> FieldsShape {
+    match kind {
+        StructKind::Record(_) => FieldsShape::Record,
+        StructKind::Tuple(_) => FieldsShape::Tuple,
+        StructKind::Unit => FieldsShape::Unit,
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
index 47c6eb13293..696174cb072 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
@@ -2,15 +2,13 @@
 
 use std::fmt::{self, Write};
 
-use la_arena::{Idx, RawIdx};
 use span::{Edition, ErasedFileAstId};
 
 use crate::{
     item_tree::{
-        AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, Field, FieldParent,
-        FieldsShape, FileItemTreeId, Function, Impl, ItemTree, Macro2, MacroCall, MacroRules, Mod,
-        ModItem, ModKind, RawAttrs, RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias,
-        Union, Use, UseTree, UseTreeKind, Variant,
+        Const, DefDatabase, Enum, ExternBlock, ExternCrate, FieldsShape, Function, Impl, ItemTree,
+        Macro2, MacroCall, MacroRules, Mod, ModItemId, ModKind, RawAttrs, RawVisibilityId, Static,
+        Struct, Trait, TraitAlias, TypeAlias, Union, Use, UseTree, UseTreeKind,
     },
     visibility::RawVisibility,
 };
@@ -19,9 +17,7 @@ pub(super) fn print_item_tree(db: &dyn DefDatabase, tree: &ItemTree, edition: Ed
     let mut p =
         Printer { db, tree, buf: String::new(), indent_level: 0, needs_indent: true, edition };
 
-    if let Some(attrs) = tree.attrs.get(&AttrOwner::TopLevel) {
-        p.print_attrs(attrs, true, "\n");
-    }
+    p.print_attrs(&tree.top_attrs, true, "\n");
     p.blank();
 
     for item in tree.top_level_items() {
@@ -103,8 +99,8 @@ impl Printer<'_> {
         }
     }
 
-    fn print_attrs_of(&mut self, of: impl Into<AttrOwner>, separated_by: &str) {
-        if let Some(attrs) = self.tree.attrs.get(&of.into()) {
+    fn print_attrs_of(&mut self, of: ModItemId, separated_by: &str) {
+        if let Some(attrs) = self.tree.attrs.get(&of.ast_id()) {
             self.print_attrs(attrs, false, separated_by);
         }
     }
@@ -112,50 +108,22 @@ impl Printer<'_> {
     fn print_visibility(&mut self, vis: RawVisibilityId) {
         match &self.tree[vis] {
             RawVisibility::Module(path, _expl) => {
-                w!(self, "pub({}) ", path.display(self.db, self.edition))
+                w!(self, "pub(in {}) ", path.display(self.db, self.edition))
             }
             RawVisibility::Public => w!(self, "pub "),
+            RawVisibility::PubCrate => w!(self, "pub(crate) "),
+            RawVisibility::PubSelf(_) => w!(self, "pub(self) "),
         };
     }
 
-    fn print_fields(&mut self, parent: FieldParent, kind: FieldsShape, fields: &[Field]) {
-        let edition = self.edition;
+    fn print_fields(&mut self, kind: FieldsShape) {
         match kind {
             FieldsShape::Record => {
                 self.whitespace();
-                w!(self, "{{");
-                self.indented(|this| {
-                    for (idx, Field { name, visibility, is_unsafe }) in fields.iter().enumerate() {
-                        this.print_attrs_of(
-                            AttrOwner::Field(parent, Idx::from_raw(RawIdx::from(idx as u32))),
-                            "\n",
-                        );
-                        this.print_visibility(*visibility);
-                        if *is_unsafe {
-                            w!(this, "unsafe ");
-                        }
-
-                        wln!(this, "{},", name.display(self.db, edition));
-                    }
-                });
-                w!(self, "}}");
+                w!(self, "{{ ... }}");
             }
             FieldsShape::Tuple => {
-                w!(self, "(");
-                self.indented(|this| {
-                    for (idx, Field { name, visibility, is_unsafe }) in fields.iter().enumerate() {
-                        this.print_attrs_of(
-                            AttrOwner::Field(parent, Idx::from_raw(RawIdx::from(idx as u32))),
-                            "\n",
-                        );
-                        this.print_visibility(*visibility);
-                        if *is_unsafe {
-                            w!(this, "unsafe ");
-                        }
-                        wln!(this, "{},", name.display(self.db, edition));
-                    }
-                });
-                w!(self, ")");
+                w!(self, "(...)");
             }
             FieldsShape::Unit => {}
         }
@@ -191,20 +159,20 @@ impl Printer<'_> {
         }
     }
 
-    fn print_mod_item(&mut self, item: ModItem) {
+    fn print_mod_item(&mut self, item: ModItemId) {
         self.print_attrs_of(item, "\n");
 
         match item {
-            ModItem::Use(it) => {
-                let Use { visibility, use_tree, ast_id } = &self.tree[it];
+            ModItemId::Use(ast_id) => {
+                let Use { visibility, use_tree } = &self.tree[ast_id];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "use ");
                 self.print_use_tree(use_tree);
                 wln!(self, ";");
             }
-            ModItem::ExternCrate(it) => {
-                let ExternCrate { name, alias, visibility, ast_id } = &self.tree[it];
+            ModItemId::ExternCrate(ast_id) => {
+                let ExternCrate { name, alias, visibility } = &self.tree[ast_id];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "extern crate {}", name.display(self.db, self.edition));
@@ -213,14 +181,10 @@ impl Printer<'_> {
                 }
                 wln!(self, ";");
             }
-            ModItem::ExternBlock(it) => {
-                let ExternBlock { abi, ast_id, children } = &self.tree[it];
+            ModItemId::ExternBlock(ast_id) => {
+                let ExternBlock { children } = &self.tree[ast_id];
                 self.print_ast_id(ast_id.erase());
-                w!(self, "extern ");
-                if let Some(abi) = abi {
-                    w!(self, "\"{}\" ", abi);
-                }
-                w!(self, "{{");
+                w!(self, "extern {{");
                 self.indented(|this| {
                     for child in &**children {
                         this.print_mod_item(*child);
@@ -228,52 +192,40 @@ impl Printer<'_> {
                 });
                 wln!(self, "}}");
             }
-            ModItem::Function(it) => {
-                let Function { name, visibility, ast_id } = &self.tree[it];
+            ModItemId::Function(ast_id) => {
+                let Function { name, visibility } = &self.tree[ast_id];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 wln!(self, "fn {};", name.display(self.db, self.edition));
             }
-            ModItem::Struct(it) => {
-                let Struct { visibility, name, fields, shape: kind, ast_id } = &self.tree[it];
+            ModItemId::Struct(ast_id) => {
+                let Struct { visibility, name, shape: kind } = &self.tree[ast_id];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "struct {}", name.display(self.db, self.edition));
-                self.print_fields(FieldParent::Struct(it), *kind, fields);
+                self.print_fields(*kind);
                 if matches!(kind, FieldsShape::Record) {
                     wln!(self);
                 } else {
                     wln!(self, ";");
                 }
             }
-            ModItem::Union(it) => {
-                let Union { name, visibility, fields, ast_id } = &self.tree[it];
+            ModItemId::Union(ast_id) => {
+                let Union { name, visibility } = &self.tree[ast_id];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "union {}", name.display(self.db, self.edition));
-                self.print_fields(FieldParent::Union(it), FieldsShape::Record, fields);
+                self.print_fields(FieldsShape::Record);
                 wln!(self);
             }
-            ModItem::Enum(it) => {
-                let Enum { name, visibility, variants, ast_id } = &self.tree[it];
+            ModItemId::Enum(ast_id) => {
+                let Enum { name, visibility } = &self.tree[ast_id];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
-                w!(self, "enum {}", name.display(self.db, self.edition));
-                let edition = self.edition;
-                self.indented(|this| {
-                    for variant in FileItemTreeId::range_iter(variants.clone()) {
-                        let Variant { name, fields, shape: kind, ast_id } = &this.tree[variant];
-                        this.print_ast_id(ast_id.erase());
-                        this.print_attrs_of(variant, "\n");
-                        w!(this, "{}", name.display(self.db, edition));
-                        this.print_fields(FieldParent::EnumVariant(variant), *kind, fields);
-                        wln!(this, ",");
-                    }
-                });
-                wln!(self, "}}");
+                w!(self, "enum {} {{ ... }}", name.display(self.db, self.edition));
             }
-            ModItem::Const(it) => {
-                let Const { name, visibility, ast_id } = &self.tree[it];
+            ModItemId::Const(ast_id) => {
+                let Const { name, visibility } = &self.tree[ast_id];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "const ");
@@ -283,8 +235,8 @@ impl Printer<'_> {
                 }
                 wln!(self, " = _;");
             }
-            ModItem::Static(it) => {
-                let Static { name, visibility, ast_id } = &self.tree[it];
+            ModItemId::Static(ast_id) => {
+                let Static { name, visibility } = &self.tree[ast_id];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "static ");
@@ -292,45 +244,33 @@ impl Printer<'_> {
                 w!(self, " = _;");
                 wln!(self);
             }
-            ModItem::Trait(it) => {
-                let Trait { name, visibility, items, ast_id } = &self.tree[it];
+            ModItemId::Trait(ast_id) => {
+                let Trait { name, visibility } = &self.tree[ast_id];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
-                w!(self, "trait {} {{", name.display(self.db, self.edition));
-                self.indented(|this| {
-                    for item in &**items {
-                        this.print_mod_item((*item).into());
-                    }
-                });
-                wln!(self, "}}");
+                w!(self, "trait {} {{ ... }}", name.display(self.db, self.edition));
             }
-            ModItem::TraitAlias(it) => {
-                let TraitAlias { name, visibility, ast_id } = &self.tree[it];
+            ModItemId::TraitAlias(ast_id) => {
+                let TraitAlias { name, visibility } = &self.tree[ast_id];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 wln!(self, "trait {} = ..;", name.display(self.db, self.edition));
             }
-            ModItem::Impl(it) => {
-                let Impl { items, ast_id } = &self.tree[it];
+            ModItemId::Impl(ast_id) => {
+                let Impl {} = &self.tree[ast_id];
                 self.print_ast_id(ast_id.erase());
-                w!(self, "impl {{");
-                self.indented(|this| {
-                    for item in &**items {
-                        this.print_mod_item((*item).into());
-                    }
-                });
-                wln!(self, "}}");
+                w!(self, "impl {{ ... }}");
             }
-            ModItem::TypeAlias(it) => {
-                let TypeAlias { name, visibility, ast_id } = &self.tree[it];
+            ModItemId::TypeAlias(ast_id) => {
+                let TypeAlias { name, visibility } = &self.tree[ast_id];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "type {}", name.display(self.db, self.edition));
                 w!(self, ";");
                 wln!(self);
             }
-            ModItem::Mod(it) => {
-                let Mod { name, visibility, kind, ast_id } = &self.tree[it];
+            ModItemId::Mod(ast_id) => {
+                let Mod { name, visibility, kind } = &self.tree[ast_id];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "mod {}", name.display(self.db, self.edition));
@@ -349,24 +289,24 @@ impl Printer<'_> {
                     }
                 }
             }
-            ModItem::MacroCall(it) => {
-                let MacroCall { path, ast_id, expand_to, ctxt } = &self.tree[it];
+            ModItemId::MacroCall(ast_id) => {
+                let MacroCall { path, expand_to, ctxt } = &self.tree[ast_id];
                 let _ = writeln!(
                     self,
-                    "// AstId: {:?}, SyntaxContextId: {}, ExpandTo: {:?}",
-                    ast_id.erase().into_raw(),
+                    "// AstId: {:#?}, SyntaxContextId: {}, ExpandTo: {:?}",
+                    ast_id.erase(),
                     ctxt,
                     expand_to
                 );
                 wln!(self, "{}!(...);", path.display(self.db, self.edition));
             }
-            ModItem::MacroRules(it) => {
-                let MacroRules { name, ast_id } = &self.tree[it];
+            ModItemId::MacroRules(ast_id) => {
+                let MacroRules { name } = &self.tree[ast_id];
                 self.print_ast_id(ast_id.erase());
                 wln!(self, "macro_rules! {} {{ ... }}", name.display(self.db, self.edition));
             }
-            ModItem::Macro2(it) => {
-                let Macro2 { name, visibility, ast_id } = &self.tree[it];
+            ModItemId::Macro2(ast_id) => {
+                let Macro2 { name, visibility } = &self.tree[ast_id];
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 wln!(self, "macro {} {{ ... }}", name.display(self.db, self.edition));
@@ -377,7 +317,7 @@ impl Printer<'_> {
     }
 
     fn print_ast_id(&mut self, ast_id: ErasedFileAstId) {
-        wln!(self, "// AstId: {:?}", ast_id.into_raw());
+        wln!(self, "// AstId: {ast_id:#?}");
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
index 824fbfa5921..5923b3ea491 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
@@ -35,23 +35,23 @@ use a::{c, d::{e}};
             #![no_std]
             #![doc = " another file comment"]
 
-            // AstId: 1
+            // AstId: ExternCrate[5A82, 0]
             pub(self) extern crate self as renamed;
 
-            // AstId: 2
-            pub(super) extern crate bli;
+            // AstId: ExternCrate[7E1C, 0]
+            pub(in super) extern crate bli;
 
-            // AstId: 3
+            // AstId: Use[0000, 0]
             pub use crate::path::{nested, items as renamed, Trait as _};
 
-            // AstId: 4
+            // AstId: Use[0000, 1]
             pub(self) use globs::*;
 
             #[doc = " docs on import"]
-            // AstId: 5
+            // AstId: Use[0000, 2]
             pub(self) use crate::{A, B};
 
-            // AstId: 6
+            // AstId: Use[0000, 3]
             pub(self) use a::{c, d::{e}};
         "##]],
     );
@@ -73,23 +73,23 @@ extern "C" {
     fn ex_fn();
 }
         "#,
-        expect![[r##"
+        expect![[r#"
             #[on_extern_block]
-            // AstId: 1
-            extern "C" {
+            // AstId: ExternBlock[0000, 0]
+            extern {
                 #[on_extern_type]
-                // AstId: 2
+                // AstId: TypeAlias[9FDF, 0]
                 pub(self) type ExType;
 
                 #[on_extern_static]
-                // AstId: 3
+                // AstId: Static[43C1, 0]
                 pub(self) static EX_STATIC = _;
 
                 #[on_extern_fn]
-                // AstId: 4
+                // AstId: Fn[452D, 0]
                 pub(self) fn ex_fn;
             }
-        "##]],
+        "#]],
     );
 }
 
@@ -124,44 +124,21 @@ enum E {
 }
         "#,
         expect![[r#"
-            // AstId: 1
+            // AstId: Struct[DFF3, 0]
             pub(self) struct Unit;
 
             #[derive(Debug)]
-            // AstId: 2
-            pub(self) struct Struct {
-                #[doc = " fld docs"]
-                pub(self) fld,
-            }
+            // AstId: Struct[C7A1, 0]
+            pub(self) struct Struct { ... }
 
-            // AstId: 3
-            pub(self) struct Tuple(
-                #[attr]
-                pub(self) 0,
-            );
+            // AstId: Struct[DAC2, 0]
+            pub(self) struct Tuple(...);
 
-            // AstId: 4
-            pub(self) union Ize {
-                pub(self) a,
-                pub(self) b,
-            }
+            // AstId: Union[2DBB, 0]
+            pub(self) union Ize { ... }
 
-            // AstId: 5
-            pub(self) enum E
-                // AstId: 6
-                #[doc = " comment on Unit"]
-                Unit,
-                // AstId: 7
-                #[doc = " comment on Tuple"]
-                Tuple(
-                    pub(self) 0,
-                ),
-                // AstId: 8
-                Struct {
-                    #[doc = " comment on a: u8"]
-                    pub(self) a,
-                },
-            }
+            // AstId: Enum[7FF8, 0]
+            pub(self) enum E { ... }
         "#]],
     );
 }
@@ -185,25 +162,19 @@ trait Tr: SuperTrait + 'lifetime {
 }
         "#,
         expect![[r#"
-            // AstId: 1
+            // AstId: Static[B393, 0]
             pub static ST = _;
 
-            // AstId: 2
+            // AstId: Const[B309, 0]
             pub(self) const _ = _;
 
             #[attr]
             #[inner_attr_in_fn]
-            // AstId: 3
+            // AstId: Fn[75E3, 0]
             pub(self) fn f;
 
-            // AstId: 4
-            pub(self) trait Tr {
-                // AstId: 6
-                pub(self) type Assoc;
-
-                // AstId: 7
-                pub(self) fn method;
-            }
+            // AstId: Trait[2998, 0]
+            pub(self) trait Tr { ... }
         "#]],
     );
 }
@@ -226,16 +197,16 @@ mod outline;
         expect![[r##"
             #[doc = " outer"]
             #[doc = " inner"]
-            // AstId: 1
+            // AstId: Module[CF93, 0]
             pub(self) mod inline {
-                // AstId: 3
+                // AstId: Use[0000, 0]
                 pub(self) use super::*;
 
-                // AstId: 4
+                // AstId: Fn[1B26, 0]
                 pub(self) fn fn_in_module;
             }
 
-            // AstId: 2
+            // AstId: Module[8994, 0]
             pub(self) mod outline;
         "##]],
     );
@@ -254,13 +225,13 @@ pub macro m2() {}
 m!();
         "#,
         expect![[r#"
-            // AstId: 1
+            // AstId: MacroRules[88CE, 0]
             macro_rules! m { ... }
 
-            // AstId: 2
+            // AstId: MacroDef[DC34, 0]
             pub macro m2 { ... }
 
-            // AstId: 3, SyntaxContextId: ROOT2024, ExpandTo: Items
+            // AstId: MacroCall[612F, 0], SyntaxContextId: ROOT2024, ExpandTo: Items
             m!(...);
         "#]],
     );
@@ -273,7 +244,7 @@ fn pub_self() {
 pub(self) struct S;
         "#,
         expect![[r#"
-            // AstId: 1
+            // AstId: Struct[42E2, 0]
             pub(self) struct S;
         "#]],
     )
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
index 4ad44775ea1..faff7d036a2 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
@@ -96,7 +96,7 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option<Box<LangIt
     for (_, module_data) in crate_def_map.modules() {
         for impl_def in module_data.scope.impls() {
             lang_items.collect_lang_item(db, impl_def, LangItemTarget::ImplDef);
-            for &(_, assoc) in db.impl_items(impl_def).items.iter() {
+            for &(_, assoc) in impl_def.impl_items(db).items.iter() {
                 match assoc {
                     AssocItemId::FunctionId(f) => {
                         lang_items.collect_lang_item(db, f, LangItemTarget::Function)
@@ -125,7 +125,7 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option<Box<LangIt
                 }
                 ModuleDefId::AdtId(AdtId::EnumId(e)) => {
                     lang_items.collect_lang_item(db, e, LangItemTarget::EnumId);
-                    db.enum_variants(e).variants.iter().for_each(|&(id, _)| {
+                    e.enum_variants(db).variants.iter().for_each(|&(id, _, _)| {
                         lang_items.collect_lang_item(db, id, LangItemTarget::EnumVariant);
                     });
                 }
@@ -377,6 +377,7 @@ language_item_table! {
     AsyncFnMut,              sym::async_fn_mut,        async_fn_mut_trait,         Target::Trait,          GenericRequirement::Exact(1);
     AsyncFnOnce,             sym::async_fn_once,       async_fn_once_trait,        Target::Trait,          GenericRequirement::Exact(1);
 
+    AsyncFnOnceOutput,       sym::async_fn_once_output,async_fn_once_output,       Target::AssocTy,        GenericRequirement::None;
     FnOnceOutput,            sym::fn_once_output,      fn_once_output,             Target::AssocTy,        GenericRequirement::None;
 
     Future,                  sym::future_trait,        future_trait,               Target::Trait,          GenericRequirement::Exact(0);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
index b41ff026bca..a542214d303 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -49,8 +49,9 @@ pub mod find_path;
 pub mod import_map;
 pub mod visibility;
 
-use intern::{Interned, sym};
+use intern::{Interned, Symbol, sym};
 pub use rustc_abi as layout;
+use thin_vec::ThinVec;
 use triomphe::Arc;
 
 pub use crate::signatures::LocalFieldId;
@@ -74,12 +75,11 @@ use hir_expand::{
     name::Name,
     proc_macro::{CustomProcMacroExpander, ProcMacroKind},
 };
-use item_tree::ExternBlock;
 use la_arena::Idx;
 use nameres::DefMap;
 use span::{AstIdNode, Edition, FileAstId, SyntaxContext};
 use stdx::impl_from;
-use syntax::ast;
+use syntax::{AstNode, ast};
 
 pub use hir_expand::{Intern, Lookup, tt};
 
@@ -88,12 +88,11 @@ use crate::{
     builtin_type::BuiltinType,
     db::DefDatabase,
     hir::generics::{LocalLifetimeParamId, LocalTypeOrConstParamId},
-    item_tree::{
-        Const, Enum, ExternCrate, Function, Impl, ItemTreeId, ItemTreeNode, Macro2, MacroRules,
-        Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, Variant,
+    nameres::{
+        LocalDefMap, assoc::ImplItems, block_def_map, crate_def_map, crate_local_def_map,
+        diagnostics::DefDiagnostics,
     },
-    nameres::{LocalDefMap, block_def_map, crate_def_map, crate_local_def_map},
-    signatures::VariantFields,
+    signatures::{EnumVariants, InactiveEnumVariantCode, VariantFields},
 };
 
 type FxIndexMap<K, V> = indexmap::IndexMap<K, V, rustc_hash::FxBuildHasher>;
@@ -113,70 +112,111 @@ pub struct ImportPathConfig {
 }
 
 #[derive(Debug)]
-pub struct ItemLoc<N: ItemTreeNode> {
+pub struct ItemLoc<N: AstIdNode> {
     pub container: ModuleId,
-    pub id: ItemTreeId<N>,
+    pub id: AstId<N>,
 }
 
-impl<N: ItemTreeNode> Clone for ItemLoc<N> {
+impl<N: AstIdNode> Clone for ItemLoc<N> {
     fn clone(&self) -> Self {
         *self
     }
 }
 
-impl<N: ItemTreeNode> Copy for ItemLoc<N> {}
+impl<N: AstIdNode> Copy for ItemLoc<N> {}
 
-impl<N: ItemTreeNode> PartialEq for ItemLoc<N> {
+impl<N: AstIdNode> PartialEq for ItemLoc<N> {
     fn eq(&self, other: &Self) -> bool {
         self.container == other.container && self.id == other.id
     }
 }
 
-impl<N: ItemTreeNode> Eq for ItemLoc<N> {}
+impl<N: AstIdNode> Eq for ItemLoc<N> {}
 
-impl<N: ItemTreeNode> Hash for ItemLoc<N> {
+impl<N: AstIdNode> Hash for ItemLoc<N> {
     fn hash<H: Hasher>(&self, state: &mut H) {
         self.container.hash(state);
         self.id.hash(state);
     }
 }
 
+impl<N: AstIdNode> HasModule for ItemLoc<N> {
+    #[inline]
+    fn module(&self, _db: &dyn DefDatabase) -> ModuleId {
+        self.container
+    }
+}
+
 #[derive(Debug)]
-pub struct AssocItemLoc<N: ItemTreeNode> {
+pub struct AssocItemLoc<N: AstIdNode> {
+    // FIXME: Store this as an erased `salsa::Id` to save space
     pub container: ItemContainerId,
-    pub id: ItemTreeId<N>,
+    pub id: AstId<N>,
 }
 
-impl<N: ItemTreeNode> Clone for AssocItemLoc<N> {
+impl<N: AstIdNode> Clone for AssocItemLoc<N> {
     fn clone(&self) -> Self {
         *self
     }
 }
 
-impl<N: ItemTreeNode> Copy for AssocItemLoc<N> {}
+impl<N: AstIdNode> Copy for AssocItemLoc<N> {}
 
-impl<N: ItemTreeNode> PartialEq for AssocItemLoc<N> {
+impl<N: AstIdNode> PartialEq for AssocItemLoc<N> {
     fn eq(&self, other: &Self) -> bool {
         self.container == other.container && self.id == other.id
     }
 }
 
-impl<N: ItemTreeNode> Eq for AssocItemLoc<N> {}
+impl<N: AstIdNode> Eq for AssocItemLoc<N> {}
 
-impl<N: ItemTreeNode> Hash for AssocItemLoc<N> {
+impl<N: AstIdNode> Hash for AssocItemLoc<N> {
     fn hash<H: Hasher>(&self, state: &mut H) {
         self.container.hash(state);
         self.id.hash(state);
     }
 }
 
-pub trait ItemTreeLoc {
+impl<N: AstIdNode> HasModule for AssocItemLoc<N> {
+    #[inline]
+    fn module(&self, db: &dyn DefDatabase) -> ModuleId {
+        self.container.module(db)
+    }
+}
+
+pub trait AstIdLoc {
     type Container;
-    type Id;
-    fn item_tree_id(&self) -> ItemTreeId<Self::Id>;
+    type Ast: AstNode;
+    fn ast_id(&self) -> AstId<Self::Ast>;
     fn container(&self) -> Self::Container;
 }
 
+impl<N: AstIdNode> AstIdLoc for ItemLoc<N> {
+    type Container = ModuleId;
+    type Ast = N;
+    #[inline]
+    fn ast_id(&self) -> AstId<Self::Ast> {
+        self.id
+    }
+    #[inline]
+    fn container(&self) -> Self::Container {
+        self.container
+    }
+}
+
+impl<N: AstIdNode> AstIdLoc for AssocItemLoc<N> {
+    type Container = ItemContainerId;
+    type Ast = N;
+    #[inline]
+    fn ast_id(&self) -> AstId<Self::Ast> {
+        self.id
+    }
+    #[inline]
+    fn container(&self) -> Self::Container {
+        self.container
+    }
+}
+
 macro_rules! impl_intern {
     ($id:ident, $loc:ident, $intern:ident, $lookup:ident) => {
         impl_intern_key!($id, $loc);
@@ -186,74 +226,103 @@ macro_rules! impl_intern {
 
 macro_rules! impl_loc {
     ($loc:ident, $id:ident: $id_ty:ident, $container:ident: $container_type:ident) => {
-        impl ItemTreeLoc for $loc {
+        impl AstIdLoc for $loc {
             type Container = $container_type;
-            type Id = $id_ty;
-            fn item_tree_id(&self) -> ItemTreeId<Self::Id> {
+            type Ast = ast::$id_ty;
+            fn ast_id(&self) -> AstId<Self::Ast> {
                 self.$id
             }
             fn container(&self) -> Self::Container {
                 self.$container
             }
         }
+
+        impl HasModule for $loc {
+            #[inline]
+            fn module(&self, db: &dyn DefDatabase) -> ModuleId {
+                self.$container.module(db)
+            }
+        }
     };
 }
 
-type FunctionLoc = AssocItemLoc<Function>;
+type FunctionLoc = AssocItemLoc<ast::Fn>;
 impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function);
-impl_loc!(FunctionLoc, id: Function, container: ItemContainerId);
 
-type StructLoc = ItemLoc<Struct>;
+type StructLoc = ItemLoc<ast::Struct>;
 impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct);
-impl_loc!(StructLoc, id: Struct, container: ModuleId);
 
-pub type UnionLoc = ItemLoc<Union>;
+pub type UnionLoc = ItemLoc<ast::Union>;
 impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union);
-impl_loc!(UnionLoc, id: Union, container: ModuleId);
 
-pub type EnumLoc = ItemLoc<Enum>;
+pub type EnumLoc = ItemLoc<ast::Enum>;
 impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum);
-impl_loc!(EnumLoc, id: Enum, container: ModuleId);
 
-type ConstLoc = AssocItemLoc<Const>;
+impl EnumId {
+    #[inline]
+    pub fn enum_variants(self, db: &dyn DefDatabase) -> &EnumVariants {
+        &self.enum_variants_with_diagnostics(db).0
+    }
+
+    #[inline]
+    pub fn enum_variants_with_diagnostics(
+        self,
+        db: &dyn DefDatabase,
+    ) -> &(EnumVariants, Option<ThinVec<InactiveEnumVariantCode>>) {
+        EnumVariants::of(db, self)
+    }
+}
+
+type ConstLoc = AssocItemLoc<ast::Const>;
 impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const);
-impl_loc!(ConstLoc, id: Const, container: ItemContainerId);
 
-pub type StaticLoc = AssocItemLoc<Static>;
+pub type StaticLoc = AssocItemLoc<ast::Static>;
 impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static);
-impl_loc!(StaticLoc, id: Static, container: ItemContainerId);
 
-pub type TraitLoc = ItemLoc<Trait>;
+pub type TraitLoc = ItemLoc<ast::Trait>;
 impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait);
-impl_loc!(TraitLoc, id: Trait, container: ModuleId);
 
-pub type TraitAliasLoc = ItemLoc<TraitAlias>;
+pub type TraitAliasLoc = ItemLoc<ast::TraitAlias>;
 impl_intern!(TraitAliasId, TraitAliasLoc, intern_trait_alias, lookup_intern_trait_alias);
-impl_loc!(TraitAliasLoc, id: TraitAlias, container: ModuleId);
 
-type TypeAliasLoc = AssocItemLoc<TypeAlias>;
+type TypeAliasLoc = AssocItemLoc<ast::TypeAlias>;
 impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_alias);
-impl_loc!(TypeAliasLoc, id: TypeAlias, container: ItemContainerId);
 
-type ImplLoc = ItemLoc<Impl>;
+type ImplLoc = ItemLoc<ast::Impl>;
 impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl);
-impl_loc!(ImplLoc, id: Impl, container: ModuleId);
 
-type UseLoc = ItemLoc<Use>;
+impl ImplId {
+    #[inline]
+    pub fn impl_items(self, db: &dyn DefDatabase) -> &ImplItems {
+        &self.impl_items_with_diagnostics(db).0
+    }
+
+    #[inline]
+    pub fn impl_items_with_diagnostics(self, db: &dyn DefDatabase) -> &(ImplItems, DefDiagnostics) {
+        ImplItems::of(db, self)
+    }
+}
+
+type UseLoc = ItemLoc<ast::Use>;
 impl_intern!(UseId, UseLoc, intern_use, lookup_intern_use);
-impl_loc!(UseLoc, id: Use, container: ModuleId);
 
-type ExternCrateLoc = ItemLoc<ExternCrate>;
+type ExternCrateLoc = ItemLoc<ast::ExternCrate>;
 impl_intern!(ExternCrateId, ExternCrateLoc, intern_extern_crate, lookup_intern_extern_crate);
-impl_loc!(ExternCrateLoc, id: ExternCrate, container: ModuleId);
 
-type ExternBlockLoc = ItemLoc<ExternBlock>;
+type ExternBlockLoc = ItemLoc<ast::ExternBlock>;
 impl_intern!(ExternBlockId, ExternBlockLoc, intern_extern_block, lookup_intern_extern_block);
-impl_loc!(ExternBlockLoc, id: ExternBlock, container: ModuleId);
+
+#[salsa::tracked]
+impl ExternBlockId {
+    #[salsa::tracked]
+    pub fn abi(self, db: &dyn DefDatabase) -> Option<Symbol> {
+        signatures::extern_block_abi(db, self)
+    }
+}
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct EnumVariantLoc {
-    pub id: ItemTreeId<Variant>,
+    pub id: AstId<ast::Variant>,
     pub parent: EnumId,
     pub index: u32,
 }
@@ -262,18 +331,18 @@ impl_loc!(EnumVariantLoc, id: Variant, parent: EnumId);
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct Macro2Loc {
     pub container: ModuleId,
-    pub id: ItemTreeId<Macro2>,
+    pub id: AstId<ast::MacroDef>,
     pub expander: MacroExpander,
     pub allow_internal_unsafe: bool,
     pub edition: Edition,
 }
 impl_intern!(Macro2Id, Macro2Loc, intern_macro2, lookup_intern_macro2);
-impl_loc!(Macro2Loc, id: Macro2, container: ModuleId);
+impl_loc!(Macro2Loc, id: MacroDef, container: ModuleId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct MacroRulesLoc {
     pub container: ModuleId,
-    pub id: ItemTreeId<MacroRules>,
+    pub id: AstId<ast::MacroRules>,
     pub expander: MacroExpander,
     pub flags: MacroRulesLocFlags,
     pub edition: Edition,
@@ -301,13 +370,13 @@ pub enum MacroExpander {
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct ProcMacroLoc {
     pub container: CrateRootModuleId,
-    pub id: ItemTreeId<Function>,
+    pub id: AstId<ast::Fn>,
     pub expander: CustomProcMacroExpander,
     pub kind: ProcMacroKind,
     pub edition: Edition,
 }
 impl_intern!(ProcMacroId, ProcMacroLoc, intern_proc_macro, lookup_intern_proc_macro);
-impl_loc!(ProcMacroLoc, id: Function, container: CrateRootModuleId);
+impl_loc!(ProcMacroLoc, id: Fn, container: CrateRootModuleId);
 
 #[derive(Debug, Hash, PartialEq, Eq, Clone)]
 pub struct BlockLoc {
@@ -315,7 +384,26 @@ pub struct BlockLoc {
     /// The containing module.
     pub module: ModuleId,
 }
-impl_intern!(BlockId, BlockLoc, intern_block, lookup_intern_block);
+#[salsa_macros::tracked(debug)]
+#[derive(PartialOrd, Ord)]
+pub struct BlockIdLt<'db> {
+    pub loc: BlockLoc,
+}
+pub type BlockId = BlockIdLt<'static>;
+impl hir_expand::Intern for BlockLoc {
+    type Database = dyn DefDatabase;
+    type ID = BlockId;
+    fn intern(self, db: &Self::Database) -> Self::ID {
+        unsafe { std::mem::transmute::<BlockIdLt<'_>, BlockId>(BlockIdLt::new(db, self)) }
+    }
+}
+impl hir_expand::Lookup for BlockId {
+    type Database = dyn DefDatabase;
+    type Data = BlockLoc;
+    fn lookup(&self, db: &Self::Database) -> Self::Data {
+        self.loc(db)
+    }
+}
 
 /// A `ModuleId` that is always a crate's root module.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -338,6 +426,18 @@ impl CrateRootModuleId {
     }
 }
 
+impl HasModule for CrateRootModuleId {
+    #[inline]
+    fn module(&self, _db: &dyn DefDatabase) -> ModuleId {
+        ModuleId { krate: self.krate, block: None, local_id: DefMap::ROOT }
+    }
+
+    #[inline]
+    fn krate(&self, _db: &dyn DefDatabase) -> Crate {
+        self.krate
+    }
+}
+
 impl PartialEq<ModuleId> for CrateRootModuleId {
     fn eq(&self, other: &ModuleId) -> bool {
         other.block.is_none() && other.local_id == DefMap::ROOT && self.krate == other.krate
@@ -466,11 +566,19 @@ impl ModuleId {
     }
 }
 
+impl HasModule for ModuleId {
+    #[inline]
+    fn module(&self, _db: &dyn DefDatabase) -> ModuleId {
+        *self
+    }
+}
+
 /// An ID of a module, **local** to a `DefMap`.
 pub type LocalModuleId = Idx<nameres::ModuleData>;
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct FieldId {
+    // FIXME: Store this as an erased `salsa::Id` to save space
     pub parent: VariantId,
     pub local_id: LocalFieldId,
 }
@@ -486,6 +594,7 @@ pub struct TupleFieldId {
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
 pub struct TypeOrConstParamId {
+    // FIXME: Store this as an erased `salsa::Id` to save space
     pub parent: GenericDefId,
     pub local_id: LocalTypeOrConstParamId,
 }
@@ -544,6 +653,7 @@ impl From<ConstParamId> for TypeOrConstParamId {
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct LifetimeParamId {
+    // FIXME: Store this as an erased `salsa::Id` to save space
     pub parent: GenericDefId,
     pub local_id: LocalLifetimeParamId,
 }
@@ -642,15 +752,10 @@ impl GeneralConstId {
     pub fn name(self, db: &dyn DefDatabase) -> String {
         match self {
             GeneralConstId::StaticId(it) => {
-                let loc = it.lookup(db);
-                let tree = loc.item_tree_id().item_tree(db);
-                let name = tree[loc.id.value].name.display(db, Edition::CURRENT);
-                name.to_string()
+                db.static_signature(it).name.display(db, Edition::CURRENT).to_string()
             }
             GeneralConstId::ConstId(const_id) => {
-                let loc = const_id.lookup(db);
-                let tree = loc.item_tree_id().item_tree(db);
-                tree[loc.id.value].name.as_ref().map_or_else(
+                db.const_signature(const_id).name.as_ref().map_or_else(
                     || "_".to_owned(),
                     |name| name.display(db, Edition::CURRENT).to_string(),
                 )
@@ -692,7 +797,7 @@ impl DefWithBodyId {
     }
 }
 
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, salsa_macros::Supertype)]
 pub enum AssocItemId {
     FunctionId(FunctionId),
     ConstId(ConstId),
@@ -768,8 +873,8 @@ impl GenericDefId {
             GenericDefId::TraitId(it) => file_id_and_params_of_item_loc(db, it),
             GenericDefId::TraitAliasId(it) => file_id_and_params_of_item_loc(db, it),
             GenericDefId::ImplId(it) => file_id_and_params_of_item_loc(db, it),
-            GenericDefId::ConstId(it) => (it.lookup(db).id.file_id(), None),
-            GenericDefId::StaticId(it) => (it.lookup(db).id.file_id(), None),
+            GenericDefId::ConstId(it) => (it.lookup(db).id.file_id, None),
+            GenericDefId::StaticId(it) => (it.lookup(db).id.file_id, None),
         }
     }
 
@@ -935,9 +1040,9 @@ impl VariantId {
 
     pub fn file_id(self, db: &dyn DefDatabase) -> HirFileId {
         match self {
-            VariantId::EnumVariantId(it) => it.lookup(db).id.file_id(),
-            VariantId::StructId(it) => it.lookup(db).id.file_id(),
-            VariantId::UnionId(it) => it.lookup(db).id.file_id(),
+            VariantId::EnumVariantId(it) => it.lookup(db).id.file_id,
+            VariantId::StructId(it) => it.lookup(db).id.file_id,
+            VariantId::UnionId(it) => it.lookup(db).id.file_id,
         }
     }
 
@@ -977,7 +1082,7 @@ pub trait HasModule {
 
 impl<N, ItemId> HasModule for ItemId
 where
-    N: ItemTreeNode,
+    N: AstIdNode,
     ItemId: Lookup<Database = dyn DefDatabase, Data = ItemLoc<N>> + Copy,
 {
     #[inline]
@@ -1003,7 +1108,7 @@ where
 #[inline]
 fn module_for_assoc_item_loc<'db>(
     db: &(dyn 'db + DefDatabase),
-    id: impl Lookup<Database = dyn DefDatabase, Data = AssocItemLoc<impl ItemTreeNode>>,
+    id: impl Lookup<Database = dyn DefDatabase, Data = AssocItemLoc<impl AstIdNode>>,
 ) -> ModuleId {
     id.lookup(db).container.module(db)
 }
@@ -1245,7 +1350,7 @@ pub struct SyntheticSyntax;
 // Crate authors can opt their type out of completions in some cases.
 // This is done with the `#[rust_analyzer::completions(...)]` attribute.
 //
-// All completeable things support `#[rust_analyzer::completions(ignore_flyimport)]`,
+// All completable things support `#[rust_analyzer::completions(ignore_flyimport)]`,
 // which causes the thing to get excluded from flyimport completion. It will still
 // be completed when in scope. This is analogous to the setting `rust-analyzer.completion.autoimport.exclude`
 // with `"type": "always"`.
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
index 38fc4b3d118..c6d901ec93b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
@@ -35,9 +35,9 @@ macro_rules! f {
     };
 }
 
-struct#0:1@58..64#14336# MyTraitMap2#0:2@31..42#ROOT2024# {#0:1@72..73#14336#
-    map#0:1@86..89#14336#:#0:1@89..90#14336# #0:1@89..90#14336#::#0:1@91..93#14336#std#0:1@93..96#14336#::#0:1@96..98#14336#collections#0:1@98..109#14336#::#0:1@109..111#14336#HashSet#0:1@111..118#14336#<#0:1@118..119#14336#(#0:1@119..120#14336#)#0:1@120..121#14336#>#0:1@121..122#14336#,#0:1@122..123#14336#
-}#0:1@132..133#14336#
+struct#0:MacroRules[8C8E, 0]@58..64#14336# MyTraitMap2#0:MacroCall[D499, 0]@31..42#ROOT2024# {#0:MacroRules[8C8E, 0]@72..73#14336#
+    map#0:MacroRules[8C8E, 0]@86..89#14336#:#0:MacroRules[8C8E, 0]@89..90#14336# #0:MacroRules[8C8E, 0]@89..90#14336#::#0:MacroRules[8C8E, 0]@91..93#14336#std#0:MacroRules[8C8E, 0]@93..96#14336#::#0:MacroRules[8C8E, 0]@96..98#14336#collections#0:MacroRules[8C8E, 0]@98..109#14336#::#0:MacroRules[8C8E, 0]@109..111#14336#HashSet#0:MacroRules[8C8E, 0]@111..118#14336#<#0:MacroRules[8C8E, 0]@118..119#14336#(#0:MacroRules[8C8E, 0]@119..120#14336#)#0:MacroRules[8C8E, 0]@120..121#14336#>#0:MacroRules[8C8E, 0]@121..122#14336#,#0:MacroRules[8C8E, 0]@122..123#14336#
+}#0:MacroRules[8C8E, 0]@132..133#14336#
 "#]],
     );
 }
@@ -75,12 +75,12 @@ macro_rules! f {
     };
 }
 
-fn#0:2@30..32#ROOT2024# main#0:2@33..37#ROOT2024#(#0:2@37..38#ROOT2024#)#0:2@38..39#ROOT2024# {#0:2@40..41#ROOT2024#
-    1#0:2@50..51#ROOT2024#;#0:2@51..52#ROOT2024#
-    1.0#0:2@61..64#ROOT2024#;#0:2@64..65#ROOT2024#
-    (#0:2@74..75#ROOT2024#(#0:2@75..76#ROOT2024#1#0:2@76..77#ROOT2024#,#0:2@77..78#ROOT2024# )#0:2@78..79#ROOT2024#,#0:2@79..80#ROOT2024# )#0:2@80..81#ROOT2024#.#0:2@81..82#ROOT2024#0#0:2@82..85#ROOT2024#.#0:2@82..85#ROOT2024#0#0:2@82..85#ROOT2024#;#0:2@85..86#ROOT2024#
-    let#0:2@95..98#ROOT2024# x#0:2@99..100#ROOT2024# =#0:2@101..102#ROOT2024# 1#0:2@103..104#ROOT2024#;#0:2@104..105#ROOT2024#
-}#0:2@110..111#ROOT2024#
+fn#0:MacroCall[D499, 0]@30..32#ROOT2024# main#0:MacroCall[D499, 0]@33..37#ROOT2024#(#0:MacroCall[D499, 0]@37..38#ROOT2024#)#0:MacroCall[D499, 0]@38..39#ROOT2024# {#0:MacroCall[D499, 0]@40..41#ROOT2024#
+    1#0:MacroCall[D499, 0]@50..51#ROOT2024#;#0:MacroCall[D499, 0]@51..52#ROOT2024#
+    1.0#0:MacroCall[D499, 0]@61..64#ROOT2024#;#0:MacroCall[D499, 0]@64..65#ROOT2024#
+    (#0:MacroCall[D499, 0]@74..75#ROOT2024#(#0:MacroCall[D499, 0]@75..76#ROOT2024#1#0:MacroCall[D499, 0]@76..77#ROOT2024#,#0:MacroCall[D499, 0]@77..78#ROOT2024# )#0:MacroCall[D499, 0]@78..79#ROOT2024#,#0:MacroCall[D499, 0]@79..80#ROOT2024# )#0:MacroCall[D499, 0]@80..81#ROOT2024#.#0:MacroCall[D499, 0]@81..82#ROOT2024#0#0:MacroCall[D499, 0]@82..85#ROOT2024#.#0:MacroCall[D499, 0]@82..85#ROOT2024#0#0:MacroCall[D499, 0]@82..85#ROOT2024#;#0:MacroCall[D499, 0]@85..86#ROOT2024#
+    let#0:MacroCall[D499, 0]@95..98#ROOT2024# x#0:MacroCall[D499, 0]@99..100#ROOT2024# =#0:MacroCall[D499, 0]@101..102#ROOT2024# 1#0:MacroCall[D499, 0]@103..104#ROOT2024#;#0:MacroCall[D499, 0]@104..105#ROOT2024#
+}#0:MacroCall[D499, 0]@110..111#ROOT2024#
 
 
 "#]],
@@ -171,7 +171,7 @@ fn main(foo: ()) {
     }
 
     fn main(foo: ()) {
-        /* error: unresolved macro unresolved */"helloworld!"#0:3@236..321#ROOT2024#;
+        /* error: unresolved macro unresolved */"helloworld!"#0:Fn[B9C7, 0]@236..321#ROOT2024#;
     }
 }
 
@@ -197,7 +197,7 @@ macro_rules! mk_struct {
 #[macro_use]
 mod foo;
 
-struct#1:1@59..65#14336# Foo#0:2@32..35#ROOT2024#(#1:1@70..71#14336#u32#0:2@41..44#ROOT2024#)#1:1@74..75#14336#;#1:1@75..76#14336#
+struct#1:MacroRules[E572, 0]@59..65#14336# Foo#0:MacroCall[BDD3, 0]@32..35#ROOT2024#(#1:MacroRules[E572, 0]@70..71#14336#u32#0:MacroCall[BDD3, 0]@41..44#ROOT2024#)#1:MacroRules[E572, 0]@74..75#14336#;#1:MacroRules[E572, 0]@75..76#14336#
 "#]],
     );
 }
@@ -2029,3 +2029,25 @@ fn f() {
     "#]],
     );
 }
+
+#[test]
+fn lifetime_repeat() {
+    check(
+        r#"
+macro_rules! m {
+    ($($x:expr)'a*) => (stringify!($($x)'b*));
+}
+fn f() {
+    let _ = m!(0 'a 1 'a 2);
+}
+    "#,
+        expect![[r#"
+macro_rules! m {
+    ($($x:expr)'a*) => (stringify!($($x)'b*));
+}
+fn f() {
+    let _ = stringify!(0 'b 1 'b 2);
+}
+    "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs
index 2d289b76833..2c94f0e8d09 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/meta_syntax.rs
@@ -13,6 +13,8 @@ macro_rules! m {
     ($(x),*) => ();
     ($(x)_*) => ();
     ($(x)i*) => ();
+    ($(x)'a*) => ();
+    ($(x)'_*) => ();
     ($($i:ident)*) => ($_);
     ($($true:ident)*) => ($true);
     ($($false:ident)*) => ($false);
@@ -28,6 +30,8 @@ macro_rules! m {
     ($(x),*) => ();
     ($(x)_*) => ();
     ($(x)i*) => ();
+    ($(x)'a*) => ();
+    ($(x)'_*) => ();
     ($($i:ident)*) => ($_);
     ($($true:ident)*) => ($true);
     ($($false:ident)*) => ($false);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
index 2cc3ca8c752..e2022c7967d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
@@ -784,7 +784,7 @@ macro_rules! delegate_impl {
         }
     }
 }
-impl <> Data for &'amut G where G: Data {}
+impl <> Data for &'a mut G where G: Data {}
 "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
index dc4334ee081..1c69b37f164 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -14,7 +14,7 @@ mod builtin_fn_macro;
 mod mbe;
 mod proc_macros;
 
-use std::{iter, ops::Range, sync};
+use std::{any::TypeId, iter, ops::Range, sync};
 
 use base_db::RootQueryDb;
 use expect_test::Expect;
@@ -302,14 +302,15 @@ fn pretty_print_macro_expansion(
             (_, T!['{']) => " ",
             (T![;] | T!['{'] | T!['}'], _) => "\n",
             (_, T!['}']) => "\n",
-            (IDENT | LIFETIME_IDENT, IDENT | LIFETIME_IDENT) => " ",
-            _ if prev_kind.is_keyword(Edition::CURRENT)
-                && curr_kind.is_keyword(Edition::CURRENT) =>
+            _ if (prev_kind.is_any_identifier()
+                || prev_kind == LIFETIME_IDENT
+                || prev_kind.is_literal())
+                && (curr_kind.is_any_identifier()
+                    || curr_kind == LIFETIME_IDENT
+                    || curr_kind.is_literal()) =>
             {
                 " "
             }
-            (IDENT, _) if curr_kind.is_keyword(Edition::CURRENT) => " ",
-            (_, IDENT) if prev_kind.is_keyword(Edition::CURRENT) => " ",
             (T![>], IDENT) => " ",
             (T![>], _) if curr_kind.is_keyword(Edition::CURRENT) => " ",
             (T![->], _) | (_, T![->]) => " ",
@@ -380,4 +381,8 @@ impl ProcMacroExpander for IdentityWhenValidProcMacroExpander {
             panic!("got invalid macro input: {:?}", parse.errors());
         }
     }
+
+    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
+        other.type_id() == TypeId::of::<Self>()
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
index b2e1adc3650..d5ae6f8d885 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
@@ -181,9 +181,9 @@ fn foo(&self) {
     self.0. 1;
 }
 
-fn#0:1@45..47#ROOT2024# foo#0:1@48..51#ROOT2024#(#0:1@51..52#ROOT2024#&#0:1@52..53#ROOT2024#self#0:1@53..57#ROOT2024# )#0:1@57..58#ROOT2024# {#0:1@59..60#ROOT2024#
-    self#0:1@65..69#ROOT2024# .#0:1@69..70#ROOT2024#0#0:1@70..71#ROOT2024#.#0:1@71..72#ROOT2024#1#0:1@73..74#ROOT2024#;#0:1@74..75#ROOT2024#
-}#0:1@76..77#ROOT2024#"#]],
+fn#0:Fn[4D85, 0]@45..47#ROOT2024# foo#0:Fn[4D85, 0]@48..51#ROOT2024#(#0:Fn[4D85, 0]@51..52#ROOT2024#&#0:Fn[4D85, 0]@52..53#ROOT2024#self#0:Fn[4D85, 0]@53..57#ROOT2024# )#0:Fn[4D85, 0]@57..58#ROOT2024# {#0:Fn[4D85, 0]@59..60#ROOT2024#
+    self#0:Fn[4D85, 0]@65..69#ROOT2024# .#0:Fn[4D85, 0]@69..70#ROOT2024#0#0:Fn[4D85, 0]@70..71#ROOT2024#.#0:Fn[4D85, 0]@71..72#ROOT2024#1#0:Fn[4D85, 0]@73..74#ROOT2024#;#0:Fn[4D85, 0]@74..75#ROOT2024#
+}#0:Fn[4D85, 0]@76..77#ROOT2024#"#]],
     );
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
index f337f83156a..0837308d5b6 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
@@ -62,8 +62,8 @@ use std::ops::Deref;
 
 use base_db::Crate;
 use hir_expand::{
-    EditionedFileId, ErasedAstId, HirFileId, InFile, MacroCallId, MacroDefId, mod_path::ModPath,
-    name::Name, proc_macro::ProcMacroKind,
+    EditionedFileId, ErasedAstId, HirFileId, InFile, MacroCallId, mod_path::ModPath, name::Name,
+    proc_macro::ProcMacroKind,
 };
 use intern::Symbol;
 use itertools::Itertools;
@@ -80,7 +80,7 @@ use crate::{
     LocalModuleId, Lookup, MacroExpander, MacroId, ModuleId, ProcMacroId, UseId,
     db::DefDatabase,
     item_scope::{BuiltinShadowMode, ItemScope},
-    item_tree::{ItemTreeId, Mod, TreeId},
+    item_tree::TreeId,
     nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode},
     per_ns::PerNs,
     visibility::{Visibility, VisibilityExplicitness},
@@ -171,12 +171,10 @@ pub struct DefMap {
     /// ExternCrateId being None implies it being imported from the general prelude import.
     macro_use_prelude: FxHashMap<Name, (MacroId, Option<ExternCrateId>)>,
 
-    // FIXME: AstId's are fairly unstable
     /// Tracks which custom derives are in scope for an item, to allow resolution of derive helper
     /// attributes.
     // FIXME: Figure out a better way for the IDE layer to resolve these?
     derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<(Name, MacroId, MacroCallId)>>,
-    // FIXME: AstId's are fairly unstable
     /// A mapping from [`hir_expand::MacroDefId`] to [`crate::MacroId`].
     pub macro_def_to_macro_id: FxHashMap<ErasedAstId, MacroId>,
 
@@ -191,7 +189,7 @@ pub struct DefMap {
 #[derive(Clone, Debug, PartialEq, Eq)]
 struct DefMapCrateData {
     /// Side table for resolving derive helpers.
-    exported_derives: FxHashMap<MacroDefId, Box<[Name]>>,
+    exported_derives: FxHashMap<MacroId, Box<[Name]>>,
     fn_proc_macro_mapping: FxHashMap<FunctionId, ProcMacroId>,
 
     /// Custom attributes registered with `#![register_attr]`.
@@ -291,11 +289,11 @@ pub enum ModuleOrigin {
     File {
         is_mod_rs: bool,
         declaration: FileAstId<ast::Module>,
-        declaration_tree_id: ItemTreeId<Mod>,
+        declaration_tree_id: TreeId,
         definition: EditionedFileId,
     },
     Inline {
-        definition_tree_id: ItemTreeId<Mod>,
+        definition_tree_id: TreeId,
         definition: FileAstId<ast::Module>,
     },
     /// Pseudo-module introduced by a block scope (contains only inner items).
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs
index 86225d33b4e..7aaa918d1c9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs
@@ -1,14 +1,28 @@
 //! Expansion of associated items
 
-use hir_expand::{AstId, InFile, Intern, Lookup, MacroCallKind, MacroDefKind, name::Name};
-use syntax::ast;
+use std::mem;
+
+use cfg::CfgOptions;
+use hir_expand::{
+    AstId, ExpandTo, HirFileId, InFile, Intern, Lookup, MacroCallKind, MacroDefKind,
+    mod_path::ModPath,
+    name::{AsName, Name},
+    span_map::SpanMap,
+};
+use intern::Interned;
+use span::AstIdMap;
+use syntax::{
+    AstNode,
+    ast::{self, HasModuleItem, HasName},
+};
+use thin_vec::ThinVec;
 use triomphe::Arc;
 
 use crate::{
     AssocItemId, AstIdWithPath, ConstLoc, FunctionId, FunctionLoc, ImplId, ItemContainerId,
     ItemLoc, MacroCallId, ModuleId, TraitId, TypeAliasId, TypeAliasLoc,
+    attr::Attrs,
     db::DefDatabase,
-    item_tree::{AssocItem, ItemTree, ItemTreeId, MacroCall, ModItem, TreeId},
     macro_call_as_call_id,
     nameres::{
         DefMap, LocalDefMap, MacroSubNs,
@@ -20,9 +34,8 @@ use crate::{
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct TraitItems {
     pub items: Box<[(Name, AssocItemId)]>,
-    // box it as the vec is usually empty anyways
-    // FIXME: AstIds are rather unstable...
-    pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
+    // `ThinVec` as the vec is usually empty anyways
+    pub macro_calls: ThinVec<(AstId<ast::Item>, MacroCallId)>,
 }
 
 impl TraitItems {
@@ -35,12 +48,12 @@ impl TraitItems {
         db: &dyn DefDatabase,
         tr: TraitId,
     ) -> (Arc<TraitItems>, DefDiagnostics) {
-        let ItemLoc { container: module_id, id: tree_id } = tr.lookup(db);
+        let ItemLoc { container: module_id, id: ast_id } = tr.lookup(db);
 
-        let collector = AssocItemCollector::new(db, module_id, ItemContainerId::TraitId(tr));
-        let item_tree = tree_id.item_tree(db);
-        let (items, macro_calls, diagnostics) =
-            collector.collect(&item_tree, tree_id.tree_id(), &item_tree[tree_id.value].items);
+        let collector =
+            AssocItemCollector::new(db, module_id, ItemContainerId::TraitId(tr), ast_id.file_id);
+        let source = ast_id.with_value(collector.ast_id_map.get(ast_id.value)).to_node(db);
+        let (items, macro_calls, diagnostics) = collector.collect(source.assoc_item_list());
 
         (Arc::new(TraitItems { macro_calls, items }), DefDiagnostics::new(diagnostics))
     }
@@ -76,41 +89,36 @@ impl TraitItems {
     }
 
     pub fn macro_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
-        self.macro_calls.iter().flat_map(|it| it.iter()).copied()
+        self.macro_calls.iter().copied()
     }
 }
 
 #[derive(Debug, PartialEq, Eq)]
 pub struct ImplItems {
     pub items: Box<[(Name, AssocItemId)]>,
-    // box it as the vec is usually empty anyways
-    // FIXME: AstIds are rather unstable...
-    pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
+    // `ThinVec` as the vec is usually empty anyways
+    pub macro_calls: ThinVec<(AstId<ast::Item>, MacroCallId)>,
 }
 
+#[salsa::tracked]
 impl ImplItems {
-    #[inline]
-    pub(crate) fn impl_items_query(db: &dyn DefDatabase, id: ImplId) -> Arc<ImplItems> {
-        db.impl_items_with_diagnostics(id).0
-    }
-
-    pub(crate) fn impl_items_with_diagnostics_query(
-        db: &dyn DefDatabase,
-        id: ImplId,
-    ) -> (Arc<ImplItems>, DefDiagnostics) {
+    #[salsa::tracked(returns(ref))]
+    pub fn of(db: &dyn DefDatabase, id: ImplId) -> (ImplItems, DefDiagnostics) {
         let _p = tracing::info_span!("impl_items_with_diagnostics_query").entered();
-        let ItemLoc { container: module_id, id: tree_id } = id.lookup(db);
+        let ItemLoc { container: module_id, id: ast_id } = id.lookup(db);
 
-        let collector = AssocItemCollector::new(db, module_id, ItemContainerId::ImplId(id));
-        let item_tree = tree_id.item_tree(db);
-        let (items, macro_calls, diagnostics) =
-            collector.collect(&item_tree, tree_id.tree_id(), &item_tree[tree_id.value].items);
+        let collector =
+            AssocItemCollector::new(db, module_id, ItemContainerId::ImplId(id), ast_id.file_id);
+        let source = ast_id.with_value(collector.ast_id_map.get(ast_id.value)).to_node(db);
+        let (items, macro_calls, diagnostics) = collector.collect(source.assoc_item_list());
 
-        (Arc::new(ImplItems { items, macro_calls }), DefDiagnostics::new(diagnostics))
+        (ImplItems { items, macro_calls }, DefDiagnostics::new(diagnostics))
     }
+}
 
+impl ImplItems {
     pub fn macro_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
-        self.macro_calls.iter().flat_map(|it| it.iter()).copied()
+        self.macro_calls.iter().copied()
     }
 }
 
@@ -119,67 +127,73 @@ struct AssocItemCollector<'a> {
     module_id: ModuleId,
     def_map: &'a DefMap,
     local_def_map: &'a LocalDefMap,
+    ast_id_map: Arc<AstIdMap>,
+    span_map: SpanMap,
+    cfg_options: &'a CfgOptions,
+    file_id: HirFileId,
     diagnostics: Vec<DefDiagnostic>,
     container: ItemContainerId,
 
     depth: usize,
     items: Vec<(Name, AssocItemId)>,
-    macro_calls: Vec<(AstId<ast::Item>, MacroCallId)>,
+    macro_calls: ThinVec<(AstId<ast::Item>, MacroCallId)>,
 }
 
 impl<'a> AssocItemCollector<'a> {
-    fn new(db: &'a dyn DefDatabase, module_id: ModuleId, container: ItemContainerId) -> Self {
+    fn new(
+        db: &'a dyn DefDatabase,
+        module_id: ModuleId,
+        container: ItemContainerId,
+        file_id: HirFileId,
+    ) -> Self {
         let (def_map, local_def_map) = module_id.local_def_map(db);
         Self {
             db,
             module_id,
             def_map,
             local_def_map,
+            ast_id_map: db.ast_id_map(file_id),
+            span_map: db.span_map(file_id),
+            cfg_options: module_id.krate.cfg_options(db),
+            file_id,
             container,
             items: Vec::new(),
 
             depth: 0,
-            macro_calls: Vec::new(),
+            macro_calls: ThinVec::new(),
             diagnostics: Vec::new(),
         }
     }
 
     fn collect(
         mut self,
-        item_tree: &ItemTree,
-        tree_id: TreeId,
-        assoc_items: &[AssocItem],
-    ) -> (
-        Box<[(Name, AssocItemId)]>,
-        Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
-        Vec<DefDiagnostic>,
-    ) {
-        self.items.reserve(assoc_items.len());
-        for &item in assoc_items {
-            self.collect_item(item_tree, tree_id, item);
+        item_list: Option<ast::AssocItemList>,
+    ) -> (Box<[(Name, AssocItemId)]>, ThinVec<(AstId<ast::Item>, MacroCallId)>, Vec<DefDiagnostic>)
+    {
+        if let Some(item_list) = item_list {
+            for item in item_list.assoc_items() {
+                self.collect_item(item);
+            }
         }
-        (
-            self.items.into_boxed_slice(),
-            if self.macro_calls.is_empty() { None } else { Some(Box::new(self.macro_calls)) },
-            self.diagnostics,
-        )
+        self.macro_calls.shrink_to_fit();
+        (self.items.into_boxed_slice(), self.macro_calls, self.diagnostics)
     }
 
-    fn collect_item(&mut self, item_tree: &ItemTree, tree_id: TreeId, item: AssocItem) {
-        let attrs = item_tree.attrs(self.db, self.module_id.krate, ModItem::from(item).into());
-        if !attrs.is_cfg_enabled(self.module_id.krate.cfg_options(self.db)) {
+    fn collect_item(&mut self, item: ast::AssocItem) {
+        let ast_id = self.ast_id_map.ast_id(&item);
+        let attrs = Attrs::new(self.db, &item, self.span_map.as_ref(), self.cfg_options);
+        if let Err(cfg) = attrs.is_cfg_enabled(self.cfg_options) {
             self.diagnostics.push(DefDiagnostic::unconfigured_code(
                 self.module_id.local_id,
-                tree_id,
-                ModItem::from(item).into(),
-                attrs.cfg().unwrap(),
-                self.module_id.krate.cfg_options(self.db).clone(),
+                InFile::new(self.file_id, ast_id.erase()),
+                cfg,
+                self.cfg_options.clone(),
             ));
             return;
         }
+        let ast_id = InFile::new(self.file_id, ast_id.upcast());
 
         'attrs: for attr in &*attrs {
-            let ast_id = AstId::new(tree_id.file_id(), item.ast_id(item_tree).upcast());
             let ast_id_with_path = AstIdWithPath { path: attr.path.clone(), ast_id };
 
             match self.def_map.resolve_attr_macro(
@@ -223,34 +237,51 @@ impl<'a> AssocItemCollector<'a> {
             }
         }
 
-        self.record_item(item_tree, tree_id, item);
+        self.record_item(item);
     }
 
-    fn record_item(&mut self, item_tree: &ItemTree, tree_id: TreeId, item: AssocItem) {
+    fn record_item(&mut self, item: ast::AssocItem) {
         match item {
-            AssocItem::Function(id) => {
-                let item = &item_tree[id];
-                let def =
-                    FunctionLoc { container: self.container, id: ItemTreeId::new(tree_id, id) }
-                        .intern(self.db);
-                self.items.push((item.name.clone(), def.into()));
+            ast::AssocItem::Fn(function) => {
+                let Some(name) = function.name() else { return };
+                let ast_id = self.ast_id_map.ast_id(&function);
+                let def = FunctionLoc {
+                    container: self.container,
+                    id: InFile::new(self.file_id, ast_id),
+                }
+                .intern(self.db);
+                self.items.push((name.as_name(), def.into()));
             }
-            AssocItem::TypeAlias(id) => {
-                let item = &item_tree[id];
+            ast::AssocItem::TypeAlias(type_alias) => {
+                let Some(name) = type_alias.name() else { return };
+                let ast_id = self.ast_id_map.ast_id(&type_alias);
+                let def = TypeAliasLoc {
+                    container: self.container,
+                    id: InFile::new(self.file_id, ast_id),
+                }
+                .intern(self.db);
+                self.items.push((name.as_name(), def.into()));
+            }
+            ast::AssocItem::Const(konst) => {
+                let Some(name) = konst.name() else { return };
+                let ast_id = self.ast_id_map.ast_id(&konst);
                 let def =
-                    TypeAliasLoc { container: self.container, id: ItemTreeId::new(tree_id, id) }
+                    ConstLoc { container: self.container, id: InFile::new(self.file_id, ast_id) }
                         .intern(self.db);
-                self.items.push((item.name.clone(), def.into()));
-            }
-            AssocItem::Const(id) => {
-                let item = &item_tree[id];
-                let Some(name) = item.name.clone() else { return };
-                let def = ConstLoc { container: self.container, id: ItemTreeId::new(tree_id, id) }
-                    .intern(self.db);
-                self.items.push((name, def.into()));
+                self.items.push((name.as_name(), def.into()));
             }
-            AssocItem::MacroCall(call) => {
-                let MacroCall { ast_id, expand_to, ctxt, ref path } = item_tree[call];
+            ast::AssocItem::MacroCall(call) => {
+                let ast_id = self.ast_id_map.ast_id(&call);
+                let ast_id = InFile::new(self.file_id, ast_id);
+                let Some(path) = call.path() else { return };
+                let range = path.syntax().text_range();
+                let Some(path) = ModPath::from_src(self.db, path, &mut |range| {
+                    self.span_map.span_for_range(range).ctx
+                }) else {
+                    return;
+                };
+                let path = Interned::new(path);
+                let ctxt = self.span_map.span_for_range(range).ctx;
 
                 let resolver = |path: &_| {
                     self.def_map
@@ -268,10 +299,10 @@ impl<'a> AssocItemCollector<'a> {
                 };
                 match macro_call_as_call_id(
                     self.db,
-                    InFile::new(tree_id.file_id(), ast_id),
-                    path,
+                    ast_id,
+                    &path,
                     ctxt,
-                    expand_to,
+                    ExpandTo::Items,
                     self.module_id.krate(),
                     resolver,
                     &mut |ptr, call_id| {
@@ -281,8 +312,7 @@ impl<'a> AssocItemCollector<'a> {
                     // FIXME: Expansion error?
                     Ok(call_id) => match call_id.value {
                         Some(call_id) => {
-                            self.macro_calls
-                                .push((InFile::new(tree_id.file_id(), ast_id.upcast()), call_id));
+                            self.macro_calls.push((ast_id.upcast(), call_id));
                             self.collect_macro_items(call_id);
                         }
                         None => (),
@@ -291,11 +321,11 @@ impl<'a> AssocItemCollector<'a> {
                         self.diagnostics.push(DefDiagnostic::unresolved_macro_call(
                             self.module_id.local_id,
                             MacroCallKind::FnLike {
-                                ast_id: InFile::new(tree_id.file_id(), ast_id),
-                                expand_to,
+                                ast_id,
+                                expand_to: ExpandTo::Items,
                                 eager: None,
                             },
-                            Clone::clone(path),
+                            (*path).clone(),
                         ));
                     }
                 }
@@ -308,13 +338,29 @@ impl<'a> AssocItemCollector<'a> {
             tracing::warn!("macro expansion is too deep");
             return;
         }
-        let tree_id = TreeId::new(macro_call_id.into(), None);
-        let item_tree = self.db.file_item_tree(macro_call_id.into());
 
+        let (syntax, span_map) = self.db.parse_macro_expansion(macro_call_id).value;
+        let old_file_id = mem::replace(&mut self.file_id, macro_call_id.into());
+        let old_ast_id_map = mem::replace(&mut self.ast_id_map, self.db.ast_id_map(self.file_id));
+        let old_span_map = mem::replace(&mut self.span_map, SpanMap::ExpansionSpanMap(span_map));
         self.depth += 1;
-        for item in item_tree.top_level_items().iter().filter_map(ModItem::as_assoc_item) {
-            self.collect_item(&item_tree, tree_id, item);
+
+        let items = ast::MacroItems::cast(syntax.syntax_node()).expect("not `MacroItems`");
+        for item in items.items() {
+            let item = match item {
+                ast::Item::Fn(it) => ast::AssocItem::from(it),
+                ast::Item::Const(it) => it.into(),
+                ast::Item::TypeAlias(it) => it.into(),
+                ast::Item::MacroCall(it) => it.into(),
+                // FIXME: Should error on disallowed item kinds.
+                _ => continue,
+            };
+            self.collect_item(item);
         }
+
         self.depth -= 1;
+        self.file_id = old_file_id;
+        self.ast_id_map = old_ast_id_map;
+        self.span_map = old_span_map;
     }
 }
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 350c97c3982..78fdc275606 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
@@ -9,8 +9,8 @@ use base_db::{BuiltDependency, Crate, CrateOrigin, LangCrateOrigin};
 use cfg::{CfgAtom, CfgExpr, CfgOptions};
 use either::Either;
 use hir_expand::{
-    EditionedFileId, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId,
-    MacroDefKind,
+    EditionedFileId, ErasedAstId, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind,
+    MacroDefId, MacroDefKind,
     attrs::{Attr, AttrId},
     builtin::{find_builtin_attr, find_builtin_derive, find_builtin_macro},
     mod_path::{ModPath, PathKind},
@@ -35,9 +35,8 @@ use crate::{
     db::DefDatabase,
     item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports},
     item_tree::{
-        self, AttrOwner, FieldsShape, FileItemTreeId, ImportAlias, ImportKind, ItemTree,
-        ItemTreeId, ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId,
-        UseTreeKind,
+        self, FieldsShape, ImportAlias, ImportKind, ItemTree, ItemTreeAstId, Macro2, MacroCall,
+        MacroRules, Mod, ModItemId, ModKind, TreeId,
     },
     macro_call_as_call_id,
     nameres::{
@@ -154,14 +153,14 @@ struct Import {
 impl Import {
     fn from_use(
         tree: &ItemTree,
-        item_tree_id: ItemTreeId<item_tree::Use>,
+        item: FileAstId<ast::Use>,
         id: UseId,
         is_prelude: bool,
         mut cb: impl FnMut(Self),
     ) {
-        let it = &tree[item_tree_id.value];
+        let it = &tree[item];
         let visibility = &tree[it.visibility];
-        it.use_tree.expand(|idx, path, kind, alias| {
+        it.expand(|idx, path, kind, alias| {
             cb(Self {
                 path,
                 alias,
@@ -181,15 +180,15 @@ struct ImportDirective {
 }
 
 #[derive(Clone, Debug, Eq, PartialEq)]
-struct MacroDirective {
+struct MacroDirective<'db> {
     module_id: LocalModuleId,
     depth: usize,
-    kind: MacroDirectiveKind,
+    kind: MacroDirectiveKind<'db>,
     container: ItemContainerId,
 }
 
 #[derive(Clone, Debug, Eq, PartialEq)]
-enum MacroDirectiveKind {
+enum MacroDirectiveKind<'db> {
     FnLike {
         ast_id: AstIdWithPath<ast::MacroCall>,
         expand_to: ExpandTo,
@@ -206,30 +205,31 @@ enum MacroDirectiveKind {
     Attr {
         ast_id: AstIdWithPath<ast::Item>,
         attr: Attr,
-        mod_item: ModItem,
+        mod_item: ModItemId,
         /* is this needed? */ tree: TreeId,
+        item_tree: &'db ItemTree,
     },
 }
 
 /// Walks the tree of module recursively
-struct DefCollector<'a> {
-    db: &'a dyn DefDatabase,
+struct DefCollector<'db> {
+    db: &'db dyn DefDatabase,
     def_map: DefMap,
     local_def_map: LocalDefMap,
     /// Set only in case of blocks.
-    crate_local_def_map: Option<&'a LocalDefMap>,
+    crate_local_def_map: Option<&'db LocalDefMap>,
     // The dependencies of the current crate, including optional deps like `test`.
     deps: FxHashMap<Name, BuiltDependency>,
     glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility, GlobId)>>,
     unresolved_imports: Vec<ImportDirective>,
     indeterminate_imports: Vec<(ImportDirective, PerNs)>,
-    unresolved_macros: Vec<MacroDirective>,
+    unresolved_macros: Vec<MacroDirective<'db>>,
     // We'd like to avoid emitting a diagnostics avalanche when some `extern crate` doesn't
     // resolve. When we emit diagnostics for unresolved imports, we only do so if the import
     // doesn't start with an unresolved crate's name.
     unresolved_extern_crates: FxHashSet<Name>,
     mod_dirs: FxHashMap<LocalModuleId, ModDir>,
-    cfg_options: &'a CfgOptions,
+    cfg_options: &'db CfgOptions,
     /// List of procedural macros defined by this crate. This is read from the dynamic library
     /// built by the build system, and is the list of proc-macros we can actually expand. It is
     /// empty when proc-macro support is disabled (in which case we still do name resolution for
@@ -244,10 +244,10 @@ struct DefCollector<'a> {
     /// This also stores the attributes to skip when we resolve derive helpers and non-macro
     /// non-builtin attributes in general.
     // FIXME: There has to be a better way to do this
-    skip_attrs: FxHashMap<InFile<ModItem>, AttrId>,
+    skip_attrs: FxHashMap<InFile<FileAstId<ast::Item>>, AttrId>,
 }
 
-impl DefCollector<'_> {
+impl<'db> DefCollector<'db> {
     fn seed_with_top_level(&mut self) {
         let _p = tracing::info_span!("seed_with_top_level").entered();
 
@@ -355,7 +355,7 @@ impl DefCollector<'_> {
             macro_depth: 0,
             module_id: DefMap::ROOT,
             tree_id: TreeId::new(file_id.into(), None),
-            item_tree: &item_tree,
+            item_tree,
             mod_dir: ModDir::root(),
         }
         .collect_in_top_module(item_tree.top_level_items());
@@ -376,7 +376,7 @@ impl DefCollector<'_> {
                 macro_depth: 0,
                 module_id: DefMap::ROOT,
                 tree_id,
-                item_tree: &item_tree,
+                item_tree,
                 mod_dir: ModDir::root(),
             }
             .collect_in_top_module(item_tree.top_level_items());
@@ -437,9 +437,8 @@ impl DefCollector<'_> {
             // Additionally, while the proc macro entry points must be `pub`, they are not publicly
             // exported in type/value namespace. This function reduces the visibility of all items
             // in the crate root that aren't proc macros.
-            let module_id = self.def_map.module_id(DefMap::ROOT);
             let root = &mut self.def_map.modules[DefMap::ROOT];
-            root.scope.censor_non_proc_macros(module_id);
+            root.scope.censor_non_proc_macros(self.def_map.krate);
         }
     }
 
@@ -459,7 +458,7 @@ impl DefCollector<'_> {
             self.unresolved_macros.iter().enumerate().find_map(|(idx, directive)| match &directive
                 .kind
             {
-                MacroDirectiveKind::Attr { ast_id, mod_item, attr, tree } => {
+                MacroDirectiveKind::Attr { ast_id, mod_item, attr, tree, item_tree } => {
                     self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
                         directive.module_id,
                         MacroCallKind::Attr {
@@ -470,16 +469,22 @@ impl DefCollector<'_> {
                         attr.path().clone(),
                     ));
 
-                    self.skip_attrs.insert(ast_id.ast_id.with_value(*mod_item), attr.id);
+                    self.skip_attrs.insert(ast_id.ast_id.with_value(mod_item.ast_id()), attr.id);
 
-                    Some((idx, directive, *mod_item, *tree))
+                    Some((idx, directive, *mod_item, *tree, *item_tree))
                 }
                 _ => None,
             });
 
         match unresolved_attr {
-            Some((pos, &MacroDirective { module_id, depth, container, .. }, mod_item, tree_id)) => {
-                let item_tree = &tree_id.item_tree(self.db);
+            Some((
+                pos,
+                &MacroDirective { module_id, depth, container, .. },
+                mod_item,
+                tree_id,
+                item_tree,
+            )) => {
+                // FIXME: Remove this clone
                 let mod_dir = self.mod_dirs[&module_id].clone();
                 ModCollector {
                     def_collector: self,
@@ -576,13 +581,7 @@ impl DefCollector<'_> {
     /// use a dummy expander that always errors. This comes with the drawback of macros potentially
     /// going out of sync with what the build system sees (since we resolve using VFS state, but
     /// Cargo builds only on-disk files). We could and probably should add diagnostics for that.
-    fn export_proc_macro(
-        &mut self,
-        def: ProcMacroDef,
-        id: ItemTreeId<item_tree::Function>,
-        ast_id: AstId<ast::Fn>,
-        fn_id: FunctionId,
-    ) {
+    fn export_proc_macro(&mut self, def: ProcMacroDef, ast_id: AstId<ast::Fn>, fn_id: FunctionId) {
         let kind = def.kind.to_basedb_kind();
         let (expander, kind) = match self.proc_macros.iter().find(|(n, _, _)| n == &def.name) {
             Some(_)
@@ -598,7 +597,7 @@ impl DefCollector<'_> {
 
         let proc_macro_id = ProcMacroLoc {
             container: self.def_map.crate_root(),
-            id,
+            id: ast_id,
             expander,
             kind,
             edition: self.def_map.data.edition,
@@ -609,7 +608,7 @@ impl DefCollector<'_> {
         self.define_proc_macro(def.name.clone(), proc_macro_id);
         let crate_data = Arc::get_mut(&mut self.def_map.data).unwrap();
         if let ProcMacroKind::Derive { helpers } = def.kind {
-            crate_data.exported_derives.insert(self.db.macro_def(proc_macro_id.into()), helpers);
+            crate_data.exported_derives.insert(proc_macro_id.into(), helpers);
         }
         crate_data.fn_proc_macro_mapping.insert(fn_id, proc_macro_id);
     }
@@ -887,9 +886,31 @@ impl DefCollector<'_> {
                 let imp = ImportOrExternCrate::Import(ImportId { use_: id, idx: use_tree });
                 tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
 
+                // `extern crate crate_name` things can be re-exported as `pub use crate_name`.
+                // But they cannot be re-exported as `pub use self::crate_name`, `pub use crate::crate_name`
+                // or `pub use ::crate_name`.
+                //
+                // This has been historically allowed, but may be not allowed in future
+                // https://github.com/rust-lang/rust/issues/127909
+                if let Some(def) = def.types.as_mut() {
+                    let is_extern_crate_reimport_without_prefix = || {
+                        let Some(ImportOrExternCrate::ExternCrate(_)) = def.import else {
+                            return false;
+                        };
+                        if kind == ImportKind::Glob {
+                            return false;
+                        }
+                        matches!(import.path.kind, PathKind::Plain | PathKind::SELF)
+                            && import.path.segments().len() < 2
+                    };
+                    if is_extern_crate_reimport_without_prefix() {
+                        def.vis = vis;
+                    }
+                }
+
                 self.update(module_id, &[(name.cloned(), def)], vis, Some(imp));
             }
-            ImportSource { kind: ImportKind::Glob, id, is_prelude, use_tree } => {
+            ImportSource { kind: ImportKind::Glob, id, is_prelude, use_tree, .. } => {
                 tracing::debug!("glob import: {:?}", import);
                 let glob = GlobId { use_: id, idx: use_tree };
                 match def.take_types() {
@@ -973,12 +994,11 @@ impl DefCollector<'_> {
                     Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => {
                         cov_mark::hit!(glob_enum);
                         // glob import from enum => just import all the variants
-                        let resolutions = self
-                            .db
-                            .enum_variants(e)
+                        let resolutions = e
+                            .enum_variants(self.db)
                             .variants
                             .iter()
-                            .map(|&(variant, ref name)| {
+                            .map(|&(variant, ref name, _)| {
                                 let res = PerNs::both(variant.into(), variant.into(), vis, None);
                                 (Some(name.clone()), res)
                             })
@@ -1150,33 +1170,8 @@ impl DefCollector<'_> {
         vis: Visibility,
         def_import_type: Option<ImportOrExternCrate>,
     ) -> bool {
-        // `extern crate crate_name` things can be re-exported as `pub use crate_name`.
-        // But they cannot be re-exported as `pub use self::crate_name`, `pub use crate::crate_name`
-        // or `pub use ::crate_name`.
-        //
-        // This has been historically allowed, but may be not allowed in future
-        // https://github.com/rust-lang/rust/issues/127909
         if let Some(def) = defs.types.as_mut() {
-            let is_extern_crate_reimport_without_prefix = || {
-                let Some(ImportOrExternCrate::ExternCrate(_)) = def.import else {
-                    return false;
-                };
-                let Some(ImportOrExternCrate::Import(id)) = def_import_type else {
-                    return false;
-                };
-                let use_id = id.use_.lookup(self.db).id;
-                let item_tree = use_id.item_tree(self.db);
-                let use_kind = item_tree[use_id.value].use_tree.kind();
-                let UseTreeKind::Single { path, .. } = use_kind else {
-                    return false;
-                };
-                path.segments().len() < 2
-            };
-            if is_extern_crate_reimport_without_prefix() {
-                def.vis = vis;
-            } else {
-                def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis);
-            }
+            def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis);
         }
         if let Some(def) = defs.values.as_mut() {
             def.vis = def.vis.min(vis, &self.def_map).unwrap_or(vis);
@@ -1259,7 +1254,7 @@ impl DefCollector<'_> {
     fn resolve_macros(&mut self) -> ReachedFixedPoint {
         let mut macros = mem::take(&mut self.unresolved_macros);
         let mut resolved = Vec::new();
-        let mut push_resolved = |directive: &MacroDirective, call_id| {
+        let mut push_resolved = |directive: &MacroDirective<'_>, call_id| {
             resolved.push((directive.module_id, directive.depth, directive.container, call_id));
         };
 
@@ -1272,7 +1267,7 @@ impl DefCollector<'_> {
         let mut eager_callback_buffer = vec![];
         let mut res = ReachedFixedPoint::Yes;
         // Retain unresolved macros after this round of resolution.
-        let mut retain = |directive: &MacroDirective| {
+        let mut retain = |directive: &MacroDirective<'db>| {
             let subns = match &directive.kind {
                 MacroDirectiveKind::FnLike { .. } => MacroSubNs::Bang,
                 MacroDirectiveKind::Attr { .. } | MacroDirectiveKind::Derive { .. } => {
@@ -1349,7 +1344,7 @@ impl DefCollector<'_> {
                         // Record its helper attributes.
                         if def_id.krate != self.def_map.krate {
                             let def_map = crate_def_map(self.db, def_id.krate);
-                            if let Some(helpers) = def_map.data.exported_derives.get(&def_id) {
+                            if let Some(helpers) = def_map.data.exported_derives.get(&macro_id) {
                                 self.def_map
                                     .derive_helpers_in_scope
                                     .entry(ast_id.ast_id.map(|it| it.upcast()))
@@ -1367,22 +1362,29 @@ impl DefCollector<'_> {
                         return Resolved::Yes;
                     }
                 }
-                MacroDirectiveKind::Attr { ast_id: file_ast_id, mod_item, attr, tree } => {
+                MacroDirectiveKind::Attr {
+                    ast_id: file_ast_id,
+                    mod_item,
+                    attr,
+                    tree,
+                    item_tree,
+                } => {
                     let &AstIdWithPath { ast_id, ref path } = file_ast_id;
                     let file_id = ast_id.file_id;
 
                     let mut recollect_without = |collector: &mut Self| {
                         // Remove the original directive since we resolved it.
                         let mod_dir = collector.mod_dirs[&directive.module_id].clone();
-                        collector.skip_attrs.insert(InFile::new(file_id, *mod_item), attr.id);
+                        collector
+                            .skip_attrs
+                            .insert(InFile::new(file_id, mod_item.ast_id()), attr.id);
 
-                        let item_tree = tree.item_tree(self.db);
                         ModCollector {
                             def_collector: collector,
                             macro_depth: directive.depth,
                             module_id: directive.module_id,
                             tree_id: *tree,
-                            item_tree: &item_tree,
+                            item_tree,
                             mod_dir,
                         }
                         .collect(&[*mod_item], directive.container);
@@ -1435,11 +1437,10 @@ impl DefCollector<'_> {
                         // normal (as that would just be an identity expansion with extra output)
                         // Instead we treat derive attributes special and apply them separately.
 
-                        let item_tree = tree.item_tree(self.db);
                         let ast_adt_id: FileAstId<ast::Adt> = match *mod_item {
-                            ModItem::Struct(strukt) => item_tree[strukt].ast_id().upcast(),
-                            ModItem::Union(union) => item_tree[union].ast_id().upcast(),
-                            ModItem::Enum(enum_) => item_tree[enum_].ast_id().upcast(),
+                            ModItemId::Struct(ast_id) => ast_id.upcast(),
+                            ModItemId::Union(ast_id) => ast_id.upcast(),
+                            ModItemId::Enum(ast_id) => ast_id.upcast(),
                             _ => {
                                 let diag = DefDiagnostic::invalid_derive_target(
                                     directive.module_id,
@@ -1571,7 +1572,7 @@ impl DefCollector<'_> {
             macro_depth: depth,
             tree_id: TreeId::new(file_id, None),
             module_id,
-            item_tree: &item_tree,
+            item_tree,
             mod_dir,
         }
         .collect(item_tree.top_level_items(), container);
@@ -1672,22 +1673,22 @@ impl DefCollector<'_> {
 }
 
 /// Walks a single module, populating defs, imports and macros
-struct ModCollector<'a, 'b> {
-    def_collector: &'a mut DefCollector<'b>,
+struct ModCollector<'a, 'db> {
+    def_collector: &'a mut DefCollector<'db>,
     macro_depth: usize,
     module_id: LocalModuleId,
     tree_id: TreeId,
-    item_tree: &'a ItemTree,
+    item_tree: &'db ItemTree,
     mod_dir: ModDir,
 }
 
 impl ModCollector<'_, '_> {
-    fn collect_in_top_module(&mut self, items: &[ModItem]) {
+    fn collect_in_top_module(&mut self, items: &[ModItemId]) {
         let module = self.def_collector.def_map.module_id(self.module_id);
         self.collect(items, module.into())
     }
 
-    fn collect(&mut self, items: &[ModItem], container: ItemContainerId) {
+    fn collect(&mut self, items: &[ModItemId], container: ItemContainerId) {
         let krate = self.def_collector.def_map.krate;
         let is_crate_root =
             self.module_id == DefMap::ROOT && self.def_collector.def_map.block.is_none();
@@ -1726,11 +1727,12 @@ impl ModCollector<'_, '_> {
                 .unwrap_or(Visibility::Public)
         };
 
-        let mut process_mod_item = |item: ModItem| {
-            let attrs = self.item_tree.attrs(db, krate, item.into());
+        let mut process_mod_item = |item: ModItemId| {
+            let attrs = self.item_tree.attrs(db, krate, item.ast_id());
             if let Some(cfg) = attrs.cfg() {
                 if !self.is_cfg_enabled(&cfg) {
-                    self.emit_unconfigured_diagnostic(self.tree_id, item.into(), &cfg);
+                    let ast_id = item.ast_id().erase();
+                    self.emit_unconfigured_diagnostic(InFile::new(self.file_id(), ast_id), &cfg);
                     return;
                 }
             }
@@ -1747,39 +1749,31 @@ impl ModCollector<'_, '_> {
                 self.def_collector.crate_local_def_map.unwrap_or(&self.def_collector.local_def_map);
 
             match item {
-                ModItem::Mod(m) => self.collect_module(m, &attrs),
-                ModItem::Use(item_tree_id) => {
-                    let id = UseLoc {
-                        container: module,
-                        id: ItemTreeId::new(self.tree_id, item_tree_id),
-                    }
-                    .intern(db);
+                ModItemId::Mod(m) => self.collect_module(m, &attrs),
+                ModItemId::Use(item_tree_id) => {
+                    let id =
+                        UseLoc { container: module, id: InFile::new(self.file_id(), item_tree_id) }
+                            .intern(db);
                     let is_prelude = attrs.by_key(sym::prelude_import).exists();
-                    Import::from_use(
-                        self.item_tree,
-                        ItemTreeId::new(self.tree_id, item_tree_id),
-                        id,
-                        is_prelude,
-                        |import| {
-                            self.def_collector.unresolved_imports.push(ImportDirective {
-                                module_id: self.module_id,
-                                import,
-                                status: PartialResolvedImport::Unresolved,
-                            });
-                        },
-                    )
+                    Import::from_use(self.item_tree, item_tree_id, id, is_prelude, |import| {
+                        self.def_collector.unresolved_imports.push(ImportDirective {
+                            module_id: self.module_id,
+                            import,
+                            status: PartialResolvedImport::Unresolved,
+                        });
+                    })
                 }
-                ModItem::ExternCrate(item_tree_id) => {
+                ModItemId::ExternCrate(item_tree_id) => {
+                    let item_tree::ExternCrate { name, visibility, alias } =
+                        &self.item_tree[item_tree_id];
+
                     let id = ExternCrateLoc {
                         container: module,
-                        id: ItemTreeId::new(self.tree_id, item_tree_id),
+                        id: InFile::new(self.tree_id.file_id(), item_tree_id),
                     }
                     .intern(db);
                     def_map.modules[self.module_id].scope.define_extern_crate_decl(id);
 
-                    let item_tree::ExternCrate { name, visibility, alias, ast_id } =
-                        &self.item_tree[item_tree_id];
-
                     let is_self = *name == sym::self_;
                     let resolved = if is_self {
                         cov_mark::hit!(extern_crate_self_as);
@@ -1838,15 +1832,15 @@ impl ModCollector<'_, '_> {
                         self.def_collector.def_map.diagnostics.push(
                             DefDiagnostic::unresolved_extern_crate(
                                 module_id,
-                                InFile::new(self.file_id(), *ast_id),
+                                InFile::new(self.file_id(), item_tree_id),
                             ),
                         );
                     }
                 }
-                ModItem::ExternBlock(block) => {
+                ModItemId::ExternBlock(block) => {
                     let extern_block_id = ExternBlockLoc {
                         container: module,
-                        id: ItemTreeId::new(self.tree_id, block),
+                        id: InFile::new(self.file_id(), block),
                     }
                     .intern(db);
                     self.def_collector.def_map.modules[self.module_id]
@@ -1857,19 +1851,20 @@ impl ModCollector<'_, '_> {
                         ItemContainerId::ExternBlockId(extern_block_id),
                     )
                 }
-                ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac], container),
-                ModItem::MacroRules(id) => self.collect_macro_rules(id, module),
-                ModItem::Macro2(id) => self.collect_macro_def(id, module),
-                ModItem::Impl(imp) => {
+                ModItemId::MacroCall(mac) => self.collect_macro_call(mac, container),
+                ModItemId::MacroRules(id) => self.collect_macro_rules(id, module),
+                ModItemId::Macro2(id) => self.collect_macro_def(id, module),
+                ModItemId::Impl(imp) => {
                     let impl_id =
-                        ImplLoc { container: module, id: ItemTreeId::new(self.tree_id, imp) }
+                        ImplLoc { container: module, id: InFile::new(self.file_id(), imp) }
                             .intern(db);
                     self.def_collector.def_map.modules[self.module_id].scope.define_impl(impl_id)
                 }
-                ModItem::Function(id) => {
+                ModItemId::Function(id) => {
                     let it = &self.item_tree[id];
                     let fn_id =
-                        FunctionLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
+                        FunctionLoc { container, id: InFile::new(self.tree_id.file_id(), id) }
+                            .intern(db);
 
                     let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
 
@@ -1880,8 +1875,7 @@ impl ModCollector<'_, '_> {
                         if let Some(proc_macro) = attrs.parse_proc_macro_decl(&it.name) {
                             self.def_collector.export_proc_macro(
                                 proc_macro,
-                                ItemTreeId::new(self.tree_id, id),
-                                InFile::new(self.file_id(), self.item_tree[id].ast_id()),
+                                InFile::new(self.file_id(), id),
                                 fn_id,
                             );
                         }
@@ -1889,13 +1883,13 @@ impl ModCollector<'_, '_> {
 
                     update_def(self.def_collector, fn_id.into(), &it.name, vis, false);
                 }
-                ModItem::Struct(id) => {
+                ModItemId::Struct(id) => {
                     let it = &self.item_tree[id];
 
                     let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
                     update_def(
                         self.def_collector,
-                        StructLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
+                        StructLoc { container: module, id: InFile::new(self.file_id(), id) }
                             .intern(db)
                             .into(),
                         &it.name,
@@ -1903,13 +1897,13 @@ impl ModCollector<'_, '_> {
                         !matches!(it.shape, FieldsShape::Record),
                     );
                 }
-                ModItem::Union(id) => {
+                ModItemId::Union(id) => {
                     let it = &self.item_tree[id];
 
                     let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
                     update_def(
                         self.def_collector,
-                        UnionLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
+                        UnionLoc { container: module, id: InFile::new(self.file_id(), id) }
                             .intern(db)
                             .into(),
                         &it.name,
@@ -1917,19 +1911,20 @@ impl ModCollector<'_, '_> {
                         false,
                     );
                 }
-                ModItem::Enum(id) => {
+                ModItemId::Enum(id) => {
                     let it = &self.item_tree[id];
                     let enum_ =
-                        EnumLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
+                        EnumLoc { container: module, id: InFile::new(self.tree_id.file_id(), id) }
                             .intern(db);
 
                     let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
                     update_def(self.def_collector, enum_.into(), &it.name, vis, false);
                 }
-                ModItem::Const(id) => {
+                ModItemId::Const(id) => {
                     let it = &self.item_tree[id];
                     let const_id =
-                        ConstLoc { container, id: ItemTreeId::new(self.tree_id, id) }.intern(db);
+                        ConstLoc { container, id: InFile::new(self.tree_id.file_id(), id) }
+                            .intern(db);
 
                     match &it.name {
                         Some(name) => {
@@ -1945,13 +1940,13 @@ impl ModCollector<'_, '_> {
                         }
                     }
                 }
-                ModItem::Static(id) => {
+                ModItemId::Static(id) => {
                     let it = &self.item_tree[id];
 
                     let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
                     update_def(
                         self.def_collector,
-                        StaticLoc { container, id: ItemTreeId::new(self.tree_id, id) }
+                        StaticLoc { container, id: InFile::new(self.file_id(), id) }
                             .intern(db)
                             .into(),
                         &it.name,
@@ -1959,13 +1954,13 @@ impl ModCollector<'_, '_> {
                         false,
                     );
                 }
-                ModItem::Trait(id) => {
+                ModItemId::Trait(id) => {
                     let it = &self.item_tree[id];
 
                     let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
                     update_def(
                         self.def_collector,
-                        TraitLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
+                        TraitLoc { container: module, id: InFile::new(self.file_id(), id) }
                             .intern(db)
                             .into(),
                         &it.name,
@@ -1973,13 +1968,13 @@ impl ModCollector<'_, '_> {
                         false,
                     );
                 }
-                ModItem::TraitAlias(id) => {
+                ModItemId::TraitAlias(id) => {
                     let it = &self.item_tree[id];
 
                     let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
                     update_def(
                         self.def_collector,
-                        TraitAliasLoc { container: module, id: ItemTreeId::new(self.tree_id, id) }
+                        TraitAliasLoc { container: module, id: InFile::new(self.file_id(), id) }
                             .intern(db)
                             .into(),
                         &it.name,
@@ -1987,13 +1982,13 @@ impl ModCollector<'_, '_> {
                         false,
                     );
                 }
-                ModItem::TypeAlias(id) => {
+                ModItemId::TypeAlias(id) => {
                     let it = &self.item_tree[id];
 
                     let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
                     update_def(
                         self.def_collector,
-                        TypeAliasLoc { container, id: ItemTreeId::new(self.tree_id, id) }
+                        TypeAliasLoc { container, id: InFile::new(self.file_id(), id) }
                             .intern(db)
                             .into(),
                         &it.name,
@@ -2010,12 +2005,12 @@ impl ModCollector<'_, '_> {
         if is_crate_root {
             items
                 .iter()
-                .filter(|it| matches!(it, ModItem::ExternCrate(..)))
+                .filter(|it| matches!(it, ModItemId::ExternCrate(..)))
                 .copied()
                 .for_each(&mut process_mod_item);
             items
                 .iter()
-                .filter(|it| !matches!(it, ModItem::ExternCrate(..)))
+                .filter(|it| !matches!(it, ModItemId::ExternCrate(..)))
                 .copied()
                 .for_each(process_mod_item);
         } else {
@@ -2056,19 +2051,18 @@ impl ModCollector<'_, '_> {
         );
     }
 
-    fn collect_module(&mut self, module_id: FileItemTreeId<Mod>, attrs: &Attrs) {
+    fn collect_module(&mut self, module_ast_id: ItemTreeAstId<Mod>, attrs: &Attrs) {
         let path_attr = attrs.by_key(sym::path).string_value_unescape();
         let is_macro_use = attrs.by_key(sym::macro_use).exists();
-        let module = &self.item_tree[module_id];
+        let module = &self.item_tree[module_ast_id];
         match &module.kind {
             // inline module, just recurse
             ModKind::Inline { items } => {
                 let module_id = self.push_child_module(
                     module.name.clone(),
-                    module.ast_id,
+                    module_ast_id,
                     None,
                     &self.item_tree[module.visibility],
-                    module_id,
                 );
 
                 let Some(mod_dir) =
@@ -2091,7 +2085,7 @@ impl ModCollector<'_, '_> {
             }
             // out of line module, resolve, parse and recurse
             ModKind::Outline => {
-                let ast_id = AstId::new(self.file_id(), module.ast_id);
+                let ast_id = AstId::new(self.file_id(), module_ast_id);
                 let db = self.def_collector.db;
                 match self.mod_dir.resolve_declaration(
                     db,
@@ -2110,8 +2104,7 @@ impl ModCollector<'_, '_> {
                         match is_enabled {
                             Err(cfg) => {
                                 self.emit_unconfigured_diagnostic(
-                                    self.tree_id,
-                                    AttrOwner::ModItem(module_id.into()),
+                                    InFile::new(self.file_id(), module_ast_id.erase()),
                                     &cfg,
                                 );
                             }
@@ -2121,14 +2114,13 @@ impl ModCollector<'_, '_> {
                                     ast_id.value,
                                     Some((file_id, is_mod_rs)),
                                     &self.item_tree[module.visibility],
-                                    module_id,
                                 );
                                 ModCollector {
                                     def_collector: self.def_collector,
                                     macro_depth: self.macro_depth,
                                     module_id,
                                     tree_id: TreeId::new(file_id.into(), None),
-                                    item_tree: &item_tree,
+                                    item_tree,
                                     mod_dir,
                                 }
                                 .collect_in_top_module(item_tree.top_level_items());
@@ -2149,7 +2141,6 @@ impl ModCollector<'_, '_> {
                             ast_id.value,
                             None,
                             &self.item_tree[module.visibility],
-                            module_id,
                         );
                         self.def_collector.def_map.diagnostics.push(
                             DefDiagnostic::unresolved_module(self.module_id, ast_id, candidates),
@@ -2166,7 +2157,6 @@ impl ModCollector<'_, '_> {
         declaration: FileAstId<ast::Module>,
         definition: Option<(EditionedFileId, bool)>,
         visibility: &crate::visibility::RawVisibility,
-        mod_tree_id: FileItemTreeId<Mod>,
     ) -> LocalModuleId {
         let def_map = &mut self.def_collector.def_map;
         let vis = def_map
@@ -2179,15 +2169,14 @@ impl ModCollector<'_, '_> {
             )
             .unwrap_or(Visibility::Public);
         let origin = match definition {
-            None => ModuleOrigin::Inline {
-                definition: declaration,
-                definition_tree_id: ItemTreeId::new(self.tree_id, mod_tree_id),
-            },
+            None => {
+                ModuleOrigin::Inline { definition: declaration, definition_tree_id: self.tree_id }
+            }
             Some((definition, is_mod_rs)) => ModuleOrigin::File {
                 declaration,
                 definition,
                 is_mod_rs,
-                declaration_tree_id: ItemTreeId::new(self.tree_id, mod_tree_id),
+                declaration_tree_id: self.tree_id,
             },
         };
 
@@ -2228,11 +2217,14 @@ impl ModCollector<'_, '_> {
     fn resolve_attributes(
         &mut self,
         attrs: &Attrs,
-        mod_item: ModItem,
+        mod_item: ModItemId,
         container: ItemContainerId,
     ) -> Result<(), ()> {
-        let mut ignore_up_to =
-            self.def_collector.skip_attrs.get(&InFile::new(self.file_id(), mod_item)).copied();
+        let mut ignore_up_to = self
+            .def_collector
+            .skip_attrs
+            .get(&InFile::new(self.file_id(), mod_item.ast_id()))
+            .copied();
         let iter = attrs
             .iter()
             .dedup_by(|a, b| {
@@ -2262,11 +2254,7 @@ impl ModCollector<'_, '_> {
                 attr.path.display(self.def_collector.db, Edition::LATEST)
             );
 
-            let ast_id = AstIdWithPath::new(
-                self.file_id(),
-                mod_item.ast_id(self.item_tree),
-                attr.path.clone(),
-            );
+            let ast_id = AstIdWithPath::new(self.file_id(), mod_item.ast_id(), attr.path.clone());
             self.def_collector.unresolved_macros.push(MacroDirective {
                 module_id: self.module_id,
                 depth: self.macro_depth + 1,
@@ -2275,6 +2263,7 @@ impl ModCollector<'_, '_> {
                     attr: attr.clone(),
                     mod_item,
                     tree: self.tree_id,
+                    item_tree: self.item_tree,
                 },
                 container,
             });
@@ -2285,11 +2274,11 @@ impl ModCollector<'_, '_> {
         Ok(())
     }
 
-    fn collect_macro_rules(&mut self, id: FileItemTreeId<MacroRules>, module: ModuleId) {
+    fn collect_macro_rules(&mut self, ast_id: ItemTreeAstId<MacroRules>, module: ModuleId) {
         let krate = self.def_collector.def_map.krate;
-        let mac = &self.item_tree[id];
-        let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into());
-        let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast());
+        let mac = &self.item_tree[ast_id];
+        let attrs = self.item_tree.attrs(self.def_collector.db, krate, ast_id.upcast());
+        let f_ast_id = InFile::new(self.file_id(), ast_id.upcast());
 
         let export_attr = || attrs.by_key(sym::macro_export);
 
@@ -2336,7 +2325,7 @@ impl ModCollector<'_, '_> {
                     self.def_collector
                         .def_map
                         .diagnostics
-                        .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id));
+                        .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, f_ast_id));
                     return;
                 }
             }
@@ -2352,16 +2341,13 @@ impl ModCollector<'_, '_> {
 
         let macro_id = MacroRulesLoc {
             container: module,
-            id: ItemTreeId::new(self.tree_id, id),
+            id: InFile::new(self.file_id(), ast_id),
             flags,
             expander,
             edition: self.def_collector.def_map.data.edition,
         }
         .intern(self.def_collector.db);
-        self.def_collector.def_map.macro_def_to_macro_id.insert(
-            InFile::new(self.file_id(), self.item_tree[id].ast_id()).erase(),
-            macro_id.into(),
-        );
+        self.def_collector.def_map.macro_def_to_macro_id.insert(f_ast_id.erase(), macro_id.into());
         self.def_collector.define_macro_rules(
             self.module_id,
             mac.name.clone(),
@@ -2370,14 +2356,14 @@ impl ModCollector<'_, '_> {
         );
     }
 
-    fn collect_macro_def(&mut self, id: FileItemTreeId<Macro2>, module: ModuleId) {
+    fn collect_macro_def(&mut self, ast_id: ItemTreeAstId<Macro2>, module: ModuleId) {
         let krate = self.def_collector.def_map.krate;
-        let mac = &self.item_tree[id];
-        let ast_id = InFile::new(self.file_id(), mac.ast_id.upcast());
+        let mac = &self.item_tree[ast_id];
+        let attrs = self.item_tree.attrs(self.def_collector.db, krate, ast_id.upcast());
+        let f_ast_id = InFile::new(self.file_id(), ast_id.upcast());
 
         // Case 1: builtin macros
         let mut helpers_opt = None;
-        let attrs = self.item_tree.attrs(self.def_collector.db, krate, ModItem::from(id).into());
         let expander = if attrs.by_key(sym::rustc_builtin_macro).exists() {
             if let Some(expander) = find_builtin_macro(&mac.name) {
                 match expander {
@@ -2409,7 +2395,7 @@ impl ModCollector<'_, '_> {
                 self.def_collector
                     .def_map
                     .diagnostics
-                    .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, ast_id));
+                    .push(DefDiagnostic::unimplemented_builtin_macro(self.module_id, f_ast_id));
                 return;
             }
         } else {
@@ -2420,16 +2406,13 @@ impl ModCollector<'_, '_> {
 
         let macro_id = Macro2Loc {
             container: module,
-            id: ItemTreeId::new(self.tree_id, id),
+            id: InFile::new(self.file_id(), ast_id),
             expander,
             allow_internal_unsafe,
             edition: self.def_collector.def_map.data.edition,
         }
         .intern(self.def_collector.db);
-        self.def_collector.def_map.macro_def_to_macro_id.insert(
-            InFile::new(self.file_id(), self.item_tree[id].ast_id()).erase(),
-            macro_id.into(),
-        );
+        self.def_collector.def_map.macro_def_to_macro_id.insert(f_ast_id.erase(), macro_id.into());
         self.def_collector.define_macro_def(
             self.module_id,
             mac.name.clone(),
@@ -2441,16 +2424,17 @@ impl ModCollector<'_, '_> {
                 Arc::get_mut(&mut self.def_collector.def_map.data)
                     .unwrap()
                     .exported_derives
-                    .insert(self.def_collector.db.macro_def(macro_id.into()), helpers);
+                    .insert(macro_id.into(), helpers);
             }
         }
     }
 
     fn collect_macro_call(
         &mut self,
-        &MacroCall { ref path, ast_id, expand_to, ctxt }: &MacroCall,
+        ast_id: FileAstId<ast::MacroCall>,
         container: ItemContainerId,
     ) {
+        let &MacroCall { ref path, expand_to, ctxt } = &self.item_tree[ast_id];
         let ast_id = AstIdWithPath::new(self.file_id(), ast_id, path.clone());
         let db = self.def_collector.db;
 
@@ -2565,16 +2549,16 @@ impl ModCollector<'_, '_> {
         self.def_collector.cfg_options.check(cfg) != Some(false)
     }
 
-    fn emit_unconfigured_diagnostic(&mut self, tree_id: TreeId, item: AttrOwner, cfg: &CfgExpr) {
+    fn emit_unconfigured_diagnostic(&mut self, ast_id: ErasedAstId, cfg: &CfgExpr) {
         self.def_collector.def_map.diagnostics.push(DefDiagnostic::unconfigured_code(
             self.module_id,
-            tree_id,
-            item,
+            ast_id,
             cfg.clone(),
             self.def_collector.cfg_options.clone(),
         ));
     }
 
+    #[inline]
     fn file_id(&self) -> HirFileId {
         self.tree_id.file_id()
     }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
index de3d2f48367..c495a074491 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
@@ -3,22 +3,18 @@
 use std::ops::Not;
 
 use cfg::{CfgExpr, CfgOptions};
-use hir_expand::{ExpandErrorKind, MacroCallKind, attrs::AttrId, mod_path::ModPath};
+use hir_expand::{ErasedAstId, ExpandErrorKind, MacroCallKind, attrs::AttrId, mod_path::ModPath};
 use la_arena::Idx;
 use syntax::ast;
 
-use crate::{
-    AstId,
-    item_tree::{self, AttrOwner, ItemTreeId, TreeId},
-    nameres::LocalModuleId,
-};
+use crate::{AstId, nameres::LocalModuleId};
 
 #[derive(Debug, PartialEq, Eq)]
 pub enum DefDiagnosticKind {
     UnresolvedModule { ast: AstId<ast::Module>, candidates: Box<[String]> },
     UnresolvedExternCrate { ast: AstId<ast::ExternCrate> },
-    UnresolvedImport { id: ItemTreeId<item_tree::Use>, index: Idx<ast::UseTree> },
-    UnconfiguredCode { tree: TreeId, item: AttrOwner, cfg: CfgExpr, opts: CfgOptions },
+    UnresolvedImport { id: AstId<ast::Use>, index: Idx<ast::UseTree> },
+    UnconfiguredCode { ast_id: ErasedAstId, cfg: CfgExpr, opts: CfgOptions },
     UnresolvedMacroCall { ast: MacroCallKind, path: ModPath },
     UnimplementedBuiltinMacro { ast: AstId<ast::Macro> },
     InvalidDeriveTarget { ast: AstId<ast::Item>, id: usize },
@@ -28,7 +24,7 @@ pub enum DefDiagnosticKind {
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
-pub struct DefDiagnostics(Option<triomphe::Arc<Box<[DefDiagnostic]>>>);
+pub struct DefDiagnostics(Option<triomphe::ThinArc<(), DefDiagnostic>>);
 
 impl DefDiagnostics {
     pub fn new(diagnostics: Vec<DefDiagnostic>) -> Self {
@@ -36,12 +32,12 @@ impl DefDiagnostics {
             diagnostics
                 .is_empty()
                 .not()
-                .then(|| triomphe::Arc::new(diagnostics.into_boxed_slice())),
+                .then(|| triomphe::ThinArc::from_header_and_iter((), diagnostics.into_iter())),
         )
     }
 
     pub fn iter(&self) -> impl Iterator<Item = &DefDiagnostic> {
-        self.0.as_ref().into_iter().flat_map(|it| &***it)
+        self.0.as_ref().into_iter().flat_map(|it| &it.slice)
     }
 }
 
@@ -75,7 +71,7 @@ impl DefDiagnostic {
 
     pub(super) fn unresolved_import(
         container: LocalModuleId,
-        id: ItemTreeId<item_tree::Use>,
+        id: AstId<ast::Use>,
         index: Idx<ast::UseTree>,
     ) -> Self {
         Self { in_module: container, kind: DefDiagnosticKind::UnresolvedImport { id, index } }
@@ -92,14 +88,13 @@ impl DefDiagnostic {
 
     pub fn unconfigured_code(
         container: LocalModuleId,
-        tree: TreeId,
-        item: AttrOwner,
+        ast_id: ErasedAstId,
         cfg: CfgExpr,
         opts: CfgOptions,
     ) -> Self {
         Self {
             in_module: container,
-            kind: DefDiagnosticKind::UnconfiguredCode { tree, item, cfg, opts },
+            kind: DefDiagnosticKind::UnconfiguredCode { ast_id, cfg, opts },
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
index 74ce33a6419..e8235b1c96f 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
@@ -12,7 +12,6 @@
 
 use either::Either;
 use hir_expand::{
-    Lookup,
     mod_path::{ModPath, PathKind},
     name::Name,
 };
@@ -107,7 +106,7 @@ impl DefMap {
         visibility: &RawVisibility,
         within_impl: bool,
     ) -> Option<Visibility> {
-        let mut vis = match visibility {
+        let vis = match visibility {
             RawVisibility::Module(path, explicitness) => {
                 let (result, remaining) = self.resolve_path(
                     local_def_map,
@@ -121,29 +120,36 @@ impl DefMap {
                     return None;
                 }
                 let types = result.take_types()?;
-                match types {
+                let mut vis = match types {
                     ModuleDefId::ModuleId(m) => Visibility::Module(m, *explicitness),
                     // error: visibility needs to refer to module
                     _ => {
                         return None;
                     }
+                };
+
+                // In block expressions, `self` normally refers to the containing non-block module, and
+                // `super` to its parent (etc.). However, visibilities must only refer to a module in the
+                // DefMap they're written in, so we restrict them when that happens.
+                if let Visibility::Module(m, mv) = vis {
+                    // ...unless we're resolving visibility for an associated item in an impl.
+                    if self.block_id() != m.block && !within_impl {
+                        vis = Visibility::Module(self.module_id(Self::ROOT), mv);
+                        tracing::debug!(
+                            "visibility {:?} points outside DefMap, adjusting to {:?}",
+                            m,
+                            vis
+                        );
+                    }
                 }
+                vis
+            }
+            RawVisibility::PubSelf(explicitness) => {
+                Visibility::Module(self.module_id(original_module), *explicitness)
             }
             RawVisibility::Public => Visibility::Public,
+            RawVisibility::PubCrate => Visibility::PubCrate(self.krate),
         };
-
-        // In block expressions, `self` normally refers to the containing non-block module, and
-        // `super` to its parent (etc.). However, visibilities must only refer to a module in the
-        // DefMap they're written in, so we restrict them when that happens.
-        if let Visibility::Module(m, mv) = vis {
-            // ...unless we're resolving visibility for an associated item in an impl.
-            if self.block_id() != m.block && !within_impl {
-                cov_mark::hit!(adjust_vis_in_block_def_map);
-                vis = Visibility::Module(self.module_id(Self::ROOT), mv);
-                tracing::debug!("visibility {:?} points outside DefMap, adjusting to {:?}", m, vis);
-            }
-        }
-
         Some(vis)
     }
 
@@ -529,23 +535,22 @@ impl DefMap {
                     // enum variant
                     cov_mark::hit!(can_import_enum_variant);
 
-                    let res =
-                        db.enum_variants(e).variants.iter().find(|(_, name)| name == segment).map(
-                            |&(variant, _)| {
-                                let item_tree_id = variant.lookup(db).id;
-                                match item_tree_id.item_tree(db)[item_tree_id.value].shape {
-                                    FieldsShape::Record => {
-                                        PerNs::types(variant.into(), Visibility::Public, None)
-                                    }
-                                    FieldsShape::Tuple | FieldsShape::Unit => PerNs::both(
-                                        variant.into(),
-                                        variant.into(),
-                                        Visibility::Public,
-                                        None,
-                                    ),
-                                }
-                            },
-                        );
+                    let res = e
+                        .enum_variants(db)
+                        .variants
+                        .iter()
+                        .find(|(_, name, _)| name == segment)
+                        .map(|&(variant, _, shape)| match shape {
+                            FieldsShape::Record => {
+                                PerNs::types(variant.into(), Visibility::Public, None)
+                            }
+                            FieldsShape::Tuple | FieldsShape::Unit => PerNs::both(
+                                variant.into(),
+                                variant.into(),
+                                Visibility::Public,
+                                None,
+                            ),
+                        });
                     // FIXME: Need to filter visibility here and below? Not sure.
                     return match res {
                         Some(res) => {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
index 948e8bed66d..ba75dca3d3d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/incremental.rs
@@ -2,13 +2,13 @@ use base_db::{
     CrateDisplayName, CrateGraphBuilder, CrateName, CrateOrigin, CrateWorkspaceData,
     DependencyBuilder, Env, RootQueryDb, SourceDatabase,
 };
+use expect_test::{Expect, expect};
 use intern::Symbol;
 use span::Edition;
 use test_fixture::WithFixture;
 use triomphe::Arc;
 
 use crate::{
-    AdtId, ModuleDefId,
     db::DefDatabase,
     nameres::{crate_def_map, tests::TestDB},
 };
@@ -16,29 +16,29 @@ use crate::{
 fn check_def_map_is_not_recomputed(
     #[rust_analyzer::rust_fixture] ra_fixture_initial: &str,
     #[rust_analyzer::rust_fixture] ra_fixture_change: &str,
+    expecta: Expect,
+    expectb: Expect,
 ) {
     let (mut db, pos) = TestDB::with_position(ra_fixture_initial);
     let krate = db.fetch_test_crate();
-    {
-        let events = db.log_executed(|| {
+    execute_assert_events(
+        &db,
+        || {
             crate_def_map(&db, krate);
-        });
-        assert!(
-            format!("{events:?}").contains("crate_local_def_map"),
-            "no crate def map computed:\n{events:#?}",
-        )
-    }
+        },
+        &[],
+        expecta,
+    );
     db.set_file_text(pos.file_id.file_id(&db), ra_fixture_change);
 
-    {
-        let events = db.log_executed(|| {
+    execute_assert_events(
+        &db,
+        || {
             crate_def_map(&db, krate);
-        });
-        assert!(
-            !format!("{events:?}").contains("crate_local_def_map"),
-            "crate def map invalidated:\n{events:#?}",
-        )
-    }
+        },
+        &[("crate_local_def_map", 0)],
+        expectb,
+    );
 }
 
 #[test]
@@ -104,15 +104,20 @@ pub const BAZ: u32 = 0;
         Arc::ptr_eq(&all_crates_before, &all_crates_after),
         "the all_crates list should not have been invalidated"
     );
-
-    let events = db.log_executed(|| {
-        for &krate in db.all_crates().iter() {
-            crate_def_map(&db, krate);
-        }
-    });
-    let invalidated_def_maps =
-        events.iter().filter(|event| event.contains("crate_local_def_map")).count();
-    assert_eq!(invalidated_def_maps, 1, "{events:#?}")
+    execute_assert_events(
+        &db,
+        || {
+            for &krate in db.all_crates().iter() {
+                crate_def_map(&db, krate);
+            }
+        },
+        &[("crate_local_def_map", 1)],
+        expect![[r#"
+            [
+                "crate_local_def_map",
+            ]
+        "#]],
+    );
 }
 
 #[test]
@@ -152,6 +157,33 @@ fn foo() -> i32 { 92 }
 #[cfg(never)]
 fn no() {}
 ",
+        expect![[r#"
+            [
+                "crate_local_def_map",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "of_",
+            ]
+        "#]],
+        expect![[r#"
+            [
+                "parse_shim",
+                "ast_id_map_shim",
+                "file_item_tree_query",
+                "real_span_map_shim",
+                "of_",
+            ]
+        "#]],
     );
 }
 
@@ -183,6 +215,41 @@ m!(Y);
 
 pub struct S {}
 ",
+        expect![[r#"
+            [
+                "crate_local_def_map",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "macro_def_shim",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_macro_expansion_shim",
+                "macro_arg_shim",
+                "decl_macro_expander_shim",
+            ]
+        "#]],
+        expect![[r#"
+            [
+                "parse_shim",
+                "ast_id_map_shim",
+                "file_item_tree_query",
+                "real_span_map_shim",
+                "macro_arg_shim",
+                "parse_macro_expansion_shim",
+                "ast_id_map_shim",
+                "file_item_tree_query",
+            ]
+        "#]],
     );
 }
 
@@ -206,6 +273,49 @@ fn f() {}
 #[proc_macros::identity]
 fn f() { foo }
 ",
+        expect![[r#"
+            [
+                "crate_local_def_map",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "crate_local_def_map",
+                "proc_macros_for_crate_shim",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "macro_def_shim",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_macro_expansion_shim",
+                "expand_proc_macro_shim",
+                "macro_arg_shim",
+                "proc_macro_span_shim",
+            ]
+        "#]],
+        expect![[r#"
+            [
+                "parse_shim",
+                "ast_id_map_shim",
+                "file_item_tree_query",
+                "real_span_map_shim",
+                "macro_arg_shim",
+                "expand_proc_macro_shim",
+                "parse_macro_expansion_shim",
+                "ast_id_map_shim",
+                "file_item_tree_query",
+            ]
+        "#]],
     );
 }
 
@@ -287,6 +397,60 @@ m2!(X);
 #[derive(proc_macros::DeriveIdentity)]
 pub struct S {}
 ",
+        expect![[r#"
+            [
+                "crate_local_def_map",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "macro_def_shim",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_macro_expansion_shim",
+                "macro_arg_shim",
+                "decl_macro_expander_shim",
+                "macro_def_shim",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_macro_expansion_shim",
+                "macro_arg_shim",
+                "decl_macro_expander_shim",
+                "crate_local_def_map",
+                "proc_macros_for_crate_shim",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "macro_def_shim",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_macro_expansion_shim",
+                "expand_proc_macro_shim",
+                "macro_arg_shim",
+                "proc_macro_span_shim",
+            ]
+        "#]],
+        expect![[r#"
+            [
+                "parse_shim",
+                "ast_id_map_shim",
+                "file_item_tree_query",
+                "real_span_map_shim",
+                "macro_arg_shim",
+                "macro_arg_shim",
+                "decl_macro_expander_shim",
+                "macro_arg_shim",
+            ]
+        "#]],
     );
 }
 
@@ -341,19 +505,46 @@ m!(Z);
 "#,
     );
     let krate = db.test_crate();
-    {
-        let events = db.log_executed(|| {
+    execute_assert_events(
+        &db,
+        || {
             let crate_def_map = crate_def_map(&db, krate);
             let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
             assert_eq!(module_data.scope.resolutions().count(), 4);
-        });
-        let n_recalculated_item_trees =
-            events.iter().filter(|it| it.contains("file_item_tree_shim")).count();
-        assert_eq!(n_recalculated_item_trees, 6);
-        let n_reparsed_macros =
-            events.iter().filter(|it| it.contains("parse_macro_expansion_shim")).count();
-        assert_eq!(n_reparsed_macros, 3);
-    }
+        },
+        &[("file_item_tree_query", 6), ("parse_macro_expansion_shim", 3)],
+        expect![[r#"
+            [
+                "crate_local_def_map",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "macro_def_shim",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_macro_expansion_shim",
+                "macro_arg_shim",
+                "decl_macro_expander_shim",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_macro_expansion_shim",
+                "macro_arg_shim",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_macro_expansion_shim",
+                "macro_arg_shim",
+            ]
+        "#]],
+    );
 
     let new_text = r#"
 m!(X);
@@ -363,28 +554,31 @@ m!(Z);
 "#;
     db.set_file_text(pos.file_id.file_id(&db), new_text);
 
-    {
-        let events = db.log_executed(|| {
+    execute_assert_events(
+        &db,
+        || {
             let crate_def_map = crate_def_map(&db, krate);
             let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
             assert_eq!(module_data.scope.resolutions().count(), 4);
-        });
-        let n_recalculated_item_trees =
-            events.iter().filter(|it| it.contains("file_item_tree_shim")).count();
-        assert_eq!(n_recalculated_item_trees, 1, "{events:#?}");
-        let n_reparsed_macros =
-            events.iter().filter(|it| it.contains("parse_macro_expansion_shim")).count();
-        assert_eq!(n_reparsed_macros, 0);
-    }
+        },
+        &[("file_item_tree_query", 1), ("parse_macro_expansion_shim", 0)],
+        expect![[r#"
+            [
+                "parse_shim",
+                "ast_id_map_shim",
+                "file_item_tree_query",
+                "real_span_map_shim",
+                "macro_arg_shim",
+                "macro_arg_shim",
+                "macro_arg_shim",
+            ]
+        "#]],
+    );
 }
 
 #[test]
 fn item_tree_prevents_reparsing() {
-    // The `ItemTree` is used by both name resolution and the various queries in `adt.rs` and
-    // `data.rs`. After computing the `ItemTree` and deleting the parse tree, we should be able to
-    // run those other queries without triggering a reparse.
-
-    let (db, pos) = TestDB::with_position(
+    let (mut db, pos) = TestDB::with_position(
         r#"
 pub struct S;
 pub union U {}
@@ -399,53 +593,54 @@ pub static ST: u8 = 0;
 pub type Ty = ();
 "#,
     );
-    let krate = db.test_crate();
-    {
-        let events = db.log_executed(|| {
-            db.file_item_tree(pos.file_id.into());
-        });
-        let n_calculated_item_trees =
-            events.iter().filter(|it| it.contains("file_item_tree_shim")).count();
-        assert_eq!(n_calculated_item_trees, 1);
-        let n_parsed_files = events.iter().filter(|it| it.contains("parse")).count();
-        assert_eq!(n_parsed_files, 1);
-    }
 
-    // FIXME(salsa-transition): bring this back
-    // base_db::ParseQuery.in_db(&db).purge();
+    execute_assert_events(
+        &db,
+        || {
+            db.file_item_tree(pos.file_id.into());
+        },
+        &[("file_item_tree_query", 1), ("parse", 1)],
+        expect![[r#"
+            [
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+            ]
+        "#]],
+    );
 
-    {
-        let events = db.log_executed(|| {
-            let crate_def_map = crate_def_map(&db, krate);
-            let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
-            assert_eq!(module_data.scope.resolutions().count(), 8);
-            assert_eq!(module_data.scope.impls().count(), 1);
+    let file_id = pos.file_id.file_id(&db);
+    let file_text = db.file_text(file_id).text(&db);
+    db.set_file_text(file_id, &format!("{file_text}\n"));
 
-            for imp in module_data.scope.impls() {
-                db.impl_signature(imp);
-            }
+    execute_assert_events(
+        &db,
+        || {
+            db.file_item_tree(pos.file_id.into());
+        },
+        &[("file_item_tree_query", 1), ("parse", 1)],
+        expect![[r#"
+            [
+                "parse_shim",
+                "ast_id_map_shim",
+                "file_item_tree_query",
+                "real_span_map_shim",
+            ]
+        "#]],
+    );
+}
 
-            for (_, res) in module_data.scope.resolutions() {
-                match res.values.map(|it| it.def).or(res.types.map(|it| it.def)).unwrap() {
-                    ModuleDefId::FunctionId(f) => _ = db.function_signature(f),
-                    ModuleDefId::AdtId(adt) => match adt {
-                        AdtId::StructId(it) => _ = db.struct_signature(it),
-                        AdtId::UnionId(it) => _ = db.union_signature(it),
-                        AdtId::EnumId(it) => _ = db.enum_signature(it),
-                    },
-                    ModuleDefId::ConstId(it) => _ = db.const_signature(it),
-                    ModuleDefId::StaticId(it) => _ = db.static_signature(it),
-                    ModuleDefId::TraitId(it) => _ = db.trait_signature(it),
-                    ModuleDefId::TraitAliasId(it) => _ = db.trait_alias_signature(it),
-                    ModuleDefId::TypeAliasId(it) => _ = db.type_alias_signature(it),
-                    ModuleDefId::EnumVariantId(_)
-                    | ModuleDefId::ModuleId(_)
-                    | ModuleDefId::MacroId(_)
-                    | ModuleDefId::BuiltinType(_) => unreachable!(),
-                }
-            }
-        });
-        let n_reparsed_files = events.iter().filter(|it| it.contains("parse(")).count();
-        assert_eq!(n_reparsed_files, 0);
+fn execute_assert_events(
+    db: &TestDB,
+    f: impl FnOnce(),
+    required: &[(&str, usize)],
+    expect: Expect,
+) {
+    let events = db.log_executed(f);
+    for (event, count) in required {
+        let n = events.iter().filter(|it| it.contains(event)).count();
+        assert_eq!(n, *count, "Expected {event} to be executed {count} times, but only got {n}");
     }
+    expect.assert_debug_eq(&events);
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
index 16988ddf04b..6f321980af4 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -5,21 +5,22 @@ use base_db::Crate;
 use hir_expand::{
     MacroDefId,
     mod_path::{ModPath, PathKind},
-    name::Name,
+    name::{AsName, Name},
 };
 use intern::{Symbol, sym};
 use itertools::Itertools as _;
 use rustc_hash::FxHashSet;
 use smallvec::{SmallVec, smallvec};
 use span::SyntaxContext;
+use syntax::ast::HasName;
 use triomphe::Arc;
 
 use crate::{
-    AdtId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId,
-    ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId, GenericParamId, HasModule,
-    ImplId, ItemContainerId, ItemTreeLoc, LifetimeParamId, LocalModuleId, Lookup, Macro2Id,
-    MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitAliasId,
-    TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UseId, VariantId,
+    AdtId, AstIdLoc, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId,
+    EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, FxIndexMap, GenericDefId,
+    GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalModuleId, Lookup,
+    Macro2Id, MacroId, MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId,
+    TraitAliasId, TraitId, TypeAliasId, TypeOrConstParamId, TypeParamId, UseId, VariantId,
     builtin_type::BuiltinType,
     db::DefDatabase,
     expr_store::{
@@ -32,10 +33,10 @@ use crate::{
         generics::{GenericParams, TypeOrConstParamData},
     },
     item_scope::{BUILTIN_SCOPE, BuiltinShadowMode, ImportOrExternCrate, ImportOrGlob, ItemScope},
-    item_tree::ImportAlias,
     lang_item::LangItemTarget,
     nameres::{DefMap, LocalDefMap, MacroSubNs, ResolvePathResultPrefixInfo, block_def_map},
     per_ns::PerNs,
+    src::HasSource,
     type_ref::LifetimeRef,
     visibility::{RawVisibility, Visibility},
 };
@@ -304,6 +305,10 @@ impl<'db> Resolver<'db> {
                     }),
                 )
             }
+            RawVisibility::PubSelf(explicitness) => {
+                Some(Visibility::Module(self.module(), *explicitness))
+            }
+            RawVisibility::PubCrate => Some(Visibility::PubCrate(self.krate())),
             RawVisibility::Public => Some(Visibility::Public),
         }
     }
@@ -627,14 +632,14 @@ impl<'db> Resolver<'db> {
             .extern_crate_decls()
             .filter_map(|id| {
                 let loc = id.lookup(db);
-                let tree = loc.item_tree_id().item_tree(db);
-                match &tree[loc.id.value].alias {
-                    Some(alias) => match alias {
-                        ImportAlias::Underscore => None,
-                        ImportAlias::Alias(name) => Some(name.clone()),
-                    },
-                    None => Some(tree[loc.id.value].name.clone()),
-                }
+                let extern_crate = loc.source(db);
+                // If there is a rename (`as x`), extract the renamed name, or remove the `extern crate`
+                // if it is an underscore.
+                extern_crate
+                    .value
+                    .rename()
+                    .map(|a| a.name().map(|it| it.as_name()))
+                    .unwrap_or_else(|| extern_crate.value.name_ref().map(|it| it.as_name()))
             })
     }
 
@@ -1471,10 +1476,7 @@ impl HasResolver for MacroRulesId {
 
 fn lookup_resolver(
     db: &dyn DefDatabase,
-    lookup: impl Lookup<
-        Database = dyn DefDatabase,
-        Data = impl ItemTreeLoc<Container = impl HasResolver>,
-    >,
+    lookup: impl Lookup<Database = dyn DefDatabase, Data = impl AstIdLoc<Container = impl HasResolver>>,
 ) -> Resolver<'_> {
     lookup.lookup(db).container().resolver(db)
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs
index 44cfd72c48f..377a545ebf4 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/signatures.rs
@@ -4,21 +4,25 @@ use std::ops::Not as _;
 
 use bitflags::bitflags;
 use cfg::{CfgExpr, CfgOptions};
-use either::Either;
-use hir_expand::{InFile, Intern, Lookup, name::Name};
+use hir_expand::{
+    InFile, Intern, Lookup,
+    name::{AsName, Name},
+};
 use intern::{Symbol, sym};
 use la_arena::{Arena, Idx};
 use rustc_abi::{IntegerType, ReprOptions};
 use syntax::{
-    AstNode, SyntaxNodePtr,
-    ast::{self, HasGenericParams, IsString},
+    NodeOrToken, SyntaxNodePtr, T,
+    ast::{self, HasGenericParams, HasName, HasVisibility, IsString},
 };
 use thin_vec::ThinVec;
 use triomphe::Arc;
 
 use crate::{
-    ConstId, EnumId, EnumVariantId, EnumVariantLoc, FunctionId, HasModule, ImplId, ItemContainerId,
-    ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, UnionId, VariantId,
+    ConstId, EnumId, EnumVariantId, EnumVariantLoc, ExternBlockId, FunctionId, HasModule, ImplId,
+    ItemContainerId, ModuleId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId, UnionId,
+    VariantId,
+    attr::Attrs,
     db::DefDatabase,
     expr_store::{
         ExpressionStore, ExpressionStoreSourceMap,
@@ -28,15 +32,17 @@ use crate::{
         },
     },
     hir::{ExprId, PatId, generics::GenericParams},
-    item_tree::{
-        AttrOwner, Field, FieldParent, FieldsShape, FileItemTreeId, ItemTree, ItemTreeId, ModItem,
-        RawVisibility, RawVisibilityId,
-    },
+    item_tree::{FieldsShape, RawVisibility, visibility_from_ast},
     lang_item::LangItem,
     src::HasSource,
     type_ref::{TraitRef, TypeBound, TypeRefId},
 };
 
+#[inline]
+fn as_name_opt(name: Option<ast::Name>) -> Name {
+    name.map_or_else(Name::missing, |it| it.as_name())
+}
+
 #[derive(Debug, PartialEq, Eq)]
 pub struct StructSignature {
     pub name: Name,
@@ -70,8 +76,8 @@ bitflags! {
 impl StructSignature {
     pub fn query(db: &dyn DefDatabase, id: StructId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
         let loc = id.lookup(db);
-        let item_tree = loc.id.item_tree(db);
-        let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
+        let InFile { file_id, value: source } = loc.source(db);
+        let attrs = db.attrs(id.into());
 
         let mut flags = StructFlags::empty();
         if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() {
@@ -91,23 +97,23 @@ impl StructSignature {
             }
         }
         let repr = attrs.repr();
+        let shape = adt_shape(source.kind());
 
-        let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db);
         let (store, generic_params, source_map) = lower_generic_params(
             db,
             loc.container,
             id.into(),
             file_id,
-            value.generic_param_list(),
-            value.where_clause(),
+            source.generic_param_list(),
+            source.where_clause(),
         );
         (
             Arc::new(StructSignature {
                 generic_params,
                 store,
                 flags,
-                shape: item_tree[loc.id.value].shape,
-                name: item_tree[loc.id.value].name.clone(),
+                shape,
+                name: as_name_opt(source.name()),
                 repr,
             }),
             Arc::new(source_map),
@@ -115,6 +121,15 @@ impl StructSignature {
     }
 }
 
+#[inline]
+fn adt_shape(adt_kind: ast::StructKind) -> FieldsShape {
+    match adt_kind {
+        ast::StructKind::Record(_) => FieldsShape::Record,
+        ast::StructKind::Tuple(_) => FieldsShape::Tuple,
+        ast::StructKind::Unit => FieldsShape::Unit,
+    }
+}
+
 #[derive(Debug, PartialEq, Eq)]
 pub struct UnionSignature {
     pub name: Name,
@@ -127,9 +142,7 @@ pub struct UnionSignature {
 impl UnionSignature {
     pub fn query(db: &dyn DefDatabase, id: UnionId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
         let loc = id.lookup(db);
-        let krate = loc.container.krate;
-        let item_tree = loc.id.item_tree(db);
-        let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into());
+        let attrs = db.attrs(id.into());
         let mut flags = StructFlags::empty();
         if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() {
             flags |= StructFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS;
@@ -140,14 +153,14 @@ impl UnionSignature {
 
         let repr = attrs.repr();
 
-        let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db);
+        let InFile { file_id, value: source } = loc.source(db);
         let (store, generic_params, source_map) = lower_generic_params(
             db,
             loc.container,
             id.into(),
             file_id,
-            value.generic_param_list(),
-            value.where_clause(),
+            source.generic_param_list(),
+            source.where_clause(),
         );
         (
             Arc::new(UnionSignature {
@@ -155,7 +168,7 @@ impl UnionSignature {
                 store,
                 flags,
                 repr,
-                name: item_tree[loc.id.value].name.clone(),
+                name: as_name_opt(source.name()),
             }),
             Arc::new(source_map),
         )
@@ -181,8 +194,7 @@ pub struct EnumSignature {
 impl EnumSignature {
     pub fn query(db: &dyn DefDatabase, id: EnumId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
         let loc = id.lookup(db);
-        let item_tree = loc.id.item_tree(db);
-        let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
+        let attrs = db.attrs(id.into());
         let mut flags = EnumFlags::empty();
         if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() {
             flags |= EnumFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS;
@@ -190,14 +202,14 @@ impl EnumSignature {
 
         let repr = attrs.repr();
 
-        let hir_expand::files::InFileWrapper { file_id, value } = loc.source(db);
+        let InFile { file_id, value: source } = loc.source(db);
         let (store, generic_params, source_map) = lower_generic_params(
             db,
             loc.container,
             id.into(),
             file_id,
-            value.generic_param_list(),
-            value.where_clause(),
+            source.generic_param_list(),
+            source.where_clause(),
         );
 
         (
@@ -206,7 +218,7 @@ impl EnumSignature {
                 store,
                 flags,
                 repr,
-                name: item_tree[loc.id.value].name.clone(),
+                name: as_name_opt(source.name()),
             }),
             Arc::new(source_map),
         )
@@ -239,10 +251,9 @@ pub struct ConstSignature {
 impl ConstSignature {
     pub fn query(db: &dyn DefDatabase, id: ConstId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
         let loc = id.lookup(db);
-        let item_tree = loc.id.item_tree(db);
 
         let module = loc.container.module(db);
-        let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into());
+        let attrs = db.attrs(id.into());
         let mut flags = ConstFlags::empty();
         if attrs.by_key(sym::rustc_allow_incoherent_impl).exists() {
             flags |= ConstFlags::RUSTC_ALLOW_INCOHERENT_IMPL;
@@ -253,14 +264,14 @@ impl ConstSignature {
         }
 
         let (store, source_map, type_ref) =
-            crate::expr_store::lower::lower_type_ref(db, module, source.map(|it| it.ty()));
+            crate::expr_store::lower::lower_type_ref(db, module, source.as_ref().map(|it| it.ty()));
 
         (
             Arc::new(ConstSignature {
                 store: Arc::new(store),
                 type_ref,
                 flags,
-                name: item_tree[loc.id.value].name.clone(),
+                name: source.value.name().map(|it| it.as_name()),
             }),
             Arc::new(source_map),
         )
@@ -295,10 +306,9 @@ pub struct StaticSignature {
 impl StaticSignature {
     pub fn query(db: &dyn DefDatabase, id: StaticId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
         let loc = id.lookup(db);
-        let item_tree = loc.id.item_tree(db);
 
         let module = loc.container.module(db);
-        let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into());
+        let attrs = db.attrs(id.into());
         let mut flags = StaticFlags::empty();
         if attrs.by_key(sym::rustc_allow_incoherent_impl).exists() {
             flags |= StaticFlags::RUSTC_ALLOW_INCOHERENT_IMPL;
@@ -323,14 +333,14 @@ impl StaticSignature {
         }
 
         let (store, source_map, type_ref) =
-            crate::expr_store::lower::lower_type_ref(db, module, source.map(|it| it.ty()));
+            crate::expr_store::lower::lower_type_ref(db, module, source.as_ref().map(|it| it.ty()));
 
         (
             Arc::new(StaticSignature {
                 store: Arc::new(store),
                 type_ref,
                 flags,
-                name: item_tree[loc.id.value].name.clone(),
+                name: as_name_opt(source.value.name()),
             }),
             Arc::new(source_map),
         )
@@ -407,10 +417,9 @@ pub struct TraitSignature {
 impl TraitSignature {
     pub fn query(db: &dyn DefDatabase, id: TraitId) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
         let loc = id.lookup(db);
-        let item_tree = loc.id.item_tree(db);
 
         let mut flags = TraitFlags::empty();
-        let attrs = item_tree.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into());
+        let attrs = db.attrs(id.into());
         let source = loc.source(db);
         if source.value.auto_token().is_some() {
             flags.insert(TraitFlags::AUTO);
@@ -446,15 +455,11 @@ impl TraitSignature {
             flags |= TraitFlags::SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH;
         }
 
+        let name = as_name_opt(source.value.name());
         let (store, source_map, generic_params) = lower_trait(db, loc.container, source, id);
 
         (
-            Arc::new(TraitSignature {
-                store: Arc::new(store),
-                generic_params,
-                flags,
-                name: item_tree[loc.id.value].name.clone(),
-            }),
+            Arc::new(TraitSignature { store: Arc::new(store), generic_params, flags, name }),
             Arc::new(source_map),
         )
     }
@@ -473,17 +478,13 @@ impl TraitAliasSignature {
         id: TraitAliasId,
     ) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
         let loc = id.lookup(db);
-        let item_tree = loc.id.item_tree(db);
 
         let source = loc.source(db);
+        let name = as_name_opt(source.value.name());
         let (store, source_map, generic_params) = lower_trait_alias(db, loc.container, source, id);
 
         (
-            Arc::new(TraitAliasSignature {
-                generic_params,
-                store: Arc::new(store),
-                name: item_tree[loc.id.value].name.clone(),
-            }),
+            Arc::new(TraitAliasSignature { generic_params, store: Arc::new(store), name }),
             Arc::new(source_map),
         )
     }
@@ -530,10 +531,9 @@ impl FunctionSignature {
     ) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
         let loc = id.lookup(db);
         let module = loc.container.module(db);
-        let item_tree = loc.id.item_tree(db);
 
         let mut flags = FnFlags::empty();
-        let attrs = item_tree.attrs(db, module.krate, ModItem::from(loc.id.value).into());
+        let attrs = db.attrs(id.into());
         if attrs.by_key(sym::rustc_allow_incoherent_impl).exists() {
             flags.insert(FnFlags::RUSTC_ALLOW_INCOHERENT_IMPL);
         }
@@ -568,6 +568,7 @@ impl FunctionSignature {
             flags.insert(FnFlags::HAS_BODY);
         }
 
+        let name = as_name_opt(source.value.name());
         let abi = source.value.abi().map(|abi| {
             abi.abi_string().map_or_else(|| sym::C, |it| Symbol::intern(it.text_without_quotes()))
         });
@@ -588,7 +589,7 @@ impl FunctionSignature {
                 abi,
                 flags,
                 legacy_const_generics_indices,
-                name: item_tree[loc.id.value].name.clone(),
+                name,
             }),
             Arc::new(source_map),
         )
@@ -662,14 +663,9 @@ impl TypeAliasSignature {
         id: TypeAliasId,
     ) -> (Arc<Self>, Arc<ExpressionStoreSourceMap>) {
         let loc = id.lookup(db);
-        let item_tree = loc.id.item_tree(db);
 
         let mut flags = TypeAliasFlags::empty();
-        let attrs = item_tree.attrs(
-            db,
-            loc.container.module(db).krate(),
-            ModItem::from(loc.id.value).into(),
-        );
+        let attrs = db.attrs(id.into());
         if attrs.by_key(sym::rustc_has_incoherent_inherent_impls).exists() {
             flags.insert(TypeAliasFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPL);
         }
@@ -680,6 +676,7 @@ impl TypeAliasSignature {
             flags.insert(TypeAliasFlags::IS_EXTERN);
         }
         let source = loc.source(db);
+        let name = as_name_opt(source.value.name());
         let (store, source_map, generic_params, bounds, ty) =
             lower_type_alias(db, loc.container.module(db), source, id);
 
@@ -689,7 +686,7 @@ impl TypeAliasSignature {
                 generic_params,
                 flags,
                 bounds,
-                name: item_tree[loc.id.value].name.clone(),
+                name,
                 ty,
             }),
             Arc::new(source_map),
@@ -743,104 +740,41 @@ impl VariantFields {
         let (shape, (fields, store, source_map)) = match id {
             VariantId::EnumVariantId(id) => {
                 let loc = id.lookup(db);
-                let item_tree = loc.id.item_tree(db);
                 let parent = loc.parent.lookup(db);
-                let variant = &item_tree[loc.id.value];
-                (
-                    variant.shape,
-                    lower_fields(
-                        db,
-                        parent.container,
-                        &item_tree,
-                        FieldParent::EnumVariant(loc.id.value),
-                        loc.source(db).map(|src| {
-                            variant.fields.iter().zip(
-                                src.field_list()
-                                    .map(|it| {
-                                        match it {
-                                            ast::FieldList::RecordFieldList(record_field_list) => {
-                                                Either::Left(record_field_list.fields().map(|it| {
-                                                    (SyntaxNodePtr::new(it.syntax()), it.ty())
-                                                }))
-                                            }
-                                            ast::FieldList::TupleFieldList(field_list) => {
-                                                Either::Right(field_list.fields().map(|it| {
-                                                    (SyntaxNodePtr::new(it.syntax()), it.ty())
-                                                }))
-                                            }
-                                        }
-                                        .into_iter()
-                                    })
-                                    .into_iter()
-                                    .flatten(),
-                            )
-                        }),
-                        Some(item_tree[parent.id.value].visibility),
-                    ),
-                )
+                let source = loc.source(db);
+                let shape = adt_shape(source.value.kind());
+                let span_map = db.span_map(source.file_id);
+                let override_visibility = visibility_from_ast(
+                    db,
+                    source.value.parent_enum().visibility(),
+                    &mut |range| span_map.span_for_range(range).ctx,
+                );
+                let fields = lower_field_list(
+                    db,
+                    parent.container,
+                    source.map(|src| src.field_list()),
+                    Some(override_visibility),
+                );
+                (shape, fields)
             }
             VariantId::StructId(id) => {
                 let loc = id.lookup(db);
-                let item_tree = loc.id.item_tree(db);
-                let strukt = &item_tree[loc.id.value];
-                (
-                    strukt.shape,
-                    lower_fields(
-                        db,
-                        loc.container,
-                        &item_tree,
-                        FieldParent::Struct(loc.id.value),
-                        loc.source(db).map(|src| {
-                            strukt.fields.iter().zip(
-                                src.field_list()
-                                    .map(|it| {
-                                        match it {
-                                            ast::FieldList::RecordFieldList(record_field_list) => {
-                                                Either::Left(record_field_list.fields().map(|it| {
-                                                    (SyntaxNodePtr::new(it.syntax()), it.ty())
-                                                }))
-                                            }
-                                            ast::FieldList::TupleFieldList(field_list) => {
-                                                Either::Right(field_list.fields().map(|it| {
-                                                    (SyntaxNodePtr::new(it.syntax()), it.ty())
-                                                }))
-                                            }
-                                        }
-                                        .into_iter()
-                                    })
-                                    .into_iter()
-                                    .flatten(),
-                            )
-                        }),
-                        None,
-                    ),
-                )
+                let source = loc.source(db);
+                let shape = adt_shape(source.value.kind());
+                let fields =
+                    lower_field_list(db, loc.container, source.map(|src| src.field_list()), None);
+                (shape, fields)
             }
             VariantId::UnionId(id) => {
                 let loc = id.lookup(db);
-                let item_tree = loc.id.item_tree(db);
-                let union = &item_tree[loc.id.value];
-                (
-                    FieldsShape::Record,
-                    lower_fields(
-                        db,
-                        loc.container,
-                        &item_tree,
-                        FieldParent::Union(loc.id.value),
-                        loc.source(db).map(|src| {
-                            union.fields.iter().zip(
-                                src.record_field_list()
-                                    .map(|it| {
-                                        it.fields()
-                                            .map(|it| (SyntaxNodePtr::new(it.syntax()), it.ty()))
-                                    })
-                                    .into_iter()
-                                    .flatten(),
-                            )
-                        }),
-                        None,
-                    ),
-                )
+                let source = loc.source(db);
+                let fields = lower_field_list(
+                    db,
+                    loc.container,
+                    source.map(|src| src.record_field_list().map(ast::FieldList::RecordFieldList)),
+                    None,
+                );
+                (FieldsShape::Record, fields)
             }
         };
 
@@ -860,39 +794,81 @@ impl VariantFields {
     }
 }
 
-fn lower_fields<'a>(
+fn lower_field_list(
     db: &dyn DefDatabase,
     module: ModuleId,
-    item_tree: &ItemTree,
-    parent: FieldParent,
-    fields: InFile<impl Iterator<Item = (&'a Field, (SyntaxNodePtr, Option<ast::Type>))>>,
-    override_visibility: Option<RawVisibilityId>,
+    fields: InFile<Option<ast::FieldList>>,
+    override_visibility: Option<RawVisibility>,
+) -> (Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap) {
+    let file_id = fields.file_id;
+    match fields.value {
+        Some(ast::FieldList::RecordFieldList(fields)) => lower_fields(
+            db,
+            module,
+            InFile::new(file_id, fields.fields().map(|field| (field.ty(), field))),
+            |_, field| as_name_opt(field.name()),
+            override_visibility,
+        ),
+        Some(ast::FieldList::TupleFieldList(fields)) => lower_fields(
+            db,
+            module,
+            InFile::new(file_id, fields.fields().map(|field| (field.ty(), field))),
+            |idx, _| Name::new_tuple_field(idx),
+            override_visibility,
+        ),
+        None => lower_fields(
+            db,
+            module,
+            InFile::new(file_id, std::iter::empty::<(Option<ast::Type>, ast::RecordField)>()),
+            |_, _| Name::missing(),
+            None,
+        ),
+    }
+}
+
+fn lower_fields<Field: ast::HasAttrs + ast::HasVisibility>(
+    db: &dyn DefDatabase,
+    module: ModuleId,
+    fields: InFile<impl Iterator<Item = (Option<ast::Type>, Field)>>,
+    mut field_name: impl FnMut(usize, &Field) -> Name,
+    override_visibility: Option<RawVisibility>,
 ) -> (Arena<FieldData>, ExpressionStore, ExpressionStoreSourceMap) {
     let mut arena = Arena::new();
     let cfg_options = module.krate.cfg_options(db);
     let mut col = ExprCollector::new(db, module, fields.file_id);
-    for (idx, (field, (ptr, ty))) in fields.value.enumerate() {
-        let attr_owner = AttrOwner::make_field_indexed(parent, idx);
-        let attrs = item_tree.attrs(db, module.krate, attr_owner);
-        if attrs.is_cfg_enabled(cfg_options) {
-            arena.alloc(FieldData {
-                name: field.name.clone(),
-                type_ref: col
-                    .lower_type_ref_opt(ty, &mut ExprCollector::impl_trait_error_allocator),
-                visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(),
-                is_unsafe: field.is_unsafe,
-            });
-        } else {
-            col.source_map.diagnostics.push(
-                crate::expr_store::ExpressionStoreDiagnostics::InactiveCode {
-                    node: InFile::new(fields.file_id, ptr),
-                    cfg: attrs.cfg().unwrap(),
-                    opts: cfg_options.clone(),
-                },
-            );
+    let mut idx = 0;
+    for (ty, field) in fields.value {
+        match Attrs::is_cfg_enabled_for(db, &field, col.span_map(), cfg_options) {
+            Ok(()) => {
+                let type_ref =
+                    col.lower_type_ref_opt(ty, &mut ExprCollector::impl_trait_error_allocator);
+                let visibility = override_visibility.clone().unwrap_or_else(|| {
+                    visibility_from_ast(db, field.visibility(), &mut |range| {
+                        col.span_map().span_for_range(range).ctx
+                    })
+                });
+                let is_unsafe = field
+                    .syntax()
+                    .children_with_tokens()
+                    .filter_map(NodeOrToken::into_token)
+                    .any(|token| token.kind() == T![unsafe]);
+                let name = field_name(idx, &field);
+                arena.alloc(FieldData { name, type_ref, visibility, is_unsafe });
+                idx += 1;
+            }
+            Err(cfg) => {
+                col.source_map.diagnostics.push(
+                    crate::expr_store::ExpressionStoreDiagnostics::InactiveCode {
+                        node: InFile::new(fields.file_id, SyntaxNodePtr::new(field.syntax())),
+                        cfg,
+                        opts: cfg_options.clone(),
+                    },
+                );
+            }
         }
     }
     let store = col.store.finish();
+    arena.shrink_to_fit();
     (arena, store, col.source_map)
 }
 
@@ -905,56 +881,71 @@ pub struct InactiveEnumVariantCode {
 
 #[derive(Debug, Clone, PartialEq, Eq)]
 pub struct EnumVariants {
-    pub variants: Box<[(EnumVariantId, Name)]>,
+    pub variants: Box<[(EnumVariantId, Name, FieldsShape)]>,
 }
 
+#[salsa::tracked]
 impl EnumVariants {
-    pub(crate) fn enum_variants_query(
+    #[salsa::tracked(returns(ref))]
+    pub(crate) fn of(
         db: &dyn DefDatabase,
         e: EnumId,
-    ) -> (Arc<EnumVariants>, Option<Arc<ThinVec<InactiveEnumVariantCode>>>) {
+    ) -> (EnumVariants, Option<ThinVec<InactiveEnumVariantCode>>) {
         let loc = e.lookup(db);
-        let item_tree = loc.id.item_tree(db);
+        let source = loc.source(db);
+        let ast_id_map = db.ast_id_map(source.file_id);
+        let span_map = db.span_map(source.file_id);
 
         let mut diagnostics = ThinVec::new();
         let cfg_options = loc.container.krate.cfg_options(db);
         let mut index = 0;
-        let variants = FileItemTreeId::range_iter(item_tree[loc.id.value].variants.clone())
+        let Some(variants) = source.value.variant_list() else {
+            return (EnumVariants { variants: Box::default() }, None);
+        };
+        let variants = variants
+            .variants()
             .filter_map(|variant| {
-                let attrs = item_tree.attrs(db, loc.container.krate, variant.into());
-                if attrs.is_cfg_enabled(cfg_options) {
-                    let enum_variant = EnumVariantLoc {
-                        id: ItemTreeId::new(loc.id.tree_id(), variant),
-                        parent: e,
-                        index,
+                let ast_id = ast_id_map.ast_id(&variant);
+                match Attrs::is_cfg_enabled_for(db, &variant, span_map.as_ref(), cfg_options) {
+                    Ok(()) => {
+                        let enum_variant =
+                            EnumVariantLoc { id: source.with_value(ast_id), parent: e, index }
+                                .intern(db);
+                        index += 1;
+                        let name = as_name_opt(variant.name());
+                        let shape = adt_shape(variant.kind());
+                        Some((enum_variant, name, shape))
+                    }
+                    Err(cfg) => {
+                        diagnostics.push(InactiveEnumVariantCode {
+                            ast_id,
+                            cfg,
+                            opts: cfg_options.clone(),
+                        });
+                        None
                     }
-                    .intern(db);
-                    index += 1;
-                    Some((enum_variant, item_tree[variant].name.clone()))
-                } else {
-                    diagnostics.push(InactiveEnumVariantCode {
-                        ast_id: item_tree[variant].ast_id,
-                        cfg: attrs.cfg().unwrap(),
-                        opts: cfg_options.clone(),
-                    });
-                    None
                 }
             })
             .collect();
 
-        (
-            Arc::new(EnumVariants { variants }),
-            diagnostics.is_empty().not().then(|| Arc::new(diagnostics)),
-        )
+        (EnumVariants { variants }, diagnostics.is_empty().not().then_some(diagnostics))
     }
+}
 
+impl EnumVariants {
     pub fn variant(&self, name: &Name) -> Option<EnumVariantId> {
-        self.variants.iter().find_map(|(v, n)| if n == name { Some(*v) } else { None })
+        self.variants.iter().find_map(|(v, n, _)| if n == name { Some(*v) } else { None })
+    }
+
+    pub fn variant_name_by_id(&self, variant_id: EnumVariantId) -> Option<Name> {
+        self.variants
+            .iter()
+            .find_map(|(id, name, _)| if *id == variant_id { Some(name.clone()) } else { None })
     }
 
     // [Adopted from rustc](https://github.com/rust-lang/rust/blob/bd53aa3bf7a24a70d763182303bd75e5fc51a9af/compiler/rustc_middle/src/ty/adt.rs#L446-L448)
     pub fn is_payload_free(&self, db: &dyn DefDatabase) -> bool {
-        self.variants.iter().all(|&(v, _)| {
+        self.variants.iter().all(|&(v, _, _)| {
             // The condition check order is slightly modified from rustc
             // to improve performance by early returning with relatively fast checks
             let variant = &db.variant_fields(v.into());
@@ -973,3 +964,17 @@ impl EnumVariants {
         })
     }
 }
+
+pub(crate) fn extern_block_abi(
+    db: &dyn DefDatabase,
+    extern_block: ExternBlockId,
+) -> Option<Symbol> {
+    let source = extern_block.lookup(db).source(db);
+    source.value.abi().map(|abi| {
+        match abi.abi_string() {
+            Some(tok) => Symbol::intern(tok.text_without_quotes()),
+            // `extern` default to be `extern "C"`.
+            _ => sym::C,
+        }
+    })
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/src.rs b/src/tools/rust-analyzer/crates/hir-def/src/src.rs
index 3867f39b8b1..aa373a27b0d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/src.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/src.rs
@@ -1,15 +1,13 @@
 //! Utilities for mapping between hir IDs and the surface syntax.
 
 use either::Either;
-use hir_expand::InFile;
-use la_arena::ArenaMap;
+use hir_expand::{AstId, InFile};
+use la_arena::{Arena, ArenaMap, Idx};
 use syntax::{AstNode, AstPtr, ast};
 
 use crate::{
-    GenericDefId, ItemTreeLoc, LocalFieldId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup,
-    UseId, VariantId,
-    db::DefDatabase,
-    item_tree::{AttrOwner, FieldParent, ItemTreeNode},
+    AstIdLoc, GenericDefId, LocalFieldId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup,
+    UseId, VariantId, attr::Attrs, db::DefDatabase,
 };
 
 pub trait HasSource {
@@ -23,18 +21,13 @@ pub trait HasSource {
 
 impl<T> HasSource for T
 where
-    T: ItemTreeLoc,
-    T::Id: ItemTreeNode,
+    T: AstIdLoc,
 {
-    type Value = <T::Id as ItemTreeNode>::Source;
+    type Value = T::Ast;
     fn ast_ptr(&self, db: &dyn DefDatabase) -> InFile<AstPtr<Self::Value>> {
-        let id = self.item_tree_id();
-        let file_id = id.file_id();
-        let tree = id.item_tree(db);
-        let ast_id_map = db.ast_id_map(file_id);
-        let node = &tree[id.value];
-
-        InFile::new(file_id, ast_id_map.get(node.ast_id()))
+        let id = self.ast_id();
+        let ast_id_map = db.ast_id_map(id.file_id);
+        InFile::new(id.file_id, ast_id_map.get(id.value))
     }
 }
 
@@ -43,18 +36,37 @@ pub trait HasChildSource<ChildId> {
     fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<ChildId, Self::Value>>;
 }
 
+/// Maps a `UseTree` contained in this import back to its AST node.
+pub fn use_tree_to_ast(
+    db: &dyn DefDatabase,
+    use_ast_id: AstId<ast::Use>,
+    index: Idx<ast::UseTree>,
+) -> ast::UseTree {
+    use_tree_source_map(db, use_ast_id)[index].clone()
+}
+
+/// Maps a `UseTree` contained in this import back to its AST node.
+fn use_tree_source_map(db: &dyn DefDatabase, use_ast_id: AstId<ast::Use>) -> Arena<ast::UseTree> {
+    // Re-lower the AST item and get the source map.
+    // Note: The AST unwraps are fine, since if they fail we should have never obtained `index`.
+    let ast = use_ast_id.to_node(db);
+    let ast_use_tree = ast.use_tree().expect("missing `use_tree`");
+    let mut span_map = None;
+    crate::item_tree::lower_use_tree(db, ast_use_tree, &mut |range| {
+        span_map.get_or_insert_with(|| db.span_map(use_ast_id.file_id)).span_for_range(range).ctx
+    })
+    .expect("failed to lower use tree")
+    .1
+}
+
 impl HasChildSource<la_arena::Idx<ast::UseTree>> for UseId {
     type Value = ast::UseTree;
     fn child_source(
         &self,
         db: &dyn DefDatabase,
     ) -> InFile<ArenaMap<la_arena::Idx<ast::UseTree>, Self::Value>> {
-        let loc = &self.lookup(db);
-        let use_ = &loc.id.item_tree(db)[loc.id.value];
-        InFile::new(
-            loc.id.file_id(),
-            use_.use_tree_source_map(db, loc.id.file_id()).into_iter().collect(),
-        )
+        let loc = self.lookup(db);
+        InFile::new(loc.id.file_id, use_tree_source_map(db, loc.id).into_iter().collect())
     }
 }
 
@@ -124,49 +136,30 @@ impl HasChildSource<LocalFieldId> for VariantId {
     type Value = Either<ast::TupleField, ast::RecordField>;
 
     fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<LocalFieldId, Self::Value>> {
-        let item_tree;
-        let (src, parent, container) = match *self {
+        let (src, container) = match *self {
             VariantId::EnumVariantId(it) => {
                 let lookup = it.lookup(db);
-                item_tree = lookup.id.item_tree(db);
-                (
-                    lookup.source(db).map(|it| it.kind()),
-                    FieldParent::EnumVariant(lookup.id.value),
-                    lookup.parent.lookup(db).container,
-                )
+                (lookup.source(db).map(|it| it.kind()), lookup.parent.lookup(db).container)
             }
             VariantId::StructId(it) => {
                 let lookup = it.lookup(db);
-                item_tree = lookup.id.item_tree(db);
-                (
-                    lookup.source(db).map(|it| it.kind()),
-                    FieldParent::Struct(lookup.id.value),
-                    lookup.container,
-                )
+                (lookup.source(db).map(|it| it.kind()), lookup.container)
             }
             VariantId::UnionId(it) => {
                 let lookup = it.lookup(db);
-                item_tree = lookup.id.item_tree(db);
-                (
-                    lookup.source(db).map(|it| it.kind()),
-                    FieldParent::Union(lookup.id.value),
-                    lookup.container,
-                )
+                (lookup.source(db).map(|it| it.kind()), lookup.container)
             }
         };
-
+        let span_map = db.span_map(src.file_id);
         let mut map = ArenaMap::new();
         match &src.value {
             ast::StructKind::Tuple(fl) => {
                 let cfg_options = container.krate.cfg_options(db);
                 let mut idx = 0;
-                for (i, fd) in fl.fields().enumerate() {
-                    let attrs = item_tree.attrs(
-                        db,
-                        container.krate,
-                        AttrOwner::make_field_indexed(parent, i),
-                    );
-                    if !attrs.is_cfg_enabled(cfg_options) {
+                for fd in fl.fields() {
+                    let enabled =
+                        Attrs::is_cfg_enabled_for(db, &fd, span_map.as_ref(), cfg_options).is_ok();
+                    if !enabled {
                         continue;
                     }
                     map.insert(
@@ -179,13 +172,10 @@ impl HasChildSource<LocalFieldId> for VariantId {
             ast::StructKind::Record(fl) => {
                 let cfg_options = container.krate.cfg_options(db);
                 let mut idx = 0;
-                for (i, fd) in fl.fields().enumerate() {
-                    let attrs = item_tree.attrs(
-                        db,
-                        container.krate,
-                        AttrOwner::make_field_indexed(parent, i),
-                    );
-                    if !attrs.is_cfg_enabled(cfg_options) {
+                for fd in fl.fields() {
+                    let enabled =
+                        Attrs::is_cfg_enabled_for(db, &fd, span_map.as_ref(), cfg_options).is_ok();
+                    if !enabled {
                         continue;
                     }
                     map.insert(
@@ -195,7 +185,7 @@ impl HasChildSource<LocalFieldId> for VariantId {
                     idx += 1;
                 }
             }
-            _ => (),
+            ast::StructKind::Unit => (),
         }
         InFile::new(src.file_id, map)
     }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
index 3c67ee9fe5b..2514e88864f 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
@@ -2,16 +2,15 @@
 
 use std::iter;
 
-use hir_expand::Lookup;
+use base_db::Crate;
+use hir_expand::{InFile, Lookup};
 use la_arena::ArenaMap;
+use syntax::ast::{self, HasVisibility};
 use triomphe::Arc;
 
 use crate::{
-    ConstId, FunctionId, HasModule, ItemContainerId, ItemLoc, ItemTreeLoc, LocalFieldId,
-    LocalModuleId, ModuleId, TraitId, TypeAliasId, VariantId,
-    db::DefDatabase,
-    nameres::DefMap,
-    resolver::{HasResolver, Resolver},
+    AssocItemId, HasModule, ItemContainerId, LocalFieldId, LocalModuleId, ModuleId, TraitId,
+    VariantId, db::DefDatabase, nameres::DefMap, resolver::HasResolver, src::HasSource,
 };
 
 pub use crate::item_tree::{RawVisibility, VisibilityExplicitness};
@@ -21,6 +20,8 @@ pub use crate::item_tree::{RawVisibility, VisibilityExplicitness};
 pub enum Visibility {
     /// Visibility is restricted to a certain module.
     Module(ModuleId, VisibilityExplicitness),
+    /// Visibility is restricted to the crate.
+    PubCrate(Crate),
     /// Visibility is unrestricted.
     Public,
 }
@@ -43,8 +44,13 @@ impl Visibility {
     pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> bool {
         let to_module = match self {
             Visibility::Module(m, _) => m,
+            Visibility::PubCrate(krate) => return from_module.krate == krate,
             Visibility::Public => return true,
         };
+        if from_module == to_module {
+            // if the modules are the same, visibility is trivially satisfied
+            return true;
+        }
         // if they're not in the same crate, it can't be visible
         if from_module.krate != to_module.krate {
             return false;
@@ -61,12 +67,18 @@ impl Visibility {
     ) -> bool {
         let to_module = match self {
             Visibility::Module(m, _) => m,
+            Visibility::PubCrate(krate) => return def_map.krate() == krate,
             Visibility::Public => return true,
         };
         // if they're not in the same crate, it can't be visible
         if def_map.krate() != to_module.krate {
             return false;
         }
+
+        if from_module == to_module.local_id && def_map.block_id() == to_module.block {
+            // if the modules are the same, visibility is trivially satisfied
+            return true;
+        }
         Self::is_visible_from_def_map_(db, def_map, to_module, from_module)
     }
 
@@ -90,9 +102,7 @@ impl Visibility {
                 // `to_module` is not a block, so there is no parent def map to use.
                 (None, _) => (),
                 // `to_module` is at `def_map`'s block, no need to move further.
-                (Some(a), Some(b)) if a == b => {
-                    cov_mark::hit!(is_visible_from_same_block_def_map);
-                }
+                (Some(a), Some(b)) if a == b => {}
                 _ => {
                     if let Some(parent) = to_module.def_map(db).parent() {
                         to_module = parent;
@@ -134,26 +144,56 @@ impl Visibility {
     pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> {
         match (self, other) {
             (_, Visibility::Public) | (Visibility::Public, _) => Some(Visibility::Public),
+            (Visibility::PubCrate(krate), Visibility::PubCrate(krateb)) => {
+                if krate == krateb {
+                    Some(Visibility::PubCrate(krate))
+                } else {
+                    None
+                }
+            }
+            (Visibility::Module(mod_, _), Visibility::PubCrate(krate))
+            | (Visibility::PubCrate(krate), Visibility::Module(mod_, _)) => {
+                if mod_.krate == krate {
+                    Some(Visibility::PubCrate(krate))
+                } else {
+                    None
+                }
+            }
             (Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => {
-                if mod_a.krate != mod_b.krate {
+                if mod_a == mod_b {
+                    // Most module visibilities are `pub(self)`, and assuming no errors
+                    // this will be the common and thus fast path.
+                    return Some(Visibility::Module(
+                        mod_a,
+                        match (expl_a, expl_b) {
+                            (VisibilityExplicitness::Explicit, _)
+                            | (_, VisibilityExplicitness::Explicit) => {
+                                VisibilityExplicitness::Explicit
+                            }
+                            _ => VisibilityExplicitness::Implicit,
+                        },
+                    ));
+                }
+
+                if mod_a.krate() != def_map.krate() || mod_b.krate() != def_map.krate() {
                     return None;
                 }
 
                 let def_block = def_map.block_id();
-                if (mod_a.containing_block(), mod_b.containing_block()) != (def_block, def_block) {
+                if mod_a.containing_block() != def_block || mod_b.containing_block() != def_block {
                     return None;
                 }
 
                 let mut a_ancestors =
                     iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent);
-                let mut b_ancestors =
-                    iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent);
 
                 if a_ancestors.any(|m| m == mod_b.local_id) {
                     // B is above A
                     return Some(Visibility::Module(mod_b, expl_b));
                 }
 
+                let mut b_ancestors =
+                    iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent);
                 if b_ancestors.any(|m| m == mod_a.local_id) {
                     // A is above B
                     return Some(Visibility::Module(mod_a, expl_a));
@@ -171,26 +211,52 @@ impl Visibility {
     pub(crate) fn min(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> {
         match (self, other) {
             (vis, Visibility::Public) | (Visibility::Public, vis) => Some(vis),
+            (Visibility::PubCrate(krate), Visibility::PubCrate(krateb)) => {
+                if krate == krateb {
+                    Some(Visibility::PubCrate(krate))
+                } else {
+                    None
+                }
+            }
+            (Visibility::Module(mod_, exp), Visibility::PubCrate(krate))
+            | (Visibility::PubCrate(krate), Visibility::Module(mod_, exp)) => {
+                if mod_.krate == krate { Some(Visibility::Module(mod_, exp)) } else { None }
+            }
             (Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => {
-                if mod_a.krate != mod_b.krate {
+                if mod_a == mod_b {
+                    // Most module visibilities are `pub(self)`, and assuming no errors
+                    // this will be the common and thus fast path.
+                    return Some(Visibility::Module(
+                        mod_a,
+                        match (expl_a, expl_b) {
+                            (VisibilityExplicitness::Explicit, _)
+                            | (_, VisibilityExplicitness::Explicit) => {
+                                VisibilityExplicitness::Explicit
+                            }
+                            _ => VisibilityExplicitness::Implicit,
+                        },
+                    ));
+                }
+
+                if mod_a.krate() != def_map.krate() || mod_b.krate() != def_map.krate() {
                     return None;
                 }
 
                 let def_block = def_map.block_id();
-                if (mod_a.containing_block(), mod_b.containing_block()) != (def_block, def_block) {
+                if mod_a.containing_block() != def_block || mod_b.containing_block() != def_block {
                     return None;
                 }
 
                 let mut a_ancestors =
                     iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent);
-                let mut b_ancestors =
-                    iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent);
 
                 if a_ancestors.any(|m| m == mod_b.local_id) {
                     // B is above A
                     return Some(Visibility::Module(mod_a, expl_a));
                 }
 
+                let mut b_ancestors =
+                    iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent);
                 if b_ancestors.any(|m| m == mod_a.local_id) {
                     // A is above B
                     return Some(Visibility::Module(mod_b, expl_b));
@@ -217,49 +283,62 @@ pub(crate) fn field_visibilities_query(
     for (field_id, field_data) in fields.iter() {
         res.insert(field_id, Visibility::resolve(db, &resolver, &field_data.visibility));
     }
+    res.shrink_to_fit();
     Arc::new(res)
 }
 
-/// Resolve visibility of a function.
-pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -> Visibility {
-    let resolver = def.resolver(db);
-    let loc = def.lookup(db);
-    let tree = loc.item_tree_id().item_tree(db);
-    if let ItemContainerId::TraitId(trait_id) = loc.container {
-        trait_vis(db, &resolver, trait_id)
-    } else {
-        Visibility::resolve(db, &resolver, &tree[tree[loc.id.value].visibility])
+pub fn visibility_from_ast(
+    db: &dyn DefDatabase,
+    has_resolver: impl HasResolver,
+    ast_vis: InFile<Option<ast::Visibility>>,
+) -> Visibility {
+    let mut span_map = None;
+    let raw_vis = crate::item_tree::visibility_from_ast(db, ast_vis.value, &mut |range| {
+        span_map.get_or_insert_with(|| db.span_map(ast_vis.file_id)).span_for_range(range).ctx
+    });
+    if raw_vis == RawVisibility::Public {
+        return Visibility::Public;
     }
+
+    Visibility::resolve(db, &has_resolver.resolver(db), &raw_vis)
 }
 
-/// Resolve visibility of a const.
-pub(crate) fn const_visibility_query(db: &dyn DefDatabase, def: ConstId) -> Visibility {
-    let resolver = def.resolver(db);
-    let loc = def.lookup(db);
-    let tree = loc.item_tree_id().item_tree(db);
-    if let ItemContainerId::TraitId(trait_id) = loc.container {
-        trait_vis(db, &resolver, trait_id)
-    } else {
-        Visibility::resolve(db, &resolver, &tree[tree[loc.id.value].visibility])
+/// Resolve visibility of a type alias.
+pub(crate) fn assoc_visibility_query(db: &dyn DefDatabase, def: AssocItemId) -> Visibility {
+    match def {
+        AssocItemId::FunctionId(function_id) => {
+            let loc = function_id.lookup(db);
+            trait_item_visibility(db, loc.container).unwrap_or_else(|| {
+                let source = loc.source(db);
+                visibility_from_ast(db, function_id, source.map(|src| src.visibility()))
+            })
+        }
+        AssocItemId::ConstId(const_id) => {
+            let loc = const_id.lookup(db);
+            trait_item_visibility(db, loc.container).unwrap_or_else(|| {
+                let source = loc.source(db);
+                visibility_from_ast(db, const_id, source.map(|src| src.visibility()))
+            })
+        }
+        AssocItemId::TypeAliasId(type_alias_id) => {
+            let loc = type_alias_id.lookup(db);
+            trait_item_visibility(db, loc.container).unwrap_or_else(|| {
+                let source = loc.source(db);
+                visibility_from_ast(db, type_alias_id, source.map(|src| src.visibility()))
+            })
+        }
     }
 }
 
-/// Resolve visibility of a type alias.
-pub(crate) fn type_alias_visibility_query(db: &dyn DefDatabase, def: TypeAliasId) -> Visibility {
-    let resolver = def.resolver(db);
-    let loc = def.lookup(db);
-    let tree = loc.item_tree_id().item_tree(db);
-    if let ItemContainerId::TraitId(trait_id) = loc.container {
-        trait_vis(db, &resolver, trait_id)
-    } else {
-        Visibility::resolve(db, &resolver, &tree[tree[loc.id.value].visibility])
+fn trait_item_visibility(db: &dyn DefDatabase, container: ItemContainerId) -> Option<Visibility> {
+    match container {
+        ItemContainerId::TraitId(trait_) => Some(trait_visibility(db, trait_)),
+        _ => None,
     }
 }
 
-#[inline]
-fn trait_vis(db: &dyn DefDatabase, resolver: &Resolver<'_>, trait_id: TraitId) -> Visibility {
-    let ItemLoc { id: tree_id, .. } = trait_id.lookup(db);
-    let item_tree = tree_id.item_tree(db);
-    let tr_def = &item_tree[tree_id.value];
-    Visibility::resolve(db, resolver, &item_tree[tr_def.visibility])
+fn trait_visibility(db: &dyn DefDatabase, def: TraitId) -> Visibility {
+    let loc = def.lookup(db);
+    let source = loc.source(db);
+    visibility_from_ast(db, def, source.map(|src| src.visibility()))
 }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs
index 62b7b638e7b..d5874f829ba 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs
@@ -277,8 +277,8 @@ mod tests {
         assert_eq!(quoted.to_string(), "hello");
         let t = format!("{quoted:#?}");
         expect![[r#"
-            SUBTREE $$ 937550:0@0..0#ROOT2024 937550:0@0..0#ROOT2024
-              IDENT   hello 937550:0@0..0#ROOT2024"#]]
+            SUBTREE $$ 937550:Root[0000, 0]@0..0#ROOT2024 937550:Root[0000, 0]@0..0#ROOT2024
+              IDENT   hello 937550:Root[0000, 0]@0..0#ROOT2024"#]]
         .assert_eq(&t);
     }
 
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 7cb1b6c0207..7e9928c41ff 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
@@ -13,7 +13,7 @@ use crate::{
     AstId, BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerCallInfo,
     EagerExpander, EditionedFileId, ExpandError, ExpandResult, ExpandTo, HirFileId, MacroCallId,
     MacroCallKind, MacroCallLoc, MacroDefId, MacroDefKind,
-    attrs::{AttrId, collect_attrs},
+    attrs::{AttrId, AttrInput, RawAttrs, collect_attrs},
     builtin::pseudo_derive_attr_expansion,
     cfg_process,
     declarative::DeclarativeMacroExpander,
@@ -60,6 +60,7 @@ pub trait ExpandDatabase: RootQueryDb {
     fn proc_macros_for_crate(&self, krate: Crate) -> Option<Arc<CrateProcMacros>>;
 
     #[salsa::invoke(ast_id_map)]
+    #[salsa::lru(1024)]
     fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;
 
     #[salsa::transparent]
@@ -241,30 +242,36 @@ pub fn expand_speculative(
 
     let attr_arg = match loc.kind {
         MacroCallKind::Attr { invoc_attr_index, .. } => {
-            let attr = if loc.def.is_attribute_derive() {
+            if loc.def.is_attribute_derive() {
                 // for pseudo-derive expansion we actually pass the attribute itself only
-                ast::Attr::cast(speculative_args.clone())
+                ast::Attr::cast(speculative_args.clone()).and_then(|attr| attr.token_tree()).map(
+                    |token_tree| {
+                        let mut tree = syntax_node_to_token_tree(
+                            token_tree.syntax(),
+                            span_map,
+                            span,
+                            DocCommentDesugarMode::ProcMacro,
+                        );
+                        *tree.top_subtree_delimiter_mut() = tt::Delimiter::invisible_spanned(span);
+                        tree
+                    },
+                )
             } else {
                 // Attributes may have an input token tree, build the subtree and map for this as well
                 // then try finding a token id for our token if it is inside this input subtree.
                 let item = ast::Item::cast(speculative_args.clone())?;
-                collect_attrs(&item)
-                    .nth(invoc_attr_index.ast_index())
-                    .and_then(|x| Either::left(x.1))
-            }?;
-            match attr.token_tree() {
-                Some(token_tree) => {
-                    let mut tree = syntax_node_to_token_tree(
-                        token_tree.syntax(),
-                        span_map,
-                        span,
-                        DocCommentDesugarMode::ProcMacro,
-                    );
-                    *tree.top_subtree_delimiter_mut() = tt::Delimiter::invisible_spanned(span);
-
-                    Some(tree)
-                }
-                _ => None,
+                let attrs = RawAttrs::new_expanded(db, &item, span_map, loc.krate.cfg_options(db));
+                attrs.iter().find(|attr| attr.id == invoc_attr_index).and_then(|attr| {
+                    match attr.input.as_deref()? {
+                        AttrInput::TokenTree(tt) => {
+                            let mut attr_arg = tt.clone();
+                            attr_arg.top_subtree_delimiter_mut().kind =
+                                tt::DelimiterKind::Invisible;
+                            Some(attr_arg)
+                        }
+                        AttrInput::Literal(_) => None,
+                    }
+                })
             }
         }
         _ => None,
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs
index 8024823cbc5..a73a22370d2 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs
@@ -106,7 +106,7 @@ impl FileRange {
 /// It is stable across reparses, and can be used as salsa key/value.
 pub type AstId<N> = crate::InFile<FileAstId<N>>;
 
-impl<N: AstIdNode> AstId<N> {
+impl<N: AstNode> AstId<N> {
     pub fn to_node(&self, db: &dyn ExpandDatabase) -> N {
         self.to_ptr(db).to_node(&db.parse_or_expand(self.file_id))
     }
@@ -122,6 +122,13 @@ impl<N: AstIdNode> AstId<N> {
     pub fn erase(&self) -> ErasedAstId {
         crate::InFile::new(self.file_id, self.value.erase())
     }
+    #[inline]
+    pub fn upcast<M: AstIdNode>(self) -> AstId<M>
+    where
+        N: Into<M>,
+    {
+        self.map(|it| it.upcast())
+    }
 }
 
 pub type ErasedAstId = crate::InFile<ErasedFileAstId>;
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs
index 543ac0619dd..385c98ef877 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs
@@ -486,7 +486,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
         rustc_legacy_const_generics, Normal, template!(List: "N"), ErrorFollowing,
         INTERNAL_UNSTABLE
     ),
-    // Do not const-check this function's body. It will always get replaced during CTFE.
+    // Do not const-check this function's body. It will always get replaced during CTFE via `hook_special_const_fn`.
     rustc_attr!(
         rustc_do_not_const_check, Normal, template!(Word), WarnFollowing, INTERNAL_UNSTABLE
     ),
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 1cd975b980d..1c8ebb6f535 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
@@ -34,9 +34,7 @@ pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe + Any {
         current_dir: String,
     ) -> Result<tt::TopSubtree, ProcMacroExpansionError>;
 
-    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
-        other.type_id() == self.type_id()
-    }
+    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool;
 }
 
 impl PartialEq for dyn ProcMacroExpander {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
index efa544cf396..8b65126e7b7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
@@ -31,7 +31,7 @@ la-arena.workspace = true
 triomphe.workspace = true
 typed-arena = "2.0.2"
 indexmap.workspace = true
-rustc_apfloat = "0.2.2"
+rustc_apfloat = "0.2.3"
 query-group.workspace = true
 salsa.workspace = true
 salsa-macros.workspace = true
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 22b96b55cbb..79454428112 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
@@ -63,7 +63,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
     ) -> Option<rust_ir::AssociatedTyValueId<Interner>> {
         let alias_id = from_assoc_type_id(assoc_type_id);
         let trait_sig = self.db.type_alias_signature(alias_id);
-        self.db.impl_items(hir_def::ImplId::from_chalk(self.db, impl_id)).items.iter().find_map(
+        hir_def::ImplId::from_chalk(self.db, impl_id).impl_items(self.db).items.iter().find_map(
             |(name, item)| match item {
                 AssocItemId::TypeAliasId(alias) if &trait_sig.name == name => {
                     Some(TypeAliasAsValue(*alias).to_chalk(self.db))
@@ -261,10 +261,20 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
         &self,
         well_known_trait: WellKnownTrait,
     ) -> Option<chalk_ir::TraitId<Interner>> {
-        let lang_attr = lang_item_from_well_known_trait(well_known_trait);
-        let trait_ = lang_attr.resolve_trait(self.db, self.krate)?;
+        let lang_item = lang_item_from_well_known_trait(well_known_trait);
+        let trait_ = lang_item.resolve_trait(self.db, self.krate)?;
         Some(to_chalk_trait_id(trait_))
     }
+    fn well_known_assoc_type_id(
+        &self,
+        assoc_type: rust_ir::WellKnownAssocType,
+    ) -> Option<chalk_ir::AssocTypeId<Interner>> {
+        let lang_item = match assoc_type {
+            rust_ir::WellKnownAssocType::AsyncFnOnceOutput => LangItem::AsyncFnOnceOutput,
+        };
+        let alias = lang_item.resolve_type_alias(self.db, self.krate)?;
+        Some(to_assoc_type_id(alias))
+    }
 
     fn program_clauses_for_env(
         &self,
@@ -813,11 +823,11 @@ pub(crate) fn adt_datum_query(
             (rust_ir::AdtKind::Struct, vec![variant_id_to_fields(id.into())])
         }
         hir_def::AdtId::EnumId(id) => {
-            let variants = db
-                .enum_variants(id)
+            let variants = id
+                .enum_variants(db)
                 .variants
                 .iter()
-                .map(|&(variant_id, _)| variant_id_to_fields(variant_id.into()))
+                .map(|&(variant_id, _, _)| variant_id_to_fields(variant_id.into()))
                 .collect();
             (rust_ir::AdtKind::Enum, variants)
         }
@@ -870,8 +880,8 @@ fn impl_def_datum(db: &dyn HirDatabase, krate: Crate, impl_id: hir_def::ImplId)
 
     let impl_datum_bound = rust_ir::ImplDatumBound { trait_ref, where_clauses };
     let trait_data = db.trait_items(trait_);
-    let associated_ty_value_ids = db
-        .impl_items(impl_id)
+    let associated_ty_value_ids = impl_id
+        .impl_items(db)
         .items
         .iter()
         .filter_map(|(_, item)| match item {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
index aabc4c4234d..836cc96233e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
@@ -16,7 +16,8 @@ use crate::{
     ClosureId, DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime, ProjectionTy,
     QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyKind, TypeFlags, WhereClause,
     db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
-    from_placeholder_idx, generics::generics, to_chalk_trait_id, utils::ClosureSubst,
+    from_placeholder_idx, generics::generics, mapping::ToChalk, to_chalk_trait_id,
+    utils::ClosureSubst,
 };
 
 pub trait TyExt {
@@ -190,10 +191,9 @@ impl TyExt for Ty {
     fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId> {
         match *self.kind(Interner) {
             TyKind::Adt(AdtId(adt), ..) => Some(adt.into()),
-            TyKind::FnDef(callable, ..) => Some(GenericDefId::from_callable(
-                db,
-                db.lookup_intern_callable_def(callable.into()),
-            )),
+            TyKind::FnDef(callable, ..) => {
+                Some(GenericDefId::from_callable(db, ToChalk::from_chalk(db, callable)))
+            }
             TyKind::AssociatedType(type_alias, ..) => Some(from_assoc_type_id(type_alias).into()),
             TyKind::Foreign(type_alias, ..) => Some(from_foreign_def_id(type_alias).into()),
             _ => None,
@@ -202,7 +202,7 @@ impl TyExt for Ty {
 
     fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId> {
         match self.kind(Interner) {
-            &TyKind::FnDef(def, ..) => Some(db.lookup_intern_callable_def(def.into())),
+            &TyKind::FnDef(def, ..) => Some(ToChalk::from_chalk(db, def)),
             _ => None,
         }
     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
index f903b06d65e..24530a5f67c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
@@ -286,7 +286,7 @@ pub(crate) fn const_eval_discriminant_variant(
         let value = match prev_idx {
             Some(prev_idx) => {
                 1 + db.const_eval_discriminant(
-                    db.enum_variants(loc.parent).variants[prev_idx as usize].0,
+                    loc.parent.enum_variants(db).variants[prev_idx as usize].0,
                 )?
             }
             _ => 0,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs
index ee375d60deb..5e85978e299 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs
@@ -112,16 +112,16 @@ fn size_of_val() {
 }
 
 #[test]
-fn min_align_of_val() {
+fn align_of_val() {
     check_number(
         r#"
         //- minicore: coerce_unsized
         #[rustc_intrinsic]
-        pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize;
+        pub fn align_of_val<T: ?Sized>(_: *const T) -> usize;
 
         struct X(i32, u8);
 
-        const GOAL: usize = min_align_of_val(&X(1, 2));
+        const GOAL: usize = align_of_val(&X(1, 2));
         "#,
         4,
     );
@@ -129,11 +129,11 @@ fn min_align_of_val() {
         r#"
         //- minicore: coerce_unsized
         #[rustc_intrinsic]
-        pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize;
+        pub fn align_of_val<T: ?Sized>(_: *const T) -> usize;
 
         const GOAL: usize = {
             let x: &[i32] = &[1, 2, 3];
-            min_align_of_val(x)
+            align_of_val(x)
         };
         "#,
         4,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
index 1e985dc604e..1029969992c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
@@ -237,9 +237,6 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
 
     // Interned IDs for Chalk integration
     #[salsa::interned]
-    fn intern_callable_def(&self, callable_def: CallableDefId) -> InternedCallableDefId;
-
-    #[salsa::interned]
     fn intern_type_or_const_param_id(
         &self,
         param_id: TypeOrConstParamId,
@@ -347,7 +344,3 @@ impl_intern_key!(InternedClosureId, InternedClosure);
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
 pub struct InternedCoroutine(pub DefWithBodyId, pub ExprId);
 impl_intern_key!(InternedCoroutineId, InternedCoroutine);
-
-// This exists just for Chalk, because Chalk just has a single `FnDefId` where
-// we have different IDs for struct and enum variant constructors.
-impl_intern_key!(InternedCallableDefId, CallableDefId);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
index 099100a7328..1873f12fb7c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
@@ -395,9 +395,9 @@ impl<'a> DeclValidator<'a> {
 
     /// Check incorrect names for enum variants.
     fn validate_enum_variants(&mut self, enum_id: EnumId) {
-        let data = self.db.enum_variants(enum_id);
+        let data = enum_id.enum_variants(self.db);
 
-        for (variant_id, _) in data.variants.iter() {
+        for (variant_id, _, _) in data.variants.iter() {
             self.validate_enum_variant_fields(*variant_id);
         }
 
@@ -405,7 +405,7 @@ impl<'a> DeclValidator<'a> {
         let mut enum_variants_replacements = data
             .variants
             .iter()
-            .filter_map(|(_, name)| {
+            .filter_map(|(_, name, _)| {
                 to_camel_case(&name.display_no_db(edition).to_smolstr()).map(|new_name| {
                     Replacement {
                         current_name: name.clone(),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
index 9eb7ffe1c71..df2eb410b99 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
@@ -642,7 +642,7 @@ fn missing_match_arms<'p>(
     }
 
     let non_empty_enum = match scrut_ty.as_adt() {
-        Some((AdtId::EnumId(e), _)) => !cx.db.enum_variants(e).variants.is_empty(),
+        Some((AdtId::EnumId(e), _)) => !e.enum_variants(cx.db).variants.is_empty(),
         _ => false,
     };
     let display_target = DisplayTarget::from_crate(cx.db, krate);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
index 7df22a45cb4..916876d4ac9 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
@@ -328,7 +328,7 @@ impl HirDisplay for Pat {
                             write!(
                                 f,
                                 "{}",
-                                f.db.enum_variants(loc.parent).variants[loc.index as usize]
+                                loc.parent.enum_variants(f.db).variants[loc.index as usize]
                                     .1
                                     .display(f.db, f.edition())
                             )?;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
index dd82a0f45ca..2873a3e09e7 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
@@ -50,7 +50,7 @@ impl EnumVariantContiguousIndex {
     }
 
     fn to_enum_variant_id(self, db: &dyn HirDatabase, eid: EnumId) -> EnumVariantId {
-        db.enum_variants(eid).variants[self.0].0
+        eid.enum_variants(db).variants[self.0].0
     }
 }
 
@@ -458,14 +458,14 @@ impl PatCx for MatchCheckCtx<'_> {
             TyKind::Scalar(Scalar::Int(..) | Scalar::Uint(..)) => unhandled(),
             TyKind::Array(..) | TyKind::Slice(..) => unhandled(),
             &TyKind::Adt(AdtId(adt @ hir_def::AdtId::EnumId(enum_id)), ref subst) => {
-                let enum_data = cx.db.enum_variants(enum_id);
+                let enum_data = enum_id.enum_variants(cx.db);
                 let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive(adt);
 
                 if enum_data.variants.is_empty() && !is_declared_nonexhaustive {
                     ConstructorSet::NoConstructors
                 } else {
                     let mut variants = IndexVec::with_capacity(enum_data.variants.len());
-                    for &(variant, _) in enum_data.variants.iter() {
+                    for &(variant, _, _) in enum_data.variants.iter() {
                         let is_uninhabited = is_enum_variant_uninhabited_from(
                             cx.db,
                             variant,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index f210dd8799f..1aa7e0fcf88 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -914,7 +914,7 @@ fn render_const_scalar(
                     write!(
                         f,
                         "{}",
-                        f.db.enum_variants(loc.parent).variants[loc.index as usize]
+                        loc.parent.enum_variants(f.db).variants[loc.index as usize]
                             .1
                             .display(f.db, f.edition())
                     )?;
@@ -1208,7 +1208,7 @@ impl HirDisplay for Ty {
                         write!(
                             f,
                             "{}",
-                            db.enum_variants(loc.parent).variants[loc.index as usize]
+                            loc.parent.enum_variants(db).variants[loc.index as usize]
                                 .1
                                 .display(db, f.edition())
                         )?
@@ -2082,6 +2082,7 @@ pub fn write_visibility(
 ) -> Result<(), HirDisplayError> {
     match vis {
         Visibility::Public => write!(f, "pub "),
+        Visibility::PubCrate(_) => write!(f, "pub(crate) "),
         Visibility::Module(vis_id, _) => {
             let def_map = module_id.def_map(f.db);
             let root_module_id = def_map.module_id(DefMap::ROOT);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs
index 70763759ef0..5577be890da 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/drop.rs
@@ -67,11 +67,11 @@ pub(crate) fn has_drop_glue(db: &dyn HirDatabase, ty: Ty, env: Arc<TraitEnvironm
                 }
                 // Unions cannot have fields with destructors.
                 AdtId::UnionId(_) => DropGlue::None,
-                AdtId::EnumId(id) => db
-                    .enum_variants(id)
+                AdtId::EnumId(id) => id
+                    .enum_variants(db)
                     .variants
                     .iter()
-                    .map(|&(variant, _)| {
+                    .map(|&(variant, _, _)| {
                         db.field_types(variant.into())
                             .iter()
                             .map(|(_, field_ty)| {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
index ed8d8dc2624..48094945c11 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
@@ -122,7 +122,7 @@ pub fn dyn_compatibility_of_trait_query(
     res
 }
 
-fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> bool {
+pub fn generics_require_sized_self(db: &dyn HirDatabase, def: GenericDefId) -> bool {
     let krate = def.module(db).krate();
     let Some(sized) = LangItem::Sized.resolve_trait(db, krate) else {
         return false;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
index bb4aaf78895..a3ed39934cd 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
@@ -229,7 +229,7 @@ impl Generics {
     }
 
     /// Returns a Substitution that replaces each parameter by itself (i.e. `Ty::Param`).
-    pub(crate) fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution {
+    pub fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution {
         Substitution::from_iter(
             Interner,
             self.iter_id().map(|id| match id {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index 14eb7160753..80478f19371 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -1673,7 +1673,7 @@ impl<'db> InferenceContext<'db> {
                     // If we can resolve to an enum variant, it takes priority over associated type
                     // of the same name.
                     if let Some((AdtId::EnumId(id), _)) = ty.as_adt() {
-                        let enum_data = self.db.enum_variants(id);
+                        let enum_data = id.enum_variants(self.db);
                         if let Some(variant) = enum_data.variant(current_segment.name) {
                             return if remaining_segments.len() == 1 {
                                 (ty, Some(variant.into()))
@@ -1792,7 +1792,7 @@ impl<'db> InferenceContext<'db> {
                 let segment = path.segments().last().unwrap();
                 // this could be an enum variant or associated type
                 if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() {
-                    let enum_data = self.db.enum_variants(enum_id);
+                    let enum_data = enum_id.enum_variants(self.db);
                     if let Some(variant) = enum_data.variant(segment) {
                         return (ty, Some(variant.into()));
                     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs
index 10d85792c9d..8d345defdc1 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs
@@ -43,7 +43,7 @@ impl CastTy {
                 let (AdtId::EnumId(id), _) = t.as_adt()? else {
                     return None;
                 };
-                let enum_data = table.db.enum_variants(id);
+                let enum_data = id.enum_variants(table.db);
                 if enum_data.is_payload_free(table.db) { Some(Self::Int(Int::CEnum)) } else { None }
             }
             TyKind::Raw(m, ty) => Some(Self::Ptr(ty.clone(), *m)),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
index bd57ca89162..d1432cacf8d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
@@ -1360,7 +1360,7 @@ impl InferenceContext<'_> {
                 if let Some(variant) = self.result.variant_resolution_for_pat(p) {
                     let adt = variant.adt_id(self.db);
                     let is_multivariant = match adt {
-                        hir_def::AdtId::EnumId(e) => self.db.enum_variants(e).variants.len() != 1,
+                        hir_def::AdtId::EnumId(e) => e.enum_variants(self.db).variants.len() != 1,
                         _ => false,
                     };
                     if is_multivariant {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
index 9d4bbe53464..c327c13b664 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs
@@ -397,7 +397,7 @@ impl InferenceContext<'_> {
             Some((AdtId::EnumId(e), subst)) => (e, subst),
             _ => return None,
         };
-        let enum_data = self.db.enum_variants(enum_id);
+        let enum_data = enum_id.enum_variants(self.db);
         let variant = enum_data.variant(name)?;
         self.write_variant_resolution(id, variant.into());
         Some((ValueNs::EnumVariantId(variant), subst.clone()))
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
index e81a5e3c311..79a99321f10 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
@@ -113,9 +113,9 @@ impl UninhabitedFrom<'_> {
             AdtId::UnionId(_) => CONTINUE_OPAQUELY_INHABITED,
             AdtId::StructId(s) => self.visit_variant(s.into(), subst),
             AdtId::EnumId(e) => {
-                let enum_data = self.db.enum_variants(e);
+                let enum_data = e.enum_variants(self.db);
 
-                for &(variant, _) in enum_data.variants.iter() {
+                for &(variant, _, _) in enum_data.variants.iter() {
                     let variant_inhabitedness = self.visit_variant(variant.into(), subst);
                     match variant_inhabitedness {
                         Break(VisiblyUninhabited) => (),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
index 3a020bf050d..dff986fec3c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/adt.rs
@@ -56,11 +56,11 @@ pub fn layout_of_adt_query(
             (r, data.repr.unwrap_or_default(), false)
         }
         AdtId::EnumId(e) => {
-            let variants = db.enum_variants(e);
+            let variants = e.enum_variants(db);
             let r = variants
                 .variants
                 .iter()
-                .map(|&(v, _)| handle_variant(v.into(), &db.variant_fields(v.into())))
+                .map(|&(v, _, _)| handle_variant(v.into(), &db.variant_fields(v.into())))
                 .collect::<Result<SmallVec<_>, _>>()?;
             (r, db.enum_signature(e).repr.unwrap_or_default(), false)
         }
@@ -82,7 +82,7 @@ pub fn layout_of_adt_query(
             |min, max| repr_discr(dl, &repr, min, max).unwrap_or((Integer::I8, false)),
             variants.iter_enumerated().filter_map(|(id, _)| {
                 let AdtId::EnumId(e) = def else { return None };
-                let d = db.const_eval_discriminant(db.enum_variants(e).variants[id.0].0).ok()?;
+                let d = db.const_eval_discriminant(e.enum_variants(db).variants[id.0].0).ok()?;
                 Some((id, d))
             }),
             // FIXME: The current code for niche-filling relies on variant indices
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
index 128569d55dc..148f2a41e7d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -98,7 +98,7 @@ pub use lower::{
     ValueTyDefId, associated_type_shorthand_candidates, diagnostics::*,
 };
 pub use mapping::{
-    from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
+    ToChalk, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
     lt_from_placeholder_idx, lt_to_placeholder_idx, to_assoc_type_id, to_chalk_trait_id,
     to_foreign_def_id, to_placeholder_idx,
 };
@@ -542,7 +542,7 @@ impl CallableSig {
     }
 
     pub fn from_def(db: &dyn HirDatabase, def: FnDefId, substs: &Substitution) -> CallableSig {
-        let callable_def = db.lookup_intern_callable_def(def.into());
+        let callable_def = ToChalk::from_chalk(db, def);
         let sig = db.callable_item_signature(callable_def);
         sig.substitute(Interner, substs)
     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs
index 2abc1ac62a9..6936d8193eb 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mapping.rs
@@ -16,7 +16,7 @@ use crate::{
     PlaceholderIndex, chalk_db, db::HirDatabase,
 };
 
-pub(crate) trait ToChalk {
+pub trait ToChalk {
     type Chalk;
     fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk;
     fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self;
@@ -44,12 +44,12 @@ impl ToChalk for hir_def::ImplId {
 impl ToChalk for CallableDefId {
     type Chalk = FnDefId;
 
-    fn to_chalk(self, db: &dyn HirDatabase) -> FnDefId {
-        db.intern_callable_def(self).into()
+    fn to_chalk(self, _db: &dyn HirDatabase) -> FnDefId {
+        chalk_ir::FnDefId(salsa::plumbing::AsId::as_id(&self))
     }
 
     fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDefId {
-        db.lookup_intern_callable_def(fn_def_id.into())
+        salsa::plumbing::FromIdWithDb::from_id(fn_def_id.0, db.zalsa())
     }
 }
 
@@ -70,18 +70,6 @@ impl ToChalk for TypeAliasAsValue {
     }
 }
 
-impl From<FnDefId> for crate::db::InternedCallableDefId {
-    fn from(fn_def_id: FnDefId) -> Self {
-        Self::from_id(fn_def_id.0)
-    }
-}
-
-impl From<crate::db::InternedCallableDefId> for FnDefId {
-    fn from(callable_def_id: crate::db::InternedCallableDefId) -> Self {
-        chalk_ir::FnDefId(callable_def_id.as_id())
-    }
-}
-
 impl From<OpaqueTyId> for crate::db::InternedOpaqueTyId {
     fn from(id: OpaqueTyId) -> Self {
         FromId::from_id(id.0)
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index 3b295d41e6e..25f1782bdd8 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -790,7 +790,7 @@ fn find_matching_impl(
     mut impls: impl Iterator<Item = ImplId>,
     mut table: InferenceTable<'_>,
     actual_trait_ref: TraitRef,
-) -> Option<(Arc<ImplItems>, Substitution)> {
+) -> Option<(&ImplItems, Substitution)> {
     let db = table.db;
     impls.find_map(|impl_| {
         table.run_in_snapshot(|table| {
@@ -811,7 +811,7 @@ fn find_matching_impl(
             let goal = crate::Goal::all(Interner, wcs);
             table.try_obligation(goal.clone())?;
             table.register_obligation(goal);
-            Some((db.impl_items(impl_), table.resolve_completely(impl_substs)))
+            Some((impl_.impl_items(db), table.resolve_completely(impl_substs)))
         })
     })
 }
@@ -875,7 +875,7 @@ fn is_inherent_impl_coherent(
 
             _ => false,
         };
-        let items = db.impl_items(impl_id);
+        let items = impl_id.impl_items(db);
         rustc_has_incoherent_inherent_impls
             && !items.items.is_empty()
             && items.items.iter().all(|&(_, assoc)| match assoc {
@@ -1462,7 +1462,7 @@ fn iterate_inherent_methods(
         callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
     ) -> ControlFlow<()> {
         for &impl_id in impls.for_self_ty(self_ty) {
-            for &(ref item_name, item) in table.db.impl_items(impl_id).items.iter() {
+            for &(ref item_name, item) in impl_id.impl_items(table.db).items.iter() {
                 let visible = match is_valid_impl_method_candidate(
                     table,
                     self_ty,
@@ -1550,7 +1550,7 @@ fn is_valid_impl_method_candidate(
             check_that!(name.is_none_or(|n| n == item_name));
 
             if let Some(from_module) = visible_from_module {
-                if !db.const_visibility(c).is_visible_from(db, from_module) {
+                if !db.assoc_visibility(c.into()).is_visible_from(db, from_module) {
                     cov_mark::hit!(const_candidate_not_visible);
                     return IsValidCandidate::NotVisible;
                 }
@@ -1639,7 +1639,7 @@ fn is_valid_impl_fn_candidate(
     let data = db.function_signature(fn_id);
 
     if let Some(from_module) = visible_from_module {
-        if !db.function_visibility(fn_id).is_visible_from(db, from_module) {
+        if !db.assoc_visibility(fn_id.into()).is_visible_from(db, from_module) {
             cov_mark::hit!(autoderef_candidate_not_visible);
             return IsValidCandidate::NotVisible;
         }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
index 21e5428520e..a8156ec375b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
@@ -32,7 +32,7 @@ use triomphe::Arc;
 
 use crate::{
     CallableDefId, ClosureId, ComplexMemoryMap, Const, ConstData, ConstScalar, FnDefId, Interner,
-    MemoryMap, Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind,
+    MemoryMap, Substitution, ToChalk, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind,
     consteval::{ConstEvalError, intern_const_scalar, try_const_usize},
     db::{HirDatabase, InternedClosure},
     display::{ClosureStyle, DisplayTarget, HirDisplay},
@@ -1631,7 +1631,7 @@ impl Evaluator<'_> {
             Variants::Empty => unreachable!(),
             Variants::Single { index } => {
                 let r =
-                    self.const_eval_discriminant(self.db.enum_variants(e).variants[index.0].0)?;
+                    self.const_eval_discriminant(e.enum_variants(self.db).variants[index.0].0)?;
                 Ok(r)
             }
             Variants::Multiple { tag, tag_encoding, variants, .. } => {
@@ -1656,7 +1656,7 @@ impl Evaluator<'_> {
                             .unwrap_or(*untagged_variant)
                             .0;
                         let result =
-                            self.const_eval_discriminant(self.db.enum_variants(e).variants[idx].0)?;
+                            self.const_eval_discriminant(e.enum_variants(self.db).variants[idx].0)?;
                         Ok(result)
                     }
                 }
@@ -2771,12 +2771,15 @@ impl Evaluator<'_> {
             Err(e) => {
                 let db = self.db;
                 let loc = variant.lookup(db);
-                let enum_loc = loc.parent.lookup(db);
                 let edition = self.crate_id.data(self.db).edition;
                 let name = format!(
                     "{}::{}",
-                    enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition),
-                    loc.id.item_tree(db)[loc.id.value].name.display(db, edition),
+                    self.db.enum_signature(loc.parent).name.display(db, edition),
+                    loc.parent
+                        .enum_variants(self.db)
+                        .variant_name_by_id(variant)
+                        .unwrap()
+                        .display(db, edition),
                 );
                 Err(MirEvalError::ConstEvalError(name, Box::new(e)))
             }
@@ -2927,7 +2930,7 @@ pub fn render_const_using_debug_impl(
     let a2 = evaluator.heap_allocate(evaluator.ptr_size() * 2, evaluator.ptr_size())?;
     evaluator.write_memory(a2, &data.addr.to_bytes())?;
     let debug_fmt_fn_ptr = evaluator.vtable_map.id(TyKind::FnDef(
-        db.intern_callable_def(debug_fmt_fn.into()).into(),
+        CallableDefId::FunctionId(debug_fmt_fn).to_chalk(db),
         Substitution::from1(Interner, c.data(Interner).ty.clone()),
     )
     .intern(Interner));
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
index 90c52ee96f1..6ebde013344 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
@@ -65,9 +65,7 @@ impl Evaluator<'_> {
                 Some(abi) => *abi == sym::rust_dash_intrinsic,
                 None => match def.lookup(self.db).container {
                     hir_def::ItemContainerId::ExternBlockId(block) => {
-                        let id = block.lookup(self.db).id;
-                        id.item_tree(self.db)[id.value].abi.as_ref()
-                            == Some(&sym::rust_dash_intrinsic)
+                        block.abi(self.db) == Some(sym::rust_dash_intrinsic)
                     }
                     _ => false,
                 },
@@ -86,10 +84,7 @@ impl Evaluator<'_> {
             );
         }
         let is_extern_c = match def.lookup(self.db).container {
-            hir_def::ItemContainerId::ExternBlockId(block) => {
-                let id = block.lookup(self.db).id;
-                id.item_tree(self.db)[id.value].abi.as_ref() == Some(&sym::C)
-            }
+            hir_def::ItemContainerId::ExternBlockId(block) => block.abi(self.db) == Some(sym::C),
             _ => false,
         };
         if is_extern_c {
@@ -764,7 +759,9 @@ impl Evaluator<'_> {
                 let size = self.size_of_sized(ty, locals, "size_of arg")?;
                 destination.write_from_bytes(self, &size.to_le_bytes()[0..destination.size])
             }
-            "min_align_of" | "pref_align_of" => {
+            // FIXME: `min_align_of` was renamed to `align_of` in Rust 1.89
+            // (https://github.com/rust-lang/rust/pull/142410)
+            "min_align_of" | "align_of" => {
                 let Some(ty) =
                     generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner))
                 else {
@@ -796,17 +793,19 @@ impl Evaluator<'_> {
                     destination.write_from_bytes(self, &size.to_le_bytes())
                 }
             }
-            "min_align_of_val" => {
+            // FIXME: `min_align_of_val` was renamed to `align_of_val` in Rust 1.89
+            // (https://github.com/rust-lang/rust/pull/142410)
+            "min_align_of_val" | "align_of_val" => {
                 let Some(ty) =
                     generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner))
                 else {
                     return Err(MirEvalError::InternalError(
-                        "min_align_of_val generic arg is not provided".into(),
+                        "align_of_val generic arg is not provided".into(),
                     ));
                 };
                 let [arg] = args else {
                     return Err(MirEvalError::InternalError(
-                        "min_align_of_val args are not provided".into(),
+                        "align_of_val args are not provided".into(),
                     ));
                 };
                 if let Some((_, align)) = self.size_align_of(ty, locals)? {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
index 99d93515303..71e038b92f0 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
@@ -1922,11 +1922,14 @@ impl<'ctx> MirLowerCtx<'ctx> {
                 let edition = self.edition();
                 let db = self.db;
                 let loc = variant.lookup(db);
-                let enum_loc = loc.parent.lookup(db);
                 let name = format!(
                     "{}::{}",
-                    enum_loc.id.item_tree(db)[enum_loc.id.value].name.display(db, edition),
-                    loc.id.item_tree(db)[loc.id.value].name.display(db, edition),
+                    self.db.enum_signature(loc.parent).name.display(db, edition),
+                    loc.parent
+                        .enum_variants(self.db)
+                        .variant_name_by_id(variant)
+                        .unwrap()
+                        .display(db, edition),
                 );
                 Err(MirLowerError::ConstEvalError(name.into(), Box::new(e)))
             }
@@ -2152,7 +2155,7 @@ pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result<Arc<Mi
             .to_string(),
         DefWithBodyId::VariantId(it) => {
             let loc = it.lookup(db);
-            db.enum_variants(loc.parent).variants[loc.index as usize]
+            loc.parent.enum_variants(db).variants[loc.index as usize]
                 .1
                 .display(db, edition)
                 .to_string()
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
index c22bada7a90..ad664693e29 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
@@ -297,11 +297,8 @@ impl MirLowerCtx<'_> {
         let result_ref = TyKind::Ref(mutability, error_lifetime(), result_ty).intern(Interner);
         let mut result: Place = self.temp(result_ref, current, span)?.into();
         let index_fn_op = Operand::const_zst(
-            TyKind::FnDef(
-                self.db.intern_callable_def(CallableDefId::FunctionId(index_fn.0)).into(),
-                index_fn.1,
-            )
-            .intern(Interner),
+            TyKind::FnDef(CallableDefId::FunctionId(index_fn.0).to_chalk(self.db), index_fn.1)
+                .intern(Interner),
         );
         let Some(current) = self.lower_call(
             index_fn_op,
@@ -357,7 +354,7 @@ impl MirLowerCtx<'_> {
             .ok_or(MirLowerError::LangItemNotFound(trait_lang_item))?;
         let deref_fn_op = Operand::const_zst(
             TyKind::FnDef(
-                self.db.intern_callable_def(CallableDefId::FunctionId(deref_fn)).into(),
+                CallableDefId::FunctionId(deref_fn).to_chalk(self.db),
                 Substitution::from1(Interner, source_ty),
             )
             .intern(Interner),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
index 7ae6e907e7a..8764e48b538 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
@@ -63,16 +63,16 @@ impl MirBody {
             }
             hir_def::DefWithBodyId::VariantId(id) => {
                 let loc = id.lookup(db);
-                let enum_loc = loc.parent.lookup(db);
+                let edition = this.display_target.edition;
                 w!(
                     this,
                     "enum {}::{} = ",
-                    enum_loc.id.item_tree(db)[enum_loc.id.value]
-                        .name
-                        .display(db, this.display_target.edition),
-                    loc.id.item_tree(db)[loc.id.value]
-                        .name
-                        .display(db, this.display_target.edition),
+                    db.enum_signature(loc.parent).name.display(db, edition),
+                    loc.parent
+                        .enum_variants(db)
+                        .variant_name_by_id(id)
+                        .unwrap()
+                        .display(db, edition),
                 )
             }
         });
@@ -336,7 +336,7 @@ impl<'a> MirPrettyCtx<'a> {
                             w!(
                                 this,
                                 " as {}).{}",
-                                this.db.enum_variants(loc.parent).variants[loc.index as usize]
+                                loc.parent.enum_variants(this.db).variants[loc.index as usize]
                                     .1
                                     .display(this.db, this.display_target.edition),
                                 name.display(this.db, this.display_target.edition)
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
index 2b75bd6f160..9ca6ee476c6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
@@ -437,7 +437,7 @@ pub(crate) fn visit_module(
 ) {
     visit_scope(db, crate_def_map, &crate_def_map[module_id].scope, cb);
     for impl_id in crate_def_map[module_id].scope.impls() {
-        let impl_data = db.impl_items(impl_id);
+        let impl_data = impl_id.impl_items(db);
         for &(_, item) in impl_data.items.iter() {
             match item {
                 AssocItemId::FunctionId(it) => {
@@ -479,7 +479,7 @@ pub(crate) fn visit_module(
                     visit_body(db, &body, cb);
                 }
                 ModuleDefId::AdtId(hir_def::AdtId::EnumId(it)) => {
-                    db.enum_variants(it).variants.iter().for_each(|&(it, _)| {
+                    it.enum_variants(db).variants.iter().for_each(|&(it, _, _)| {
                         let body = db.body(it.into());
                         cb(it.into());
                         visit_body(db, &body, cb);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
index e8e3812c69d..905fd8a3bca 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs
@@ -1,5 +1,6 @@
 use base_db::SourceDatabase;
-use hir_def::ModuleDefId;
+use expect_test::Expect;
+use hir_def::{DefWithBodyId, ModuleDefId};
 use test_fixture::WithFixture;
 
 use crate::{db::HirDatabase, test_db::TestDB};
@@ -15,8 +16,9 @@ fn foo() -> i32 {
     $01 + 1
 }",
     );
-    {
-        let events = db.log_executed(|| {
+    execute_assert_events(
+        &db,
+        || {
             let module = db.module_for_file(pos.file_id.file_id(&db));
             let crate_def_map = module.def_map(&db);
             visit_module(&db, crate_def_map, module.local_id, &mut |def| {
@@ -24,9 +26,31 @@ fn foo() -> i32 {
                     db.infer(it.into());
                 }
             });
-        });
-        assert!(format!("{events:?}").contains("infer_shim"))
-    }
+        },
+        &[("infer_shim", 1)],
+        expect_test::expect![[r#"
+            [
+                "source_root_crates_shim",
+                "crate_local_def_map",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "infer_shim",
+                "function_signature_shim",
+                "function_signature_with_source_map_shim",
+                "attrs_shim",
+                "body_shim",
+                "body_with_source_map_shim",
+                "trait_environment_shim",
+                "return_type_impl_traits_shim",
+                "expr_scopes_shim",
+                "lang_item",
+                "crate_lang_items",
+                "lang_item",
+            ]
+        "#]],
+    );
 
     let new_text = "
 fn foo() -> i32 {
@@ -37,8 +61,9 @@ fn foo() -> i32 {
 
     db.set_file_text(pos.file_id.file_id(&db), new_text);
 
-    {
-        let events = db.log_executed(|| {
+    execute_assert_events(
+        &db,
+        || {
             let module = db.module_for_file(pos.file_id.file_id(&db));
             let crate_def_map = module.def_map(&db);
             visit_module(&db, crate_def_map, module.local_id, &mut |def| {
@@ -46,9 +71,22 @@ fn foo() -> i32 {
                     db.infer(it.into());
                 }
             });
-        });
-        assert!(!format!("{events:?}").contains("infer_shim"), "{events:#?}")
-    }
+        },
+        &[("infer_shim", 0)],
+        expect_test::expect![[r#"
+            [
+                "parse_shim",
+                "ast_id_map_shim",
+                "file_item_tree_query",
+                "real_span_map_shim",
+                "attrs_shim",
+                "function_signature_with_source_map_shim",
+                "function_signature_shim",
+                "body_with_source_map_shim",
+                "body_shim",
+            ]
+        "#]],
+    );
 }
 
 #[test]
@@ -66,8 +104,9 @@ fn baz() -> i32 {
     1 + 1
 }",
     );
-    {
-        let events = db.log_executed(|| {
+    execute_assert_events(
+        &db,
+        || {
             let module = db.module_for_file(pos.file_id.file_id(&db));
             let crate_def_map = module.def_map(&db);
             visit_module(&db, crate_def_map, module.local_id, &mut |def| {
@@ -75,9 +114,49 @@ fn baz() -> i32 {
                     db.infer(it.into());
                 }
             });
-        });
-        assert!(format!("{events:?}").contains("infer_shim"))
-    }
+        },
+        &[("infer_shim", 3)],
+        expect_test::expect![[r#"
+            [
+                "source_root_crates_shim",
+                "crate_local_def_map",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "infer_shim",
+                "function_signature_shim",
+                "function_signature_with_source_map_shim",
+                "attrs_shim",
+                "body_shim",
+                "body_with_source_map_shim",
+                "trait_environment_shim",
+                "return_type_impl_traits_shim",
+                "expr_scopes_shim",
+                "lang_item",
+                "crate_lang_items",
+                "attrs_shim",
+                "attrs_shim",
+                "lang_item",
+                "infer_shim",
+                "function_signature_shim",
+                "function_signature_with_source_map_shim",
+                "body_shim",
+                "body_with_source_map_shim",
+                "trait_environment_shim",
+                "return_type_impl_traits_shim",
+                "expr_scopes_shim",
+                "infer_shim",
+                "function_signature_shim",
+                "function_signature_with_source_map_shim",
+                "body_shim",
+                "body_with_source_map_shim",
+                "trait_environment_shim",
+                "return_type_impl_traits_shim",
+                "expr_scopes_shim",
+            ]
+        "#]],
+    );
 
     let new_text = "
 fn foo() -> f32 {
@@ -93,8 +172,9 @@ fn baz() -> i32 {
 
     db.set_file_text(pos.file_id.file_id(&db), new_text);
 
-    {
-        let events = db.log_executed(|| {
+    execute_assert_events(
+        &db,
+        || {
             let module = db.module_for_file(pos.file_id.file_id(&db));
             let crate_def_map = module.def_map(&db);
             visit_module(&db, crate_def_map, module.local_id, &mut |def| {
@@ -102,9 +182,34 @@ fn baz() -> i32 {
                     db.infer(it.into());
                 }
             });
-        });
-        assert_eq!(format!("{events:?}").matches("infer_shim").count(), 1, "{events:#?}")
-    }
+        },
+        &[("infer_shim", 1)],
+        expect_test::expect![[r#"
+            [
+                "parse_shim",
+                "ast_id_map_shim",
+                "file_item_tree_query",
+                "real_span_map_shim",
+                "attrs_shim",
+                "function_signature_with_source_map_shim",
+                "function_signature_shim",
+                "body_with_source_map_shim",
+                "body_shim",
+                "attrs_shim",
+                "attrs_shim",
+                "function_signature_with_source_map_shim",
+                "function_signature_shim",
+                "body_with_source_map_shim",
+                "body_shim",
+                "infer_shim",
+                "expr_scopes_shim",
+                "function_signature_with_source_map_shim",
+                "function_signature_shim",
+                "body_with_source_map_shim",
+                "body_shim",
+            ]
+        "#]],
+    );
 }
 
 #[test]
@@ -121,14 +226,26 @@ fn bar() -> f32 {
 }
 $0",
     );
-    {
-        let events = db.log_executed(|| {
+    execute_assert_events(
+        &db,
+        || {
             let module = db.module_for_file(pos.file_id.file_id(&db));
             let _crate_def_map = module.def_map(&db);
             db.trait_impls_in_crate(module.krate());
-        });
-        assert!(format!("{events:?}").contains("trait_impls_in_crate_shim"))
-    }
+        },
+        &[("trait_impls_in_crate_shim", 1)],
+        expect_test::expect![[r#"
+            [
+                "source_root_crates_shim",
+                "crate_local_def_map",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "trait_impls_in_crate_shim",
+            ]
+        "#]],
+    );
 
     let new_text = "
 fn foo() -> i32 {
@@ -146,24 +263,25 @@ pub struct NewStruct {
 
     db.set_file_text(pos.file_id.file_id(&db), new_text);
 
-    {
-        let actual = db.log_executed(|| {
+    execute_assert_events(
+        &db,
+        || {
             let module = db.module_for_file(pos.file_id.file_id(&db));
             let _crate_def_map = module.def_map(&db);
             db.trait_impls_in_crate(module.krate());
-        });
-
-        let expected = vec![
-            "parse_shim".to_owned(),
-            "ast_id_map_shim".to_owned(),
-            "file_item_tree_shim".to_owned(),
-            "real_span_map_shim".to_owned(),
-            "crate_local_def_map".to_owned(),
-            "trait_impls_in_crate_shim".to_owned(),
-        ];
-
-        assert_eq!(expected, actual);
-    }
+        },
+        &[("trait_impls_in_crate_shim", 1)],
+        expect_test::expect![[r#"
+            [
+                "parse_shim",
+                "ast_id_map_shim",
+                "file_item_tree_query",
+                "real_span_map_shim",
+                "crate_local_def_map",
+                "trait_impls_in_crate_shim",
+            ]
+        "#]],
+    );
 }
 
 #[test]
@@ -180,14 +298,26 @@ fn bar() -> f32 {
 }
 $0",
     );
-    {
-        let events = db.log_executed(|| {
+    execute_assert_events(
+        &db,
+        || {
             let module = db.module_for_file(pos.file_id.file_id(&db));
             let _crate_def_map = module.def_map(&db);
             db.trait_impls_in_crate(module.krate());
-        });
-        assert!(format!("{events:?}").contains("trait_impls_in_crate_shim"))
-    }
+        },
+        &[("trait_impls_in_crate_shim", 1)],
+        expect_test::expect![[r#"
+            [
+                "source_root_crates_shim",
+                "crate_local_def_map",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "trait_impls_in_crate_shim",
+            ]
+        "#]],
+    );
 
     let new_text = "
 fn foo() -> i32 {
@@ -206,24 +336,25 @@ pub enum SomeEnum {
 
     db.set_file_text(pos.file_id.file_id(&db), new_text);
 
-    {
-        let actual = db.log_executed(|| {
+    execute_assert_events(
+        &db,
+        || {
             let module = db.module_for_file(pos.file_id.file_id(&db));
             let _crate_def_map = module.def_map(&db);
             db.trait_impls_in_crate(module.krate());
-        });
-
-        let expected = vec![
-            "parse_shim".to_owned(),
-            "ast_id_map_shim".to_owned(),
-            "file_item_tree_shim".to_owned(),
-            "real_span_map_shim".to_owned(),
-            "crate_local_def_map".to_owned(),
-            "trait_impls_in_crate_shim".to_owned(),
-        ];
-
-        assert_eq!(expected, actual);
-    }
+        },
+        &[("trait_impls_in_crate_shim", 1)],
+        expect_test::expect![[r#"
+            [
+                "parse_shim",
+                "ast_id_map_shim",
+                "file_item_tree_query",
+                "real_span_map_shim",
+                "crate_local_def_map",
+                "trait_impls_in_crate_shim",
+            ]
+        "#]],
+    );
 }
 
 #[test]
@@ -240,14 +371,26 @@ fn bar() -> f32 {
 }
 $0",
     );
-    {
-        let events = db.log_executed(|| {
+    execute_assert_events(
+        &db,
+        || {
             let module = db.module_for_file(pos.file_id.file_id(&db));
             let _crate_def_map = module.def_map(&db);
             db.trait_impls_in_crate(module.krate());
-        });
-        assert!(format!("{events:?}").contains("trait_impls_in_crate_shim"))
-    }
+        },
+        &[("trait_impls_in_crate_shim", 1)],
+        expect_test::expect![[r#"
+            [
+                "source_root_crates_shim",
+                "crate_local_def_map",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "trait_impls_in_crate_shim",
+            ]
+        "#]],
+    );
 
     let new_text = "
 use std::collections::HashMap;
@@ -263,24 +406,25 @@ fn bar() -> f32 {
 
     db.set_file_text(pos.file_id.file_id(&db), new_text);
 
-    {
-        let actual = db.log_executed(|| {
+    execute_assert_events(
+        &db,
+        || {
             let module = db.module_for_file(pos.file_id.file_id(&db));
             let _crate_def_map = module.def_map(&db);
             db.trait_impls_in_crate(module.krate());
-        });
-
-        let expected = vec![
-            "parse_shim".to_owned(),
-            "ast_id_map_shim".to_owned(),
-            "file_item_tree_shim".to_owned(),
-            "real_span_map_shim".to_owned(),
-            "crate_local_def_map".to_owned(),
-            "trait_impls_in_crate_shim".to_owned(),
-        ];
-
-        assert_eq!(expected, actual);
-    }
+        },
+        &[("trait_impls_in_crate_shim", 1)],
+        expect_test::expect![[r#"
+            [
+                "parse_shim",
+                "ast_id_map_shim",
+                "file_item_tree_query",
+                "real_span_map_shim",
+                "crate_local_def_map",
+                "trait_impls_in_crate_shim",
+            ]
+        "#]],
+    );
 }
 
 #[test]
@@ -301,14 +445,26 @@ pub struct SomeStruct {
 }
 $0",
     );
-    {
-        let events = db.log_executed(|| {
+    execute_assert_events(
+        &db,
+        || {
             let module = db.module_for_file(pos.file_id.file_id(&db));
             let _crate_def_map = module.def_map(&db);
             db.trait_impls_in_crate(module.krate());
-        });
-        assert!(format!("{events:?}").contains("trait_impls_in_crate_shim"))
-    }
+        },
+        &[("trait_impls_in_crate_shim", 1)],
+        expect_test::expect![[r#"
+            [
+                "source_root_crates_shim",
+                "crate_local_def_map",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "trait_impls_in_crate_shim",
+            ]
+        "#]],
+    );
 
     let new_text = "
 fn foo() -> i32 {
@@ -332,30 +488,243 @@ impl SomeStruct {
 
     db.set_file_text(pos.file_id.file_id(&db), new_text);
 
-    {
-        let actual = db.log_executed(|| {
+    execute_assert_events(
+        &db,
+        || {
             let module = db.module_for_file(pos.file_id.file_id(&db));
             let _crate_def_map = module.def_map(&db);
             db.trait_impls_in_crate(module.krate());
-        });
-
-        let expected = vec![
-            "parse_shim".to_owned(),
-            "ast_id_map_shim".to_owned(),
-            "file_item_tree_shim".to_owned(),
-            "real_span_map_shim".to_owned(),
-            "crate_local_def_map".to_owned(),
-            "trait_impls_in_crate_shim".to_owned(),
-            "attrs_shim".to_owned(),
-            "impl_trait_with_diagnostics_shim".to_owned(),
-            "impl_signature_shim".to_owned(),
-            "impl_signature_with_source_map_shim".to_owned(),
-            "impl_self_ty_with_diagnostics_shim".to_owned(),
-            "struct_signature_shim".to_owned(),
-            "struct_signature_with_source_map_shim".to_owned(),
-            "type_for_adt_tracked".to_owned(),
-        ];
-
-        assert_eq!(expected, actual);
+        },
+        &[("trait_impls_in_crate_shim", 1)],
+        expect_test::expect![[r#"
+            [
+                "parse_shim",
+                "ast_id_map_shim",
+                "file_item_tree_query",
+                "real_span_map_shim",
+                "crate_local_def_map",
+                "trait_impls_in_crate_shim",
+                "attrs_shim",
+                "impl_trait_with_diagnostics_shim",
+                "impl_signature_shim",
+                "impl_signature_with_source_map_shim",
+                "impl_self_ty_with_diagnostics_shim",
+                "struct_signature_shim",
+                "struct_signature_with_source_map_shim",
+                "attrs_shim",
+                "type_for_adt_tracked",
+            ]
+        "#]],
+    );
+}
+
+#[test]
+fn add_struct_invalidates_trait_solve() {
+    let (mut db, file_id) = TestDB::with_single_file(
+        "
+//- /main.rs crate:main
+struct SomeStruct;
+
+trait Trait<T> {
+    fn method(&self) -> T;
+}
+impl Trait<u32> for SomeStruct {}
+
+fn main() {
+    let s = SomeStruct;
+    s.method();
+    s.$0
+}",
+    );
+
+    execute_assert_events(
+        &db,
+        || {
+            let module = db.module_for_file(file_id.file_id(&db));
+            let crate_def_map = module.def_map(&db);
+            let mut defs: Vec<DefWithBodyId> = vec![];
+            visit_module(&db, crate_def_map, module.local_id, &mut |it| {
+                let def = match it {
+                    ModuleDefId::FunctionId(it) => it.into(),
+                    ModuleDefId::EnumVariantId(it) => it.into(),
+                    ModuleDefId::ConstId(it) => it.into(),
+                    ModuleDefId::StaticId(it) => it.into(),
+                    _ => return,
+                };
+                defs.push(def);
+            });
+
+            for def in defs {
+                let _inference_result = db.infer(def);
+            }
+        },
+        &[("trait_solve_shim", 2)],
+        expect_test::expect![[r#"
+            [
+                "source_root_crates_shim",
+                "crate_local_def_map",
+                "file_item_tree_query",
+                "ast_id_map_shim",
+                "parse_shim",
+                "real_span_map_shim",
+                "trait_items_with_diagnostics_shim",
+                "body_shim",
+                "body_with_source_map_shim",
+                "attrs_shim",
+                "of_",
+                "infer_shim",
+                "trait_signature_shim",
+                "trait_signature_with_source_map_shim",
+                "attrs_shim",
+                "function_signature_shim",
+                "function_signature_with_source_map_shim",
+                "attrs_shim",
+                "body_shim",
+                "body_with_source_map_shim",
+                "trait_environment_shim",
+                "lang_item",
+                "crate_lang_items",
+                "attrs_shim",
+                "attrs_shim",
+                "return_type_impl_traits_shim",
+                "infer_shim",
+                "function_signature_shim",
+                "function_signature_with_source_map_shim",
+                "trait_environment_shim",
+                "expr_scopes_shim",
+                "struct_signature_shim",
+                "struct_signature_with_source_map_shim",
+                "generic_predicates_shim",
+                "value_ty_shim",
+                "variant_fields_shim",
+                "variant_fields_with_source_map_shim",
+                "lang_item",
+                "inherent_impls_in_crate_shim",
+                "impl_signature_shim",
+                "impl_signature_with_source_map_shim",
+                "callable_item_signature_shim",
+                "adt_variance_shim",
+                "variances_of_shim",
+                "trait_solve_shim",
+                "trait_datum_shim",
+                "generic_predicates_shim",
+                "adt_datum_shim",
+                "trait_impls_in_deps_shim",
+                "trait_impls_in_crate_shim",
+                "impl_trait_with_diagnostics_shim",
+                "impl_self_ty_with_diagnostics_shim",
+                "type_for_adt_tracked",
+                "impl_datum_shim",
+                "generic_predicates_shim",
+                "program_clauses_for_chalk_env_shim",
+                "value_ty_shim",
+                "generic_predicates_shim",
+                "trait_solve_shim",
+                "lang_item",
+            ]
+        "#]],
+    );
+
+    let new_text = "
+//- /main.rs crate:main
+struct AnotherStruct;
+
+struct SomeStruct;
+
+trait Trait<T> {
+    fn method(&self) -> T;
+}
+impl Trait<u32> for SomeStruct {}
+
+fn main() {
+    let s = SomeStruct;
+    s.method();
+    s.$0
+}";
+
+    db.set_file_text(file_id.file_id(&db), new_text);
+
+    execute_assert_events(
+        &db,
+        || {
+            let module = db.module_for_file(file_id.file_id(&db));
+            let crate_def_map = module.def_map(&db);
+            let mut defs: Vec<DefWithBodyId> = vec![];
+
+            visit_module(&db, crate_def_map, module.local_id, &mut |it| {
+                let def = match it {
+                    ModuleDefId::FunctionId(it) => it.into(),
+                    ModuleDefId::EnumVariantId(it) => it.into(),
+                    ModuleDefId::ConstId(it) => it.into(),
+                    ModuleDefId::StaticId(it) => it.into(),
+                    _ => return,
+                };
+                defs.push(def);
+            });
+
+            for def in defs {
+                let _inference_result = db.infer(def);
+            }
+        },
+        &[("trait_solve_shim", 0)],
+        expect_test::expect![[r#"
+            [
+                "parse_shim",
+                "ast_id_map_shim",
+                "file_item_tree_query",
+                "real_span_map_shim",
+                "crate_local_def_map",
+                "trait_items_with_diagnostics_shim",
+                "body_with_source_map_shim",
+                "attrs_shim",
+                "body_shim",
+                "of_",
+                "infer_shim",
+                "attrs_shim",
+                "trait_signature_with_source_map_shim",
+                "attrs_shim",
+                "function_signature_with_source_map_shim",
+                "function_signature_shim",
+                "body_with_source_map_shim",
+                "body_shim",
+                "trait_environment_shim",
+                "crate_lang_items",
+                "attrs_shim",
+                "attrs_shim",
+                "attrs_shim",
+                "return_type_impl_traits_shim",
+                "infer_shim",
+                "function_signature_with_source_map_shim",
+                "trait_environment_shim",
+                "expr_scopes_shim",
+                "struct_signature_with_source_map_shim",
+                "generic_predicates_shim",
+                "variant_fields_with_source_map_shim",
+                "inherent_impls_in_crate_shim",
+                "impl_signature_with_source_map_shim",
+                "impl_signature_shim",
+                "callable_item_signature_shim",
+                "generic_predicates_shim",
+                "trait_impls_in_crate_shim",
+                "impl_trait_with_diagnostics_shim",
+                "impl_self_ty_with_diagnostics_shim",
+                "generic_predicates_shim",
+                "generic_predicates_shim",
+            ]
+        "#]],
+    );
+}
+
+fn execute_assert_events(
+    db: &TestDB,
+    f: impl FnOnce(),
+    required: &[(&str, usize)],
+    expect: Expect,
+) {
+    let events = db.log_executed(f);
+    for (event, count) in required {
+        let n = events.iter().filter(|it| it.contains(event)).count();
+        assert_eq!(n, *count, "Expected {event} to be executed {count} times, but only got {n}");
     }
+    expect.assert_debug_eq(&events);
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs
index f5911e2161d..f53409af2b3 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tls.rs
@@ -109,7 +109,7 @@ impl DebugContext<'_> {
             CallableDefId::StructId(s) => self.0.struct_signature(s).name.clone(),
             CallableDefId::EnumVariantId(e) => {
                 let loc = e.lookup(self.0);
-                self.0.enum_variants(loc.parent).variants[loc.index as usize].1.clone()
+                loc.parent.enum_variants(self.0).variants[loc.index as usize].1.clone()
             }
         };
         match def {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
index 1e0ff423ded..4c8e635eff9 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
@@ -293,9 +293,7 @@ pub fn is_fn_unsafe_to_call(
     let loc = func.lookup(db);
     match loc.container {
         hir_def::ItemContainerId::ExternBlockId(block) => {
-            let id = block.lookup(db).id;
-            let is_intrinsic_block =
-                id.item_tree(db)[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic);
+            let is_intrinsic_block = block.abi(db) == Some(sym::rust_dash_intrinsic);
             if is_intrinsic_block {
                 // legacy intrinsics
                 // extern "rust-intrinsic" intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute
@@ -357,7 +355,7 @@ pub(crate) fn detect_variant_from_bytes<'a>(
     let (var_id, var_layout) = match &layout.variants {
         hir_def::layout::Variants::Empty => unreachable!(),
         hir_def::layout::Variants::Single { index } => {
-            (db.enum_variants(e).variants[index.0].0, layout)
+            (e.enum_variants(db).variants[index.0].0, layout)
         }
         hir_def::layout::Variants::Multiple { tag, tag_encoding, variants, .. } => {
             let size = tag.size(target_data_layout).bytes_usize();
@@ -367,7 +365,7 @@ pub(crate) fn detect_variant_from_bytes<'a>(
                 TagEncoding::Direct => {
                     let (var_idx, layout) =
                         variants.iter_enumerated().find_map(|(var_idx, v)| {
-                            let def = db.enum_variants(e).variants[var_idx.0].0;
+                            let def = e.enum_variants(db).variants[var_idx.0].0;
                             (db.const_eval_discriminant(def) == Ok(tag)).then_some((def, v))
                         })?;
                     (var_idx, layout)
@@ -380,7 +378,7 @@ pub(crate) fn detect_variant_from_bytes<'a>(
                         .filter(|x| x != untagged_variant)
                         .nth(candidate_tag)
                         .unwrap_or(*untagged_variant);
-                    (db.enum_variants(e).variants[variant.0].0, &variants[variant])
+                    (e.enum_variants(db).variants[variant.0].0, &variants[variant])
                 }
             }
         }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
index d6b43aeed4d..08a215fecf6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
@@ -213,7 +213,7 @@ impl Context<'_> {
                     AdtId::StructId(s) => add_constraints_from_variant(VariantId::StructId(s)),
                     AdtId::UnionId(u) => add_constraints_from_variant(VariantId::UnionId(u)),
                     AdtId::EnumId(e) => {
-                        db.enum_variants(e).variants.iter().for_each(|&(variant, _)| {
+                        e.enum_variants(db).variants.iter().for_each(|&(variant, _, _)| {
                             add_constraints_from_variant(VariantId::EnumVariantId(variant))
                         });
                     }
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index e8218cf8611..adae335627b 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -52,12 +52,14 @@ use hir_def::{
         BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, LabelId, Pat,
         generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance},
     },
-    item_tree::{AttrOwner, FieldParent, ImportAlias, ItemTreeFieldId, ItemTreeNode},
+    item_tree::ImportAlias,
     layout::{self, ReprOptions, TargetDataLayout},
     nameres::{self, diagnostics::DefDiagnostic},
     per_ns::PerNs,
     resolver::{HasResolver, Resolver},
     signatures::{ImplFlags, StaticFlags, TraitFlags, VariantFields},
+    src::HasSource as _,
+    visibility::visibility_from_ast,
 };
 use hir_expand::{
     AstId, MacroCallKind, RenderedExpandError, ValueResult, attrs::collect_attrs,
@@ -81,11 +83,11 @@ use itertools::Itertools;
 use nameres::diagnostics::DefDiagnosticKind;
 use rustc_hash::FxHashSet;
 use smallvec::SmallVec;
-use span::{Edition, FileId};
+use span::{AstIdNode, Edition, FileId};
 use stdx::{format_to, impl_from, never};
 use syntax::{
     AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, T, TextRange, ToSmolStr,
-    ast::{self, HasAttrs as _, HasName},
+    ast::{self, HasAttrs as _, HasName, HasVisibility as _},
     format_smolstr,
 };
 use triomphe::{Arc, ThinArc};
@@ -686,8 +688,8 @@ impl Module {
                         Adt::Enum(e) => {
                             let source_map = db.enum_signature_with_source_map(e.id).1;
                             expr_store_diagnostics(db, acc, &source_map);
-                            let (variants, diagnostics) = db.enum_variants_with_diagnostics(e.id);
-                            let file = e.id.lookup(db).id.file_id();
+                            let (variants, diagnostics) = e.id.enum_variants_with_diagnostics(db);
+                            let file = e.id.lookup(db).id.file_id;
                             let ast_id_map = db.ast_id_map(file);
                             if let Some(diagnostics) = &diagnostics {
                                 for diag in diagnostics.iter() {
@@ -704,7 +706,7 @@ impl Module {
                                     );
                                 }
                             }
-                            for &(v, _) in &variants.variants {
+                            for &(v, _, _) in &variants.variants {
                                 let source_map = db.variant_fields_with_source_map(v.into()).1;
                                 push_ty_diagnostics(
                                     db,
@@ -742,12 +744,10 @@ impl Module {
             GenericDef::Impl(impl_def).diagnostics(db, acc);
 
             let loc = impl_def.id.lookup(db);
-            let tree = loc.id.item_tree(db);
             let source_map = db.impl_signature_with_source_map(impl_def.id).1;
             expr_store_diagnostics(db, acc, &source_map);
 
-            let node = &tree[loc.id.value];
-            let file_id = loc.id.file_id();
+            let file_id = loc.id.file_id;
             if file_id.macro_file().is_some_and(|it| it.kind(db) == MacroKind::DeriveBuiltIn) {
                 // these expansion come from us, diagnosing them is a waste of resources
                 // FIXME: Once we diagnose the inputs to builtin derives, we should at least extract those diagnostics somehow
@@ -760,16 +760,16 @@ impl Module {
 
             let ast_id_map = db.ast_id_map(file_id);
 
-            for diag in db.impl_items_with_diagnostics(impl_def.id).1.iter() {
+            for diag in impl_def.id.impl_items_with_diagnostics(db).1.iter() {
                 emit_def_diagnostic(db, acc, diag, edition);
             }
 
             if inherent_impls.invalid_impls().contains(&impl_def.id) {
-                acc.push(IncoherentImpl { impl_: ast_id_map.get(node.ast_id()), file_id }.into())
+                acc.push(IncoherentImpl { impl_: ast_id_map.get(loc.id.value), file_id }.into())
             }
 
             if !impl_def.check_orphan_rules(db) {
-                acc.push(TraitImplOrphan { impl_: ast_id_map.get(node.ast_id()), file_id }.into())
+                acc.push(TraitImplOrphan { impl_: ast_id_map.get(loc.id.value), file_id }.into())
             }
 
             let trait_ = impl_def.trait_(db);
@@ -808,11 +808,11 @@ impl Module {
                 // unsafe negative impl
                 (true, _, true, _) |
                 // unsafe impl for safe trait
-                (true, false, _, false) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(node.ast_id()), file_id, should_be_safe: true }.into()),
+                (true, false, _, false) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(loc.id.value), file_id, should_be_safe: true }.into()),
                 // safe impl for unsafe trait
                 (false, true, false, _) |
                 // safe impl of dangling drop
-                (false, false, _, true) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(node.ast_id()), file_id, should_be_safe: false }.into()),
+                (false, false, _, true) => acc.push(TraitImplIncorrectSafety { impl_: ast_id_map.get(loc.id.value), file_id, should_be_safe: false }.into()),
                 _ => (),
             };
 
@@ -824,7 +824,7 @@ impl Module {
                     AssocItemId::ConstId(id) => !db.const_signature(id).has_body(),
                     AssocItemId::TypeAliasId(it) => db.type_alias_signature(it).ty.is_none(),
                 });
-                impl_assoc_items_scratch.extend(db.impl_items(impl_def.id).items.iter().cloned());
+                impl_assoc_items_scratch.extend(impl_def.id.impl_items(db).items.iter().cloned());
 
                 let redundant = impl_assoc_items_scratch
                     .iter()
@@ -839,14 +839,14 @@ impl Module {
                         TraitImplRedundantAssocItems {
                             trait_,
                             file_id,
-                            impl_: ast_id_map.get(node.ast_id()),
+                            impl_: ast_id_map.get(loc.id.value),
                             assoc_item: (name, assoc_item),
                         }
                         .into(),
                     )
                 }
 
-                let missing: Vec<_> = required_items
+                let mut missing: Vec<_> = required_items
                     .filter(|(name, id)| {
                         !impl_assoc_items_scratch.iter().any(|(impl_name, impl_item)| {
                             discriminant(impl_item) == discriminant(id) && impl_name == name
@@ -854,10 +854,42 @@ impl Module {
                     })
                     .map(|(name, item)| (name.clone(), AssocItem::from(*item)))
                     .collect();
+
+                if !missing.is_empty() {
+                    let self_ty = db.impl_self_ty(impl_def.id).substitute(
+                        Interner,
+                        &hir_ty::generics::generics(db, impl_def.id.into()).placeholder_subst(db),
+                    );
+                    let self_ty = if let TyKind::Alias(AliasTy::Projection(projection)) =
+                        self_ty.kind(Interner)
+                    {
+                        db.normalize_projection(
+                            projection.clone(),
+                            db.trait_environment(impl_def.id.into()),
+                        )
+                    } else {
+                        self_ty
+                    };
+                    let self_ty_is_guaranteed_unsized = matches!(
+                        self_ty.kind(Interner),
+                        TyKind::Dyn(..) | TyKind::Slice(..) | TyKind::Str
+                    );
+                    if self_ty_is_guaranteed_unsized {
+                        missing.retain(|(_, assoc_item)| {
+                            let assoc_item = match *assoc_item {
+                                AssocItem::Function(it) => it.id.into(),
+                                AssocItem::Const(it) => it.id.into(),
+                                AssocItem::TypeAlias(it) => it.id.into(),
+                            };
+                            !hir_ty::dyn_compatibility::generics_require_sized_self(db, assoc_item)
+                        });
+                    }
+                }
+
                 if !missing.is_empty() {
                     acc.push(
                         TraitImplMissingAssocItems {
-                            impl_: ast_id_map.get(node.ast_id()),
+                            impl_: ast_id_map.get(loc.id.value),
                             file_id,
                             missing,
                         }
@@ -880,7 +912,7 @@ impl Module {
                 &source_map,
             );
 
-            for &(_, item) in db.impl_items(impl_def.id).items.iter() {
+            for &(_, item) in impl_def.id.impl_items(db).items.iter() {
                 AssocItem::from(item).diagnostics(db, acc, style_lints);
             }
         }
@@ -1044,73 +1076,25 @@ fn emit_def_diagnostic_(
             )
         }
         DefDiagnosticKind::UnresolvedImport { id, index } => {
-            let file_id = id.file_id();
-            let item_tree = id.item_tree(db);
-            let import = &item_tree[id.value];
+            let file_id = id.file_id;
 
-            let use_tree = import.use_tree_to_ast(db, file_id, *index);
+            let use_tree = hir_def::src::use_tree_to_ast(db, *id, *index);
             acc.push(
                 UnresolvedImport { decl: InFile::new(file_id, AstPtr::new(&use_tree)) }.into(),
             );
         }
 
-        DefDiagnosticKind::UnconfiguredCode { tree, item, cfg, opts } => {
-            let item_tree = tree.item_tree(db);
-            let ast_id_map = db.ast_id_map(tree.file_id());
-            // FIXME: This parses... We could probably store relative ranges for the children things
-            // here in the item tree?
-            (|| {
-                let process_field_list =
-                    |field_list: Option<_>, idx: ItemTreeFieldId| match field_list? {
-                        ast::FieldList::RecordFieldList(it) => Some(SyntaxNodePtr::new(
-                            it.fields().nth(idx.into_raw().into_u32() as usize)?.syntax(),
-                        )),
-                        ast::FieldList::TupleFieldList(it) => Some(SyntaxNodePtr::new(
-                            it.fields().nth(idx.into_raw().into_u32() as usize)?.syntax(),
-                        )),
-                    };
-                let ptr = match *item {
-                    AttrOwner::ModItem(it) => {
-                        ast_id_map.get(it.ast_id(&item_tree)).syntax_node_ptr()
-                    }
-                    AttrOwner::TopLevel => ast_id_map.root(),
-                    AttrOwner::Variant(it) => {
-                        ast_id_map.get(item_tree[it].ast_id).syntax_node_ptr()
-                    }
-                    AttrOwner::Field(FieldParent::EnumVariant(parent), idx) => process_field_list(
-                        ast_id_map
-                            .get(item_tree[parent].ast_id)
-                            .to_node(&db.parse_or_expand(tree.file_id()))
-                            .field_list(),
-                        idx,
-                    )?,
-                    AttrOwner::Field(FieldParent::Struct(parent), idx) => process_field_list(
-                        ast_id_map
-                            .get(item_tree[parent.index()].ast_id)
-                            .to_node(&db.parse_or_expand(tree.file_id()))
-                            .field_list(),
-                        idx,
-                    )?,
-                    AttrOwner::Field(FieldParent::Union(parent), idx) => SyntaxNodePtr::new(
-                        ast_id_map
-                            .get(item_tree[parent.index()].ast_id)
-                            .to_node(&db.parse_or_expand(tree.file_id()))
-                            .record_field_list()?
-                            .fields()
-                            .nth(idx.into_raw().into_u32() as usize)?
-                            .syntax(),
-                    ),
-                };
-                acc.push(
-                    InactiveCode {
-                        node: InFile::new(tree.file_id(), ptr),
-                        cfg: cfg.clone(),
-                        opts: opts.clone(),
-                    }
-                    .into(),
-                );
-                Some(())
-            })();
+        DefDiagnosticKind::UnconfiguredCode { ast_id, cfg, opts } => {
+            let ast_id_map = db.ast_id_map(ast_id.file_id);
+            let ptr = ast_id_map.get_erased(ast_id.value);
+            acc.push(
+                InactiveCode {
+                    node: InFile::new(ast_id.file_id, ptr),
+                    cfg: cfg.clone(),
+                    opts: opts.clone(),
+                }
+                .into(),
+            );
         }
         DefDiagnosticKind::UnresolvedMacroCall { ast, path } => {
             let (node, precise_location) = precise_macro_call_location(ast, db);
@@ -1446,12 +1430,8 @@ impl Struct {
 impl HasVisibility for Struct {
     fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
         let loc = self.id.lookup(db);
-        let item_tree = loc.id.item_tree(db);
-        Visibility::resolve(
-            db,
-            &self.id.resolver(db),
-            &item_tree[item_tree[loc.id.value].visibility],
-        )
+        let source = loc.source(db);
+        visibility_from_ast(db, self.id, source.map(|src| src.visibility()))
     }
 }
 
@@ -1504,12 +1484,8 @@ impl Union {
 impl HasVisibility for Union {
     fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
         let loc = self.id.lookup(db);
-        let item_tree = loc.id.item_tree(db);
-        Visibility::resolve(
-            db,
-            &self.id.resolver(db),
-            &item_tree[item_tree[loc.id.value].visibility],
-        )
+        let source = loc.source(db);
+        visibility_from_ast(db, self.id, source.map(|src| src.visibility()))
     }
 }
 
@@ -1528,11 +1504,11 @@ impl Enum {
     }
 
     pub fn variants(self, db: &dyn HirDatabase) -> Vec<Variant> {
-        db.enum_variants(self.id).variants.iter().map(|&(id, _)| Variant { id }).collect()
+        self.id.enum_variants(db).variants.iter().map(|&(id, _, _)| Variant { id }).collect()
     }
 
     pub fn num_variants(self, db: &dyn HirDatabase) -> usize {
-        db.enum_variants(self.id).variants.len()
+        self.id.enum_variants(db).variants.len()
     }
 
     pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprOptions> {
@@ -1597,12 +1573,8 @@ impl Enum {
 impl HasVisibility for Enum {
     fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
         let loc = self.id.lookup(db);
-        let item_tree = loc.id.item_tree(db);
-        Visibility::resolve(
-            db,
-            &self.id.resolver(db),
-            &item_tree[item_tree[loc.id.value].visibility],
-        )
+        let source = loc.source(db);
+        visibility_from_ast(db, self.id, source.map(|src| src.visibility()))
     }
 }
 
@@ -1634,7 +1606,7 @@ impl Variant {
     pub fn name(self, db: &dyn HirDatabase) -> Name {
         let lookup = self.id.lookup(db);
         let enum_ = lookup.parent;
-        db.enum_variants(enum_).variants[lookup.index as usize].1.clone()
+        enum_.enum_variants(db).variants[lookup.index as usize].1.clone()
     }
 
     pub fn fields(self, db: &dyn HirDatabase) -> Vec<Field> {
@@ -2660,7 +2632,7 @@ impl SelfParam {
 
 impl HasVisibility for Function {
     fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
-        db.function_visibility(self.id)
+        db.assoc_visibility(self.id.into())
     }
 }
 
@@ -2676,10 +2648,9 @@ impl ExternCrateDecl {
 
     pub fn resolved_crate(self, db: &dyn HirDatabase) -> Option<Crate> {
         let loc = self.id.lookup(db);
-        let item_tree = loc.id.item_tree(db);
         let krate = loc.container.krate();
-        let name = &item_tree[loc.id.value].name;
-        if *name == sym::self_ {
+        let name = self.name(db);
+        if name == sym::self_ {
             Some(krate.into())
         } else {
             krate.data(db).dependencies.iter().find_map(|dep| {
@@ -2690,25 +2661,29 @@ impl ExternCrateDecl {
 
     pub fn name(self, db: &dyn HirDatabase) -> Name {
         let loc = self.id.lookup(db);
-        let item_tree = loc.id.item_tree(db);
-        item_tree[loc.id.value].name.clone()
+        let source = loc.source(db);
+        as_name_opt(source.value.name_ref())
     }
 
     pub fn alias(self, db: &dyn HirDatabase) -> Option<ImportAlias> {
         let loc = self.id.lookup(db);
-        let item_tree = loc.id.item_tree(db);
-        item_tree[loc.id.value].alias.clone()
+        let source = loc.source(db);
+        let rename = source.value.rename()?;
+        if let Some(name) = rename.name() {
+            Some(ImportAlias::Alias(name.as_name()))
+        } else if rename.underscore_token().is_some() {
+            Some(ImportAlias::Underscore)
+        } else {
+            None
+        }
     }
 
     /// Returns the name under which this crate is made accessible, taking `_` into account.
     pub fn alias_or_name(self, db: &dyn HirDatabase) -> Option<Name> {
-        let loc = self.id.lookup(db);
-        let item_tree = loc.id.item_tree(db);
-
-        match &item_tree[loc.id.value].alias {
+        match self.alias(db) {
             Some(ImportAlias::Underscore) => None,
-            Some(ImportAlias::Alias(alias)) => Some(alias.clone()),
-            None => Some(item_tree[loc.id.value].name.clone()),
+            Some(ImportAlias::Alias(alias)) => Some(alias),
+            None => Some(self.name(db)),
         }
     }
 }
@@ -2716,12 +2691,8 @@ impl ExternCrateDecl {
 impl HasVisibility for ExternCrateDecl {
     fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
         let loc = self.id.lookup(db);
-        let item_tree = loc.id.item_tree(db);
-        Visibility::resolve(
-            db,
-            &self.id.resolver(db),
-            &item_tree[item_tree[loc.id.value].visibility],
-        )
+        let source = loc.source(db);
+        visibility_from_ast(db, self.id, source.map(|src| src.visibility()))
     }
 }
 
@@ -2756,7 +2727,7 @@ impl Const {
 
 impl HasVisibility for Const {
     fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
-        db.const_visibility(self.id)
+        db.assoc_visibility(self.id.into())
     }
 }
 
@@ -2841,12 +2812,8 @@ impl Static {
 impl HasVisibility for Static {
     fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
         let loc = self.id.lookup(db);
-        let item_tree = loc.id.item_tree(db);
-        Visibility::resolve(
-            db,
-            &self.id.resolver(db),
-            &item_tree[item_tree[loc.id.value].visibility],
-        )
+        let source = loc.source(db);
+        visibility_from_ast(db, self.id, source.map(|src| src.visibility()))
     }
 }
 
@@ -2935,11 +2902,7 @@ impl Trait {
     }
 
     fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> {
-        db.trait_items(self.id)
-            .macro_calls
-            .as_ref()
-            .map(|it| it.as_ref().clone().into_boxed_slice())
-            .unwrap_or_default()
+        db.trait_items(self.id).macro_calls.to_vec().into_boxed_slice()
     }
 
     /// `#[rust_analyzer::completions(...)]` mode.
@@ -2951,12 +2914,8 @@ impl Trait {
 impl HasVisibility for Trait {
     fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
         let loc = self.id.lookup(db);
-        let item_tree = loc.id.item_tree(db);
-        Visibility::resolve(
-            db,
-            &self.id.resolver(db),
-            &item_tree[item_tree[loc.id.value].visibility],
-        )
+        let source = loc.source(db);
+        visibility_from_ast(db, self.id, source.map(|src| src.visibility()))
     }
 }
 
@@ -2978,12 +2937,8 @@ impl TraitAlias {
 impl HasVisibility for TraitAlias {
     fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
         let loc = self.id.lookup(db);
-        let item_tree = loc.id.item_tree(db);
-        Visibility::resolve(
-            db,
-            &self.id.resolver(db),
-            &item_tree[item_tree[loc.id.value].visibility],
-        )
+        let source = loc.source(db);
+        visibility_from_ast(db, self.id, source.map(|src| src.visibility()))
     }
 }
 
@@ -3021,7 +2976,7 @@ impl TypeAlias {
 
 impl HasVisibility for TypeAlias {
     fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
-        db.type_alias_visibility(self.id)
+        db.assoc_visibility(self.id.into())
     }
 }
 
@@ -3131,25 +3086,23 @@ impl Macro {
         match self.id {
             MacroId::Macro2Id(id) => {
                 let loc = id.lookup(db);
-                let item_tree = loc.id.item_tree(db);
-                item_tree[loc.id.value].name.clone()
+                let source = loc.source(db);
+                as_name_opt(source.value.name())
             }
             MacroId::MacroRulesId(id) => {
                 let loc = id.lookup(db);
-                let item_tree = loc.id.item_tree(db);
-                item_tree[loc.id.value].name.clone()
+                let source = loc.source(db);
+                as_name_opt(source.value.name())
             }
             MacroId::ProcMacroId(id) => {
                 let loc = id.lookup(db);
-                let item_tree = loc.id.item_tree(db);
+                let source = loc.source(db);
                 match loc.kind {
                     ProcMacroKind::CustomDerive => db
                         .attrs(id.into())
                         .parse_proc_macro_derive()
-                        .map_or_else(|| item_tree[loc.id.value].name.clone(), |(it, _)| it),
-                    ProcMacroKind::Bang | ProcMacroKind::Attr => {
-                        item_tree[loc.id.value].name.clone()
-                    }
+                        .map_or_else(|| as_name_opt(source.value.name()), |(it, _)| it),
+                    ProcMacroKind::Bang | ProcMacroKind::Attr => as_name_opt(source.value.name()),
                 }
             }
         }
@@ -3246,12 +3199,8 @@ impl HasVisibility for Macro {
         match self.id {
             MacroId::Macro2Id(id) => {
                 let loc = id.lookup(db);
-                let item_tree = loc.id.item_tree(db);
-                Visibility::resolve(
-                    db,
-                    &id.resolver(db),
-                    &item_tree[item_tree[loc.id.value].visibility],
-                )
+                let source = loc.source(db);
+                visibility_from_ast(db, id, source.map(|src| src.visibility()))
             }
             MacroId::MacroRulesId(_) => Visibility::Public,
             MacroId::ProcMacroId(_) => Visibility::Public,
@@ -3405,7 +3354,7 @@ fn as_assoc_item<'db, ID, DEF, LOC>(
 where
     ID: Lookup<Database = dyn DefDatabase, Data = AssocItemLoc<LOC>>,
     DEF: From<ID>,
-    LOC: ItemTreeNode,
+    LOC: AstIdNode,
 {
     match id.lookup(db).container {
         ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
@@ -3421,7 +3370,7 @@ fn as_extern_assoc_item<'db, ID, DEF, LOC>(
 where
     ID: Lookup<Database = dyn DefDatabase, Data = AssocItemLoc<LOC>>,
     DEF: From<ID>,
-    LOC: ItemTreeNode,
+    LOC: AstIdNode,
 {
     match id.lookup(db).container {
         ItemContainerId::ExternBlockId(_) => Some(ctor(DEF::from(id))),
@@ -4464,7 +4413,7 @@ impl Impl {
     }
 
     pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
-        db.impl_items(self.id).items.iter().map(|&(_, it)| it.into()).collect()
+        self.id.impl_items(db).items.iter().map(|&(_, it)| it.into()).collect()
     }
 
     pub fn is_negative(self, db: &dyn HirDatabase) -> bool {
@@ -4513,11 +4462,7 @@ impl Impl {
     }
 
     fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> {
-        db.impl_items(self.id)
-            .macro_calls
-            .as_ref()
-            .map(|it| it.as_ref().clone().into_boxed_slice())
-            .unwrap_or_default()
+        self.id.impl_items(db).macro_calls.to_vec().into_boxed_slice()
     }
 }
 
@@ -5326,7 +5271,7 @@ impl Type {
             let impls = db.inherent_impls_in_crate(krate);
 
             for impl_def in impls.for_self_ty(&self.ty) {
-                for &(_, item) in db.impl_items(*impl_def).items.iter() {
+                for &(_, item) in impl_def.impl_items(db).items.iter() {
                     if callback(item) {
                         return;
                     }
@@ -6478,3 +6423,7 @@ pub fn resolve_absolute_path<'a, I: Iterator<Item = Symbol> + Clone + 'a>(
         })
         .flatten()
 }
+
+fn as_name_opt(name: Option<impl AsName>) -> Name {
+    name.map_or_else(Name::missing, |name| name.as_name())
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 4a2e8e379fb..10498958242 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -25,7 +25,6 @@ use hir_expand::{
     builtin::{BuiltinFnLikeExpander, EagerExpander},
     db::ExpandDatabase,
     files::{FileRangeWrapper, HirFileRange, InRealFile},
-    inert_attr_macro::find_builtin_attr_idx,
     mod_path::{ModPath, PathKind},
     name::AsName,
 };
@@ -159,13 +158,13 @@ pub struct SemanticsImpl<'db> {
     macro_call_cache: RefCell<FxHashMap<InFile<ast::MacroCall>, MacroCallId>>,
 }
 
-impl<DB> fmt::Debug for Semantics<'_, DB> {
+impl<DB: ?Sized> fmt::Debug for Semantics<'_, DB> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "Semantics {{ ... }}")
     }
 }
 
-impl<'db, DB> ops::Deref for Semantics<'db, DB> {
+impl<'db, DB: ?Sized> ops::Deref for Semantics<'db, DB> {
     type Target = SemanticsImpl<'db>;
 
     fn deref(&self) -> &Self::Target {
@@ -173,12 +172,28 @@ impl<'db, DB> ops::Deref for Semantics<'db, DB> {
     }
 }
 
+// Note: while this variant of `Semantics<'_, _>` might seem unused, as it does not
+// find actual use within the rust-analyzer project itself, it exists to enable the use
+// within e.g. tracked salsa functions in third-party crates that build upon `ra_ap_hir`.
+impl Semantics<'_, dyn HirDatabase> {
+    /// Creates an instance that's weakly coupled to its underlying database type.
+    pub fn new_dyn(db: &'_ dyn HirDatabase) -> Semantics<'_, dyn HirDatabase> {
+        let impl_ = SemanticsImpl::new(db);
+        Semantics { db, imp: impl_ }
+    }
+}
+
 impl<DB: HirDatabase> Semantics<'_, DB> {
+    /// Creates an instance that's strongly coupled to its underlying database type.
     pub fn new(db: &DB) -> Semantics<'_, DB> {
         let impl_ = SemanticsImpl::new(db);
         Semantics { db, imp: impl_ }
     }
+}
 
+// Note: We take `DB` as `?Sized` here in order to support type-erased
+// use of `Semantics` via `Semantics<'_, dyn HirDatabase>`:
+impl<DB: HirDatabase + ?Sized> Semantics<'_, DB> {
     pub fn hir_file_for(&self, syntax_node: &SyntaxNode) -> HirFileId {
         self.imp.find_file(syntax_node).file_id
     }
@@ -229,7 +244,7 @@ impl<DB: HirDatabase> Semantics<'_, DB> {
         offset: TextSize,
     ) -> impl Iterator<Item = ast::NameLike> + 'slf {
         node.token_at_offset(offset)
-            .map(move |token| self.descend_into_macros_no_opaque(token))
+            .map(move |token| self.descend_into_macros_no_opaque(token, true))
             .map(|descendants| descendants.into_iter().filter_map(move |it| it.value.parent()))
             // re-order the tokens from token_at_offset by returning the ancestors with the smaller first nodes first
             // See algo::ancestors_at_offset, which uses the same approach
@@ -953,13 +968,6 @@ impl<'db> SemanticsImpl<'db> {
             let Some(item) = ast::Item::cast(ancestor) else {
                 return false;
             };
-            // Optimization to skip the semantic check.
-            if item.attrs().all(|attr| {
-                attr.simple_name()
-                    .is_some_and(|attr| find_builtin_attr_idx(&Symbol::intern(&attr)).is_some())
-            }) {
-                return false;
-            }
             self.with_ctx(|ctx| {
                 if ctx.item_to_macro_call(token.with_value(&item)).is_some() {
                     return true;
@@ -1001,10 +1009,11 @@ impl<'db> SemanticsImpl<'db> {
     pub fn descend_into_macros_no_opaque(
         &self,
         token: SyntaxToken,
+        always_descend_into_derives: bool,
     ) -> SmallVec<[InFile<SyntaxToken>; 1]> {
         let mut res = smallvec![];
         let token = self.wrap_token_infile(token);
-        self.descend_into_macros_all(token.clone(), true, &mut |t, ctx| {
+        self.descend_into_macros_all(token.clone(), always_descend_into_derives, &mut |t, ctx| {
             if !ctx.is_opaque(self.db) {
                 // Don't descend into opaque contexts
                 res.push(t);
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs
index 1a6d63c88c6..fedd8239d03 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs
@@ -6,10 +6,11 @@
 
 use either::Either;
 use hir_expand::{HirFileId, attrs::collect_attrs};
+use span::AstIdNode;
 use syntax::{AstPtr, ast};
 
 use hir_def::{
-    AdtId, AssocItemId, DefWithBodyId, EnumId, FieldId, GenericDefId, ImplId, ItemTreeLoc,
+    AdtId, AssocItemId, AstIdLoc, DefWithBodyId, EnumId, FieldId, GenericDefId, ImplId,
     LifetimeParamId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, TypeOrConstParamId,
     VariantId,
     db::DefDatabase,
@@ -19,7 +20,6 @@ use hir_def::{
     },
     hir::generics::GenericParams,
     item_scope::ItemScope,
-    item_tree::ItemTreeNode,
     nameres::DefMap,
     src::{HasChildSource, HasSource},
 };
@@ -61,7 +61,7 @@ impl ChildBySource for TraitId {
 
 impl ChildBySource for ImplId {
     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
-        let data = db.impl_items(*self);
+        let data = self.impl_items(db);
         data.macro_calls().filter(|(ast_id, _)| ast_id.file_id == file_id).for_each(
             |(ast_id, call_id)| {
                 let ptr = ast_id.to_ptr(db);
@@ -113,7 +113,7 @@ impl ChildBySource for ItemScope {
             ids.iter().for_each(|&id| {
                 if let MacroId::MacroRulesId(id) = id {
                     let loc = id.lookup(db);
-                    if loc.id.file_id() == file_id {
+                    if loc.id.file_id == file_id {
                         res[keys::MACRO_RULES].insert(loc.ast_ptr(db).value, id);
                     }
                 }
@@ -199,16 +199,14 @@ impl ChildBySource for VariantId {
 impl ChildBySource for EnumId {
     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
         let loc = &self.lookup(db);
-        if file_id != loc.id.file_id() {
+        if file_id != loc.id.file_id {
             return;
         }
 
-        let tree = loc.id.item_tree(db);
-        let ast_id_map = db.ast_id_map(loc.id.file_id());
+        let ast_id_map = db.ast_id_map(loc.id.file_id);
 
-        db.enum_variants(*self).variants.iter().for_each(|&(variant, _)| {
-            res[keys::ENUM_VARIANT]
-                .insert(ast_id_map.get(tree[variant.lookup(db).id.value].ast_id), variant);
+        self.enum_variants(db).variants.iter().for_each(|&(variant, _, _)| {
+            res[keys::ENUM_VARIANT].insert(ast_id_map.get(variant.lookup(db).id.value), variant);
         });
         let (_, source_map) = db.enum_signature_with_source_map(*self);
         source_map
@@ -287,15 +285,14 @@ fn insert_item_loc<ID, N, Data>(
     res: &mut DynMap,
     file_id: HirFileId,
     id: ID,
-    key: Key<N::Source, ID>,
+    key: Key<N, ID>,
 ) where
     ID: Lookup<Database = dyn DefDatabase, Data = Data> + 'static,
-    Data: ItemTreeLoc<Id = N>,
-    N: ItemTreeNode,
-    N::Source: 'static,
+    Data: AstIdLoc<Ast = N>,
+    N: AstIdNode + 'static,
 {
     let loc = id.lookup(db);
-    if loc.item_tree_id().file_id() == file_id {
+    if loc.ast_id().file_id == file_id {
         res[key].insert(loc.ast_ptr(db).value, id)
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index ec2ccf8cba0..3273358b78e 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -37,7 +37,7 @@ use hir_expand::{
 };
 use hir_ty::{
     Adjustment, AliasTy, InferenceResult, Interner, LifetimeElisionKind, ProjectionTy,
-    Substitution, TraitEnvironment, Ty, TyExt, TyKind, TyLoweringContext,
+    Substitution, ToChalk, TraitEnvironment, Ty, TyExt, TyKind, TyLoweringContext,
     diagnostics::{
         InsideUnsafeBlock, record_literal_missing_fields, record_pattern_missing_fields,
         unsafe_operations,
@@ -829,7 +829,7 @@ impl<'db> SourceAnalyzer<'db> {
                                 handle_variants(id.into(), subst, &mut container)?
                             }
                             AdtId::EnumId(id) => {
-                                let variants = db.enum_variants(id);
+                                let variants = id.enum_variants(db);
                                 let variant = variants.variant(&field_name.as_name())?;
                                 container = Either::Left((variant, subst.clone()));
                                 (Either::Left(Variant { id: variant }), id.into(), subst.clone())
@@ -1169,8 +1169,7 @@ impl<'db> SourceAnalyzer<'db> {
                         )
                     }
                     TyKind::FnDef(fn_id, subst) => {
-                        let fn_id = hir_ty::db::InternedCallableDefId::from(*fn_id);
-                        let fn_id = db.lookup_intern_callable_def(fn_id);
+                        let fn_id = ToChalk::from_chalk(db, *fn_id);
                         let generic_def_id = match fn_id {
                             CallableDefId::StructId(id) => id.into(),
                             CallableDefId::FunctionId(id) => id.into(),
diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
index e87ab87407f..64f2a910bd1 100644
--- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
@@ -1,5 +1,6 @@
 //! File symbol extraction.
 
+use base_db::FxIndexSet;
 use either::Either;
 use hir_def::{
     AdtId, AssocItemId, Complete, DefWithBodyId, ExternCrateId, HasModule, ImplId, Lookup, MacroId,
@@ -21,8 +22,6 @@ use syntax::{AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, ToSmolStr, ast
 
 use crate::{HasCrate, Module, ModuleDef, Semantics};
 
-pub type FxIndexSet<T> = indexmap::IndexSet<T, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
-
 /// The actual data that is stored in the index. It should be as compact as
 /// possible.
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -34,6 +33,7 @@ pub struct FileSymbol {
     /// Whether this symbol is a doc alias for the original symbol.
     pub is_alias: bool,
     pub is_assoc: bool,
+    pub is_import: bool,
     pub do_not_complete: Complete,
 }
 
@@ -165,6 +165,7 @@ impl<'a> SymbolCollector<'a> {
 
         let is_explicit_import = |vis| match vis {
             Visibility::Public => true,
+            Visibility::PubCrate(_) => true,
             Visibility::Module(_, VisibilityExplicitness::Explicit) => true,
             Visibility::Module(_, VisibilityExplicitness::Implicit) => false,
         };
@@ -197,6 +198,7 @@ impl<'a> SymbolCollector<'a> {
                 loc: dec_loc,
                 is_alias: false,
                 is_assoc: false,
+                is_import: true,
                 do_not_complete: Complete::Yes,
             });
         };
@@ -227,6 +229,7 @@ impl<'a> SymbolCollector<'a> {
                     loc: dec_loc,
                     is_alias: false,
                     is_assoc: false,
+                    is_import: false,
                     do_not_complete: Complete::Yes,
                 });
             };
@@ -322,7 +325,7 @@ impl<'a> SymbolCollector<'a> {
                 .to_smolstr(),
         );
         self.with_container_name(impl_name, |s| {
-            for &(ref name, assoc_item_id) in &self.db.impl_items(impl_id).items {
+            for &(ref name, assoc_item_id) in &impl_id.impl_items(self.db).items {
                 s.push_assoc_item(assoc_item_id, name, None)
             }
         })
@@ -398,6 +401,7 @@ impl<'a> SymbolCollector<'a> {
                     container_name: self.current_container_name.clone(),
                     is_alias: true,
                     is_assoc,
+                    is_import: false,
                     do_not_complete,
                 });
             }
@@ -410,6 +414,7 @@ impl<'a> SymbolCollector<'a> {
             loc: dec_loc,
             is_alias: false,
             is_assoc,
+            is_import: false,
             do_not_complete,
         });
 
@@ -442,6 +447,7 @@ impl<'a> SymbolCollector<'a> {
                     container_name: self.current_container_name.clone(),
                     is_alias: true,
                     is_assoc: false,
+                    is_import: false,
                     do_not_complete,
                 });
             }
@@ -454,6 +460,7 @@ impl<'a> SymbolCollector<'a> {
             loc: dec_loc,
             is_alias: false,
             is_assoc: false,
+            is_import: false,
             do_not_complete,
         });
     }
diff --git a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
index 583318de26d..acde1d665da 100644
--- a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
@@ -22,7 +22,7 @@ either.workspace = true
 itertools.workspace = true
 arrayvec.workspace = true
 indexmap.workspace = true
-memchr = "2.7.4"
+memchr = "2.7.5"
 salsa.workspace = true
 salsa-macros.workspace = true
 query-group.workspace = true
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
index d1ba79e8c78..c15cade84a5 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
@@ -50,6 +50,7 @@ pub struct Query {
     case_sensitive: bool,
     only_types: bool,
     libs: bool,
+    exclude_imports: bool,
 }
 
 impl Query {
@@ -63,6 +64,7 @@ impl Query {
             mode: SearchMode::Fuzzy,
             assoc_mode: AssocSearchMode::Include,
             case_sensitive: false,
+            exclude_imports: false,
         }
     }
 
@@ -94,6 +96,10 @@ impl Query {
     pub fn case_sensitive(&mut self) {
         self.case_sensitive = true;
     }
+
+    pub fn exclude_imports(&mut self) {
+        self.exclude_imports = true;
+    }
 }
 
 #[query_group::query_group]
@@ -362,6 +368,9 @@ impl Query {
                     if ignore_underscore_prefixed && symbol_name.starts_with("__") {
                         continue;
                     }
+                    if self.exclude_imports && symbol.is_import {
+                        continue;
+                    }
                     if self.mode.check(&self.query, self.case_sensitive, symbol_name) {
                         if let Some(b) = cb(symbol).break_value() {
                             return Some(b);
@@ -385,7 +394,8 @@ impl Query {
 mod tests {
 
     use expect_test::expect_file;
-    use test_fixture::WithFixture;
+    use salsa::Durability;
+    use test_fixture::{WORKSPACE, WithFixture};
 
     use super::*;
 
@@ -506,4 +516,31 @@ struct Duplicate;
 
         expect_file!["./test_data/test_doc_alias.txt"].assert_debug_eq(&symbols);
     }
+
+    #[test]
+    fn test_exclude_imports() {
+        let (mut db, _) = RootDatabase::with_many_files(
+            r#"
+//- /lib.rs
+mod foo;
+pub use foo::Foo;
+
+//- /foo.rs
+pub struct Foo;
+"#,
+        );
+
+        let mut local_roots = FxHashSet::default();
+        local_roots.insert(WORKSPACE);
+        db.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
+
+        let mut query = Query::new("Foo".to_owned());
+        let mut symbols = world_symbols(&db, query.clone());
+        symbols.sort_by_key(|x| x.is_import);
+        expect_file!["./test_data/test_symbols_with_imports.txt"].assert_debug_eq(&symbols);
+
+        query.exclude_imports();
+        let symbols = world_symbols(&db, query);
+        expect_file!["./test_data/test_symbols_exclude_imports.txt"].assert_debug_eq(&symbols);
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt
index 455a6805907..30d1df4f8e5 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_doc_alias.txt
@@ -41,6 +41,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -74,6 +75,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -107,6 +109,7 @@
                 container_name: None,
                 is_alias: true,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -140,6 +143,7 @@
                 container_name: None,
                 is_alias: true,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -173,6 +177,7 @@
                 container_name: None,
                 is_alias: true,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -206,6 +211,7 @@
                 container_name: None,
                 is_alias: true,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -239,6 +245,7 @@
                 container_name: None,
                 is_alias: true,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
         ],
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
index 5e5ae1d168e..de046e70c67 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
@@ -39,6 +39,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -70,6 +71,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -101,6 +103,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -134,6 +137,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -167,6 +171,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: true,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -200,6 +205,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -231,6 +237,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -264,6 +271,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -297,6 +305,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -332,6 +341,7 @@
                 ),
                 is_alias: false,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -367,6 +377,7 @@
                 ),
                 is_alias: false,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -400,6 +411,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -433,6 +445,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -464,6 +477,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -497,6 +511,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: true,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -530,6 +545,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -565,6 +581,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -600,6 +617,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -633,6 +651,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -666,6 +685,7 @@
                 ),
                 is_alias: false,
                 is_assoc: true,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -699,6 +719,7 @@
                 ),
                 is_alias: false,
                 is_assoc: true,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -732,6 +753,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -763,6 +785,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -796,6 +819,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: true,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -829,6 +853,7 @@
                 ),
                 is_alias: false,
                 is_assoc: true,
+                is_import: false,
                 do_not_complete: Yes,
             },
         ],
@@ -875,6 +900,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
         ],
@@ -919,6 +945,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: true,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -952,6 +979,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: true,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -985,6 +1013,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: false,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -1018,6 +1047,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: true,
                 do_not_complete: Yes,
             },
             FileSymbol {
@@ -1051,6 +1081,7 @@
                 container_name: None,
                 is_alias: false,
                 is_assoc: false,
+                is_import: true,
                 do_not_complete: Yes,
             },
         ],
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt
new file mode 100644
index 00000000000..22872b577f7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_exclude_imports.txt
@@ -0,0 +1,36 @@
+[
+    FileSymbol {
+        name: "Foo",
+        def: Adt(
+            Struct(
+                Struct {
+                    id: StructId(
+                        3800,
+                    ),
+                },
+            ),
+        ),
+        loc: DeclarationLocation {
+            hir_file_id: FileId(
+                EditionedFileId(
+                    Id(2001),
+                ),
+            ),
+            ptr: SyntaxNodePtr {
+                kind: STRUCT,
+                range: 0..15,
+            },
+            name_ptr: AstPtr(
+                SyntaxNodePtr {
+                    kind: NAME,
+                    range: 11..14,
+                },
+            ),
+        },
+        container_name: None,
+        is_alias: false,
+        is_assoc: false,
+        is_import: false,
+        do_not_complete: Yes,
+    },
+]
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt
new file mode 100644
index 00000000000..9f98bf87e2e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbols_with_imports.txt
@@ -0,0 +1,70 @@
+[
+    FileSymbol {
+        name: "Foo",
+        def: Adt(
+            Struct(
+                Struct {
+                    id: StructId(
+                        3800,
+                    ),
+                },
+            ),
+        ),
+        loc: DeclarationLocation {
+            hir_file_id: FileId(
+                EditionedFileId(
+                    Id(2001),
+                ),
+            ),
+            ptr: SyntaxNodePtr {
+                kind: STRUCT,
+                range: 0..15,
+            },
+            name_ptr: AstPtr(
+                SyntaxNodePtr {
+                    kind: NAME,
+                    range: 11..14,
+                },
+            ),
+        },
+        container_name: None,
+        is_alias: false,
+        is_assoc: false,
+        is_import: false,
+        do_not_complete: Yes,
+    },
+    FileSymbol {
+        name: "Foo",
+        def: Adt(
+            Struct(
+                Struct {
+                    id: StructId(
+                        3800,
+                    ),
+                },
+            ),
+        ),
+        loc: DeclarationLocation {
+            hir_file_id: FileId(
+                EditionedFileId(
+                    Id(2000),
+                ),
+            ),
+            ptr: SyntaxNodePtr {
+                kind: USE_TREE,
+                range: 17..25,
+            },
+            name_ptr: AstPtr(
+                SyntaxNodePtr {
+                    kind: NAME_REF,
+                    range: 22..25,
+                },
+            ),
+        },
+        container_name: None,
+        is_alias: false,
+        is_assoc: false,
+        is_import: true,
+        do_not_complete: Yes,
+    },
+]
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs
index fa7ba90a756..0e18ce96740 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs
@@ -127,4 +127,33 @@ impl !Trait for () {}
 "#,
         )
     }
+
+    #[test]
+    fn impl_sized_for_unsized() {
+        check_diagnostics(
+            r#"
+//- minicore: sized
+trait Trait {
+    type Item
+    where
+        Self: Sized;
+
+    fn item()
+    where
+        Self: Sized;
+}
+
+trait OtherTrait {}
+
+impl Trait for () {
+    type Item = ();
+    fn item() {}
+}
+
+// Items with Self: Sized bound not required to be implemented for unsized types.
+impl Trait for str {}
+impl Trait for dyn OtherTrait {}
+ "#,
+        )
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/Cargo.toml b/src/tools/rust-analyzer/crates/ide/Cargo.toml
index 1d19daf2f5a..2f8ed88fbb5 100644
--- a/src/tools/rust-analyzer/crates/ide/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide/Cargo.toml
@@ -25,7 +25,7 @@ dot.workspace = true
 smallvec.workspace = true
 triomphe.workspace = true
 nohash-hasher.workspace = true
-rustc_apfloat = "0.2.2"
+rustc_apfloat = "0.2.3"
 
 # local deps
 cfg.workspace = true
diff --git a/src/tools/rust-analyzer/crates/ide/src/annotations.rs b/src/tools/rust-analyzer/crates/ide/src/annotations.rs
index 3d71da985b2..05196ac98c0 100644
--- a/src/tools/rust-analyzer/crates/ide/src/annotations.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/annotations.rs
@@ -10,6 +10,7 @@ use crate::{
     NavigationTarget, RunnableKind,
     annotations::fn_references::find_all_methods,
     goto_implementation::goto_implementation,
+    navigation_target,
     references::find_all_refs,
     runnables::{Runnable, runnables},
 };
@@ -148,15 +149,32 @@ pub(crate) fn annotations(
             node: InFile<T>,
             source_file_id: FileId,
         ) -> Option<(TextRange, Option<TextRange>)> {
-            if let Some(InRealFile { file_id, value }) = node.original_ast_node_rooted(db) {
-                if file_id.file_id(db) == source_file_id {
-                    return Some((
-                        value.syntax().text_range(),
-                        value.name().map(|name| name.syntax().text_range()),
-                    ));
+            if let Some(name) = node.value.name().map(|name| name.syntax().text_range()) {
+                // if we have a name, try mapping that out of the macro expansion as we can put the
+                // annotation on that name token
+                // See `test_no_annotations_macro_struct_def` vs `test_annotations_macro_struct_def_call_site`
+                let res = navigation_target::orig_range_with_focus_r(
+                    db,
+                    node.file_id,
+                    node.value.syntax().text_range(),
+                    Some(name),
+                );
+                if res.call_site.0.file_id == source_file_id {
+                    if let Some(name_range) = res.call_site.1 {
+                        return Some((res.call_site.0.range, Some(name_range)));
+                    }
                 }
+            };
+            // otherwise try upmapping the entire node out of attributes
+            let InRealFile { file_id, value } = node.original_ast_node_rooted(db)?;
+            if file_id.file_id(db) == source_file_id {
+                Some((
+                    value.syntax().text_range(),
+                    value.name().map(|name| name.syntax().text_range()),
+                ))
+            } else {
+                None
             }
-            None
         }
     });
 
@@ -914,6 +932,56 @@ m!();
     }
 
     #[test]
+    fn test_annotations_macro_struct_def_call_site() {
+        check(
+            r#"
+//- /lib.rs
+macro_rules! m {
+    ($name:ident) => {
+        struct $name {}
+    };
+}
+
+m! {
+    Name
+};
+"#,
+            expect![[r#"
+                [
+                    Annotation {
+                        range: 83..87,
+                        kind: HasImpls {
+                            pos: FilePositionWrapper {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 83,
+                            },
+                            data: Some(
+                                [],
+                            ),
+                        },
+                    },
+                    Annotation {
+                        range: 83..87,
+                        kind: HasReferences {
+                            pos: FilePositionWrapper {
+                                file_id: FileId(
+                                    0,
+                                ),
+                                offset: 83,
+                            },
+                            data: Some(
+                                [],
+                            ),
+                        },
+                    },
+                ]
+            "#]],
+        );
+    }
+
+    #[test]
     fn test_annotations_appear_above_whole_item_when_configured_to_do_so() {
         check_with_config(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
index 38c032d382e..267e8ff7128 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
@@ -29,7 +29,7 @@ pub(crate) fn goto_declaration(
         .find(|it| matches!(it.kind(), IDENT | T![self] | T![super] | T![crate] | T![Self]))?;
     let range = original_token.text_range();
     let info: Vec<NavigationTarget> = sema
-        .descend_into_macros_no_opaque(original_token)
+        .descend_into_macros_no_opaque(original_token, false)
         .iter()
         .filter_map(|token| {
             let parent = token.value.parent()?;
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
index 7917aab8bf7..574803fb9e8 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -88,7 +88,7 @@ pub(crate) fn goto_definition(
     }
 
     let navs = sema
-        .descend_into_macros_no_opaque(original_token.clone())
+        .descend_into_macros_no_opaque(original_token.clone(), false)
         .into_iter()
         .filter_map(|token| {
             let parent = token.value.parent()?;
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
index a6c7ea29b09..9781e7116de 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
@@ -70,7 +70,7 @@ pub(crate) fn goto_type_definition(
     }
 
     let range = token.text_range();
-    sema.descend_into_macros_no_opaque(token)
+    sema.descend_into_macros_no_opaque(token,false)
         .into_iter()
         .filter_map(|token| {
             sema
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implied_dyn_trait.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implied_dyn_trait.rs
index 32d130503a4..cd01c075832 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implied_dyn_trait.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implied_dyn_trait.rs
@@ -22,9 +22,14 @@ pub(super) fn hints(
             let parent = paren.as_ref().and_then(|it| it.parent()).unwrap_or(parent);
             if ast::TypeBound::can_cast(parent.kind())
                 || ast::TypeAnchor::can_cast(parent.kind())
-                || ast::Impl::cast(parent)
-                    .and_then(|it| it.trait_())
-                    .is_some_and(|it| it.syntax() == path.syntax())
+                || ast::Impl::cast(parent).is_some_and(|it| {
+                    it.trait_().map_or(
+                        // only show it for impl type if the impl is not incomplete, otherwise we
+                        // are likely typing a trait impl
+                        it.assoc_item_list().is_none_or(|it| it.l_curly_token().is_none()),
+                        |trait_| trait_.syntax() == path.syntax(),
+                    )
+                })
             {
                 return None;
             }
@@ -85,6 +90,7 @@ impl T {}
   // ^ dyn
 impl T for (T) {}
         // ^^^ dyn
+impl T
 "#,
         );
     }
diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
index 9334b73fc7b..4c7c597e684 100644
--- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
@@ -867,7 +867,7 @@ pub(crate) fn orig_range_with_focus_r(
             }
 
             // def site name
-            // FIXME: This can be de improved
+            // FIXME: This can be improved
             Some((focus_range, _ctxt)) => {
                 match value_range {
                     // but overall node is in macro input
diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
index ab139602404..f48150b369f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
@@ -5,11 +5,11 @@ use ast::HasName;
 use cfg::{CfgAtom, CfgExpr};
 use hir::{
     AsAssocItem, AttrsWithOwner, HasAttrs, HasCrate, HasSource, ModPath, Name, PathKind, Semantics,
-    Symbol, db::HirDatabase, sym, symbols::FxIndexSet,
+    Symbol, db::HirDatabase, sym,
 };
 use ide_assists::utils::{has_test_related_attribute, test_related_attribute_syn};
 use ide_db::{
-    FilePosition, FxHashMap, FxIndexMap, RootDatabase, SymbolKind,
+    FilePosition, FxHashMap, FxIndexMap, FxIndexSet, RootDatabase, SymbolKind,
     base_db::RootQueryDb,
     defs::Definition,
     documentation::docs_from_attrs,
diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
index fc922dd849f..d5cbb7328c1 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
@@ -222,6 +222,7 @@ define_symbols! {
     fn_once_output,
     fn_once,
     async_fn_once,
+    async_fn_once_output,
     async_fn_mut,
     async_fn,
     fn_ptr_addr,
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 30e2d5416cf..89b8631cd25 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -2,7 +2,7 @@
 //! for incorporating changes.
 // Note, don't remove any public api from this. This API is consumed by external tools
 // to run rust-analyzer as a library.
-use std::{collections::hash_map::Entry, mem, path::Path, sync};
+use std::{any::Any, collections::hash_map::Entry, mem, path::Path, sync};
 
 use crossbeam_channel::{Receiver, unbounded};
 use hir_expand::proc_macro::{
@@ -512,6 +512,10 @@ impl ProcMacroExpander for Expander {
             Err(err) => Err(ProcMacroExpansionError::System(err.to_string())),
         }
     }
+
+    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
+        (other as &dyn Any).downcast_ref::<Self>() == Some(self)
+    }
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs
index db75dceae1c..04ac85ad43d 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs
@@ -197,6 +197,10 @@ fn invocation_fixtures(
                                         builder.push(tt::Leaf::Punct(*it))
                                     }
                                 }
+                                Separator::Lifetime(punct, ident) => {
+                                    builder.push(tt::Leaf::Punct(*punct));
+                                    builder.push(tt::Leaf::Ident(ident.clone()));
+                                }
                             };
                         }
                     }
diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs
index 940aaacb02e..a8d5965d480 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs
@@ -823,7 +823,7 @@ fn match_meta_var<'t>(
                         "expected token tree",
                     )
                 }),
-                MetaVarKind::Lifetime => expect_lifetime(input).map_err(|()| {
+                MetaVarKind::Lifetime => expect_lifetime(input).map(drop).map_err(|()| {
                     ExpandError::binding_error(
                         span.unwrap_or(delim_span.close),
                         "expected lifetime",
@@ -963,6 +963,10 @@ fn expect_separator<S: Copy>(iter: &mut TtIter<'_, S>, separator: &Separator) ->
             }
             Err(_) => false,
         },
+        Separator::Lifetime(_punct, ident) => match expect_lifetime(&mut fork) {
+            Ok(lifetime) => lifetime.sym == ident.sym,
+            Err(_) => false,
+        },
     };
     if ok {
         *iter = fork;
@@ -983,13 +987,12 @@ fn expect_tt<S: Copy>(iter: &mut TtIter<'_, S>) -> Result<(), ()> {
     Ok(())
 }
 
-fn expect_lifetime<S: Copy>(iter: &mut TtIter<'_, S>) -> Result<(), ()> {
+fn expect_lifetime<'a, S: Copy>(iter: &mut TtIter<'a, S>) -> Result<&'a tt::Ident<S>, ()> {
     let punct = iter.expect_single_punct()?;
     if punct.char != '\'' {
         return Err(());
     }
-    iter.expect_ident_or_underscore()?;
-    Ok(())
+    iter.expect_ident_or_underscore()
 }
 
 fn eat_char<S: Copy>(iter: &mut TtIter<'_, S>, c: char) {
diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
index ec277ba72e9..2c046df10f5 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
@@ -497,6 +497,10 @@ fn expand_repeat(
                         builder.push(tt::Leaf::from(punct));
                     }
                 }
+                Separator::Lifetime(punct, ident) => {
+                    builder.push(tt::Leaf::from(*punct));
+                    builder.push(tt::Leaf::from(ident.clone()));
+                }
             };
         }
 
diff --git a/src/tools/rust-analyzer/crates/mbe/src/parser.rs b/src/tools/rust-analyzer/crates/mbe/src/parser.rs
index fbc353d6103..711101260a0 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/parser.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/parser.rs
@@ -155,6 +155,7 @@ pub(crate) enum Separator {
     Literal(tt::Literal<Span>),
     Ident(tt::Ident<Span>),
     Puncts(ArrayVec<tt::Punct<Span>, MAX_GLUED_PUNCT_LEN>),
+    Lifetime(tt::Punct<Span>, tt::Ident<Span>),
 }
 
 // Note that when we compare a Separator, we just care about its textual value.
@@ -170,6 +171,7 @@ impl PartialEq for Separator {
                 let b_iter = b.iter().map(|b| b.char);
                 a_iter.eq(b_iter)
             }
+            (Lifetime(_, a), Lifetime(_, b)) => a.sym == b.sym,
             _ => false,
         }
     }
@@ -350,10 +352,19 @@ fn parse_repeat(src: &mut TtIter<'_, Span>) -> Result<(Option<Separator>, Repeat
             _ => true,
         };
         match tt {
-            tt::Leaf::Ident(_) | tt::Leaf::Literal(_) if has_sep => {
-                return Err(ParseError::InvalidRepeat);
-            }
-            tt::Leaf::Ident(ident) => separator = Separator::Ident(ident.clone()),
+            tt::Leaf::Ident(ident) => match separator {
+                Separator::Puncts(puncts) if puncts.is_empty() => {
+                    separator = Separator::Ident(ident.clone());
+                }
+                Separator::Puncts(puncts) => match puncts.as_slice() {
+                    [tt::Punct { char: '\'', .. }] => {
+                        separator = Separator::Lifetime(puncts[0], ident.clone());
+                    }
+                    _ => return Err(ParseError::InvalidRepeat),
+                },
+                _ => return Err(ParseError::InvalidRepeat),
+            },
+            tt::Leaf::Literal(_) if has_sep => return Err(ParseError::InvalidRepeat),
             tt::Leaf::Literal(lit) => separator = Separator::Literal(lit.clone()),
             tt::Leaf::Punct(punct) => {
                 let repeat_kind = match punct.char {
diff --git a/src/tools/rust-analyzer/crates/mbe/src/tests.rs b/src/tools/rust-analyzer/crates/mbe/src/tests.rs
index 769455faac0..56034516ef3 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/tests.rs
@@ -3,7 +3,9 @@
 // FIXME: Move more of the nameres independent tests from
 // crates\hir-def\src\macro_expansion_tests\mod.rs to this
 use expect_test::expect;
-use span::{Edition, EditionedFileId, ErasedFileAstId, FileId, Span, SpanAnchor, SyntaxContext};
+use span::{
+    Edition, EditionedFileId, FileId, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SyntaxContext,
+};
 use stdx::format_to;
 use tt::{TextRange, TextSize};
 
@@ -24,7 +26,7 @@ fn check_(
         def_edition,
         SpanAnchor {
             file_id: EditionedFileId::new(FileId::from_raw(0), def_edition),
-            ast_id: ErasedFileAstId::from_raw(0),
+            ast_id: ROOT_ERASED_FILE_AST_ID,
         },
         SyntaxContext::root(Edition::CURRENT),
         decl,
@@ -37,7 +39,7 @@ fn check_(
     };
     let call_anchor = SpanAnchor {
         file_id: EditionedFileId::new(FileId::from_raw(1), call_edition),
-        ast_id: ErasedFileAstId::from_raw(0),
+        ast_id: ROOT_ERASED_FILE_AST_ID,
     };
     let arg_tt = syntax_bridge::parse_to_token_tree(
         call_edition,
@@ -110,8 +112,8 @@ fn unbalanced_brace() {
 "#,
         r#""#,
         expect![[r#"
-            SUBTREE $$ 1:0@0..0#ROOT2024 1:0@0..0#ROOT2024
-              SUBTREE {} 0:0@9..10#ROOT2024 0:0@11..12#ROOT2024
+            SUBTREE $$ 1:Root[0000, 0]@0..0#ROOT2024 1:Root[0000, 0]@0..0#ROOT2024
+              SUBTREE {} 0:Root[0000, 0]@9..10#ROOT2024 0:Root[0000, 0]@11..12#ROOT2024
 
             {}"#]],
     );
@@ -133,25 +135,25 @@ fn token_mapping_smoke_test() {
 struct MyTraitMap2
 "#,
         expect![[r#"
-            SUBTREE $$ 1:0@0..20#ROOT2024 1:0@0..20#ROOT2024
-              IDENT   struct 0:0@34..40#ROOT2024
-              IDENT   MyTraitMap2 1:0@8..19#ROOT2024
-              SUBTREE {} 0:0@48..49#ROOT2024 0:0@100..101#ROOT2024
-                IDENT   map 0:0@58..61#ROOT2024
-                PUNCH   : [alone] 0:0@61..62#ROOT2024
-                PUNCH   : [joint] 0:0@63..64#ROOT2024
-                PUNCH   : [alone] 0:0@64..65#ROOT2024
-                IDENT   std 0:0@65..68#ROOT2024
-                PUNCH   : [joint] 0:0@68..69#ROOT2024
-                PUNCH   : [alone] 0:0@69..70#ROOT2024
-                IDENT   collections 0:0@70..81#ROOT2024
-                PUNCH   : [joint] 0:0@81..82#ROOT2024
-                PUNCH   : [alone] 0:0@82..83#ROOT2024
-                IDENT   HashSet 0:0@83..90#ROOT2024
-                PUNCH   < [alone] 0:0@90..91#ROOT2024
-                SUBTREE () 0:0@91..92#ROOT2024 0:0@92..93#ROOT2024
-                PUNCH   > [joint] 0:0@93..94#ROOT2024
-                PUNCH   , [alone] 0:0@94..95#ROOT2024
+            SUBTREE $$ 1:Root[0000, 0]@0..20#ROOT2024 1:Root[0000, 0]@0..20#ROOT2024
+              IDENT   struct 0:Root[0000, 0]@34..40#ROOT2024
+              IDENT   MyTraitMap2 1:Root[0000, 0]@8..19#ROOT2024
+              SUBTREE {} 0:Root[0000, 0]@48..49#ROOT2024 0:Root[0000, 0]@100..101#ROOT2024
+                IDENT   map 0:Root[0000, 0]@58..61#ROOT2024
+                PUNCH   : [alone] 0:Root[0000, 0]@61..62#ROOT2024
+                PUNCH   : [joint] 0:Root[0000, 0]@63..64#ROOT2024
+                PUNCH   : [alone] 0:Root[0000, 0]@64..65#ROOT2024
+                IDENT   std 0:Root[0000, 0]@65..68#ROOT2024
+                PUNCH   : [joint] 0:Root[0000, 0]@68..69#ROOT2024
+                PUNCH   : [alone] 0:Root[0000, 0]@69..70#ROOT2024
+                IDENT   collections 0:Root[0000, 0]@70..81#ROOT2024
+                PUNCH   : [joint] 0:Root[0000, 0]@81..82#ROOT2024
+                PUNCH   : [alone] 0:Root[0000, 0]@82..83#ROOT2024
+                IDENT   HashSet 0:Root[0000, 0]@83..90#ROOT2024
+                PUNCH   < [alone] 0:Root[0000, 0]@90..91#ROOT2024
+                SUBTREE () 0:Root[0000, 0]@91..92#ROOT2024 0:Root[0000, 0]@92..93#ROOT2024
+                PUNCH   > [joint] 0:Root[0000, 0]@93..94#ROOT2024
+                PUNCH   , [alone] 0:Root[0000, 0]@94..95#ROOT2024
 
             struct MyTraitMap2 {
                 map: ::std::collections::HashSet<()>,
@@ -180,28 +182,28 @@ fn main() {
 }
 "#,
         expect![[r#"
-            SUBTREE $$ 1:0@0..63#ROOT2024 1:0@0..63#ROOT2024
-              IDENT   fn 1:0@1..3#ROOT2024
-              IDENT   main 1:0@4..8#ROOT2024
-              SUBTREE () 1:0@8..9#ROOT2024 1:0@9..10#ROOT2024
-              SUBTREE {} 1:0@11..12#ROOT2024 1:0@61..62#ROOT2024
-                LITERAL Integer 1 1:0@17..18#ROOT2024
-                PUNCH   ; [alone] 1:0@18..19#ROOT2024
-                LITERAL Float 1.0 1:0@24..27#ROOT2024
-                PUNCH   ; [alone] 1:0@27..28#ROOT2024
-                SUBTREE () 1:0@33..34#ROOT2024 1:0@39..40#ROOT2024
-                  SUBTREE () 1:0@34..35#ROOT2024 1:0@37..38#ROOT2024
-                    LITERAL Integer 1 1:0@35..36#ROOT2024
-                    PUNCH   , [alone] 1:0@36..37#ROOT2024
-                  PUNCH   , [alone] 1:0@38..39#ROOT2024
-                PUNCH   . [alone] 1:0@40..41#ROOT2024
-                LITERAL Float 0.0 1:0@41..44#ROOT2024
-                PUNCH   ; [alone] 1:0@44..45#ROOT2024
-                IDENT   let 1:0@50..53#ROOT2024
-                IDENT   x 1:0@54..55#ROOT2024
-                PUNCH   = [alone] 1:0@56..57#ROOT2024
-                LITERAL Integer 1 1:0@58..59#ROOT2024
-                PUNCH   ; [alone] 1:0@59..60#ROOT2024
+            SUBTREE $$ 1:Root[0000, 0]@0..63#ROOT2024 1:Root[0000, 0]@0..63#ROOT2024
+              IDENT   fn 1:Root[0000, 0]@1..3#ROOT2024
+              IDENT   main 1:Root[0000, 0]@4..8#ROOT2024
+              SUBTREE () 1:Root[0000, 0]@8..9#ROOT2024 1:Root[0000, 0]@9..10#ROOT2024
+              SUBTREE {} 1:Root[0000, 0]@11..12#ROOT2024 1:Root[0000, 0]@61..62#ROOT2024
+                LITERAL Integer 1 1:Root[0000, 0]@17..18#ROOT2024
+                PUNCH   ; [alone] 1:Root[0000, 0]@18..19#ROOT2024
+                LITERAL Float 1.0 1:Root[0000, 0]@24..27#ROOT2024
+                PUNCH   ; [alone] 1:Root[0000, 0]@27..28#ROOT2024
+                SUBTREE () 1:Root[0000, 0]@33..34#ROOT2024 1:Root[0000, 0]@39..40#ROOT2024
+                  SUBTREE () 1:Root[0000, 0]@34..35#ROOT2024 1:Root[0000, 0]@37..38#ROOT2024
+                    LITERAL Integer 1 1:Root[0000, 0]@35..36#ROOT2024
+                    PUNCH   , [alone] 1:Root[0000, 0]@36..37#ROOT2024
+                  PUNCH   , [alone] 1:Root[0000, 0]@38..39#ROOT2024
+                PUNCH   . [alone] 1:Root[0000, 0]@40..41#ROOT2024
+                LITERAL Float 0.0 1:Root[0000, 0]@41..44#ROOT2024
+                PUNCH   ; [alone] 1:Root[0000, 0]@44..45#ROOT2024
+                IDENT   let 1:Root[0000, 0]@50..53#ROOT2024
+                IDENT   x 1:Root[0000, 0]@54..55#ROOT2024
+                PUNCH   = [alone] 1:Root[0000, 0]@56..57#ROOT2024
+                LITERAL Integer 1 1:Root[0000, 0]@58..59#ROOT2024
+                PUNCH   ; [alone] 1:Root[0000, 0]@59..60#ROOT2024
 
             fn main(){
                 1;
@@ -227,14 +229,14 @@ fn expr_2021() {
     const { 1 },
 "#,
         expect![[r#"
-            SUBTREE $$ 1:0@0..25#ROOT2024 1:0@0..25#ROOT2024
-              IDENT   _ 1:0@5..6#ROOT2024
-              PUNCH   ; [joint] 0:0@36..37#ROOT2024
-              SUBTREE () 0:0@34..35#ROOT2024 0:0@34..35#ROOT2024
-                IDENT   const 1:0@12..17#ROOT2024
-                SUBTREE {} 1:0@18..19#ROOT2024 1:0@22..23#ROOT2024
-                  LITERAL Integer 1 1:0@20..21#ROOT2024
-              PUNCH   ; [alone] 0:0@39..40#ROOT2024
+            SUBTREE $$ 1:Root[0000, 0]@0..25#ROOT2024 1:Root[0000, 0]@0..25#ROOT2024
+              IDENT   _ 1:Root[0000, 0]@5..6#ROOT2024
+              PUNCH   ; [joint] 0:Root[0000, 0]@36..37#ROOT2024
+              SUBTREE () 0:Root[0000, 0]@34..35#ROOT2024 0:Root[0000, 0]@34..35#ROOT2024
+                IDENT   const 1:Root[0000, 0]@12..17#ROOT2024
+                SUBTREE {} 1:Root[0000, 0]@18..19#ROOT2024 1:Root[0000, 0]@22..23#ROOT2024
+                  LITERAL Integer 1 1:Root[0000, 0]@20..21#ROOT2024
+              PUNCH   ; [alone] 0:Root[0000, 0]@39..40#ROOT2024
 
             _;
             (const  {
@@ -255,13 +257,13 @@ fn expr_2021() {
         expect![[r#"
             ExpandError {
                 inner: (
-                    1:0@5..6#ROOT2024,
+                    1:Root[0000, 0]@5..6#ROOT2024,
                     NoMatchingRule,
                 ),
             }
 
-            SUBTREE $$ 1:0@0..8#ROOT2024 1:0@0..8#ROOT2024
-              PUNCH   ; [alone] 0:0@39..40#ROOT2024
+            SUBTREE $$ 1:Root[0000, 0]@0..8#ROOT2024 1:Root[0000, 0]@0..8#ROOT2024
+              PUNCH   ; [alone] 0:Root[0000, 0]@39..40#ROOT2024
 
             ;"#]],
     );
@@ -279,13 +281,13 @@ fn expr_2021() {
         expect![[r#"
             ExpandError {
                 inner: (
-                    1:0@5..10#ROOT2024,
+                    1:Root[0000, 0]@5..10#ROOT2024,
                     NoMatchingRule,
                 ),
             }
 
-            SUBTREE $$ 1:0@0..18#ROOT2024 1:0@0..18#ROOT2024
-              PUNCH   ; [alone] 0:0@39..40#ROOT2024
+            SUBTREE $$ 1:Root[0000, 0]@0..18#ROOT2024 1:Root[0000, 0]@0..18#ROOT2024
+              PUNCH   ; [alone] 0:Root[0000, 0]@39..40#ROOT2024
 
             ;"#]],
     );
@@ -305,26 +307,26 @@ fn expr_2021() {
     break 'foo bar,
 "#,
         expect![[r#"
-            SUBTREE $$ 1:0@0..76#ROOT2024 1:0@0..76#ROOT2024
-              LITERAL Integer 4 1:0@5..6#ROOT2024
-              PUNCH   ; [joint] 0:0@41..42#ROOT2024
-              LITERAL Str literal 1:0@12..21#ROOT2024
-              PUNCH   ; [joint] 0:0@41..42#ROOT2024
-              SUBTREE () 0:0@39..40#ROOT2024 0:0@39..40#ROOT2024
-                IDENT   funcall 1:0@27..34#ROOT2024
-                SUBTREE () 1:0@34..35#ROOT2024 1:0@35..36#ROOT2024
-              PUNCH   ; [joint] 0:0@41..42#ROOT2024
-              SUBTREE () 0:0@39..40#ROOT2024 0:0@39..40#ROOT2024
-                IDENT   future 1:0@42..48#ROOT2024
-                PUNCH   . [alone] 1:0@48..49#ROOT2024
-                IDENT   await 1:0@49..54#ROOT2024
-              PUNCH   ; [joint] 0:0@41..42#ROOT2024
-              SUBTREE () 0:0@39..40#ROOT2024 0:0@39..40#ROOT2024
-                IDENT   break 1:0@60..65#ROOT2024
-                PUNCH   ' [joint] 1:0@66..67#ROOT2024
-                IDENT   foo 1:0@67..70#ROOT2024
-                IDENT   bar 1:0@71..74#ROOT2024
-              PUNCH   ; [alone] 0:0@44..45#ROOT2024
+            SUBTREE $$ 1:Root[0000, 0]@0..76#ROOT2024 1:Root[0000, 0]@0..76#ROOT2024
+              LITERAL Integer 4 1:Root[0000, 0]@5..6#ROOT2024
+              PUNCH   ; [joint] 0:Root[0000, 0]@41..42#ROOT2024
+              LITERAL Str literal 1:Root[0000, 0]@12..21#ROOT2024
+              PUNCH   ; [joint] 0:Root[0000, 0]@41..42#ROOT2024
+              SUBTREE () 0:Root[0000, 0]@39..40#ROOT2024 0:Root[0000, 0]@39..40#ROOT2024
+                IDENT   funcall 1:Root[0000, 0]@27..34#ROOT2024
+                SUBTREE () 1:Root[0000, 0]@34..35#ROOT2024 1:Root[0000, 0]@35..36#ROOT2024
+              PUNCH   ; [joint] 0:Root[0000, 0]@41..42#ROOT2024
+              SUBTREE () 0:Root[0000, 0]@39..40#ROOT2024 0:Root[0000, 0]@39..40#ROOT2024
+                IDENT   future 1:Root[0000, 0]@42..48#ROOT2024
+                PUNCH   . [alone] 1:Root[0000, 0]@48..49#ROOT2024
+                IDENT   await 1:Root[0000, 0]@49..54#ROOT2024
+              PUNCH   ; [joint] 0:Root[0000, 0]@41..42#ROOT2024
+              SUBTREE () 0:Root[0000, 0]@39..40#ROOT2024 0:Root[0000, 0]@39..40#ROOT2024
+                IDENT   break 1:Root[0000, 0]@60..65#ROOT2024
+                PUNCH   ' [joint] 1:Root[0000, 0]@66..67#ROOT2024
+                IDENT   foo 1:Root[0000, 0]@67..70#ROOT2024
+                IDENT   bar 1:Root[0000, 0]@71..74#ROOT2024
+              PUNCH   ; [alone] 0:Root[0000, 0]@44..45#ROOT2024
 
             4;
             "literal";
@@ -346,13 +348,13 @@ fn expr_2021() {
         expect![[r#"
             ExpandError {
                 inner: (
-                    1:0@5..6#ROOT2024,
+                    1:Root[0000, 0]@5..6#ROOT2024,
                     NoMatchingRule,
                 ),
             }
 
-            SUBTREE $$ 1:0@0..8#ROOT2024 1:0@0..8#ROOT2024
-              PUNCH   ; [alone] 0:0@44..45#ROOT2024
+            SUBTREE $$ 1:Root[0000, 0]@0..8#ROOT2024 1:Root[0000, 0]@0..8#ROOT2024
+              PUNCH   ; [alone] 0:Root[0000, 0]@44..45#ROOT2024
 
             ;"#]],
     );
@@ -370,88 +372,88 @@ fn minus_belongs_to_literal() {
     check(
         "-1",
         expect![[r#"
-            SUBTREE $$ 1:0@0..2#ROOT2024 1:0@0..2#ROOT2024
-              PUNCH   - [alone] 0:0@10..11#ROOT2024
-              LITERAL Integer 1 0:0@11..12#ROOT2024
+            SUBTREE $$ 1:Root[0000, 0]@0..2#ROOT2024 1:Root[0000, 0]@0..2#ROOT2024
+              PUNCH   - [alone] 0:Root[0000, 0]@10..11#ROOT2024
+              LITERAL Integer 1 0:Root[0000, 0]@11..12#ROOT2024
 
             -1"#]],
     );
     check(
         "- 1",
         expect![[r#"
-            SUBTREE $$ 1:0@0..3#ROOT2024 1:0@0..3#ROOT2024
-              PUNCH   - [alone] 0:0@10..11#ROOT2024
-              LITERAL Integer 1 0:0@11..12#ROOT2024
+            SUBTREE $$ 1:Root[0000, 0]@0..3#ROOT2024 1:Root[0000, 0]@0..3#ROOT2024
+              PUNCH   - [alone] 0:Root[0000, 0]@10..11#ROOT2024
+              LITERAL Integer 1 0:Root[0000, 0]@11..12#ROOT2024
 
             -1"#]],
     );
     check(
         "-2",
         expect![[r#"
-            SUBTREE $$ 1:0@0..2#ROOT2024 1:0@0..2#ROOT2024
-              PUNCH   - [alone] 0:0@25..26#ROOT2024
-              LITERAL Integer 2 0:0@27..28#ROOT2024
+            SUBTREE $$ 1:Root[0000, 0]@0..2#ROOT2024 1:Root[0000, 0]@0..2#ROOT2024
+              PUNCH   - [alone] 0:Root[0000, 0]@25..26#ROOT2024
+              LITERAL Integer 2 0:Root[0000, 0]@27..28#ROOT2024
 
             -2"#]],
     );
     check(
         "- 2",
         expect![[r#"
-            SUBTREE $$ 1:0@0..3#ROOT2024 1:0@0..3#ROOT2024
-              PUNCH   - [alone] 0:0@25..26#ROOT2024
-              LITERAL Integer 2 0:0@27..28#ROOT2024
+            SUBTREE $$ 1:Root[0000, 0]@0..3#ROOT2024 1:Root[0000, 0]@0..3#ROOT2024
+              PUNCH   - [alone] 0:Root[0000, 0]@25..26#ROOT2024
+              LITERAL Integer 2 0:Root[0000, 0]@27..28#ROOT2024
 
             -2"#]],
     );
     check(
         "-3.0",
         expect![[r#"
-            SUBTREE $$ 1:0@0..4#ROOT2024 1:0@0..4#ROOT2024
-              PUNCH   - [alone] 0:0@43..44#ROOT2024
-              LITERAL Float 3.0 0:0@45..48#ROOT2024
+            SUBTREE $$ 1:Root[0000, 0]@0..4#ROOT2024 1:Root[0000, 0]@0..4#ROOT2024
+              PUNCH   - [alone] 0:Root[0000, 0]@43..44#ROOT2024
+              LITERAL Float 3.0 0:Root[0000, 0]@45..48#ROOT2024
 
             -3.0"#]],
     );
     check(
         "- 3.0",
         expect![[r#"
-            SUBTREE $$ 1:0@0..5#ROOT2024 1:0@0..5#ROOT2024
-              PUNCH   - [alone] 0:0@43..44#ROOT2024
-              LITERAL Float 3.0 0:0@45..48#ROOT2024
+            SUBTREE $$ 1:Root[0000, 0]@0..5#ROOT2024 1:Root[0000, 0]@0..5#ROOT2024
+              PUNCH   - [alone] 0:Root[0000, 0]@43..44#ROOT2024
+              LITERAL Float 3.0 0:Root[0000, 0]@45..48#ROOT2024
 
             -3.0"#]],
     );
     check(
         "@1",
         expect![[r#"
-            SUBTREE $$ 1:0@0..2#ROOT2024 1:0@0..2#ROOT2024
-              LITERAL Integer 1 1:0@1..2#ROOT2024
+            SUBTREE $$ 1:Root[0000, 0]@0..2#ROOT2024 1:Root[0000, 0]@0..2#ROOT2024
+              LITERAL Integer 1 1:Root[0000, 0]@1..2#ROOT2024
 
             1"#]],
     );
     check(
         "@-1",
         expect![[r#"
-            SUBTREE $$ 1:0@0..3#ROOT2024 1:0@0..3#ROOT2024
-              PUNCH   - [alone] 1:0@1..2#ROOT2024
-              LITERAL Integer 1 1:0@2..3#ROOT2024
+            SUBTREE $$ 1:Root[0000, 0]@0..3#ROOT2024 1:Root[0000, 0]@0..3#ROOT2024
+              PUNCH   - [alone] 1:Root[0000, 0]@1..2#ROOT2024
+              LITERAL Integer 1 1:Root[0000, 0]@2..3#ROOT2024
 
             -1"#]],
     );
     check(
         "@1.0",
         expect![[r#"
-            SUBTREE $$ 1:0@0..4#ROOT2024 1:0@0..4#ROOT2024
-              LITERAL Float 1.0 1:0@1..4#ROOT2024
+            SUBTREE $$ 1:Root[0000, 0]@0..4#ROOT2024 1:Root[0000, 0]@0..4#ROOT2024
+              LITERAL Float 1.0 1:Root[0000, 0]@1..4#ROOT2024
 
             1.0"#]],
     );
     check(
         "@-1.0",
         expect![[r#"
-            SUBTREE $$ 1:0@0..5#ROOT2024 1:0@0..5#ROOT2024
-              PUNCH   - [alone] 1:0@1..2#ROOT2024
-              LITERAL Float 1.0 1:0@2..5#ROOT2024
+            SUBTREE $$ 1:Root[0000, 0]@0..5#ROOT2024 1:Root[0000, 0]@0..5#ROOT2024
+              PUNCH   - [alone] 1:Root[0000, 0]@1..2#ROOT2024
+              LITERAL Float 1.0 1:Root[0000, 0]@2..5#ROOT2024
 
             -1.0"#]],
     );
@@ -460,16 +462,16 @@ fn minus_belongs_to_literal() {
         expect![[r#"
             ExpandError {
                 inner: (
-                    1:0@1..2#ROOT2024,
+                    1:Root[0000, 0]@1..2#ROOT2024,
                     BindingError(
                         "expected literal",
                     ),
                 ),
             }
 
-            SUBTREE $$ 1:0@0..6#ROOT2024 1:0@0..6#ROOT2024
-              PUNCH   - [joint] 1:0@1..2#ROOT2024
-              PUNCH   - [alone] 1:0@2..3#ROOT2024
+            SUBTREE $$ 1:Root[0000, 0]@0..6#ROOT2024 1:Root[0000, 0]@0..6#ROOT2024
+              PUNCH   - [joint] 1:Root[0000, 0]@1..2#ROOT2024
+              PUNCH   - [alone] 1:Root[0000, 0]@2..3#ROOT2024
 
             --"#]],
     );
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs
index 55185aa492d..165936269d3 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs
@@ -22,9 +22,10 @@ pub const HAS_GLOBAL_SPANS: u32 = 3;
 pub const RUST_ANALYZER_SPAN_SUPPORT: u32 = 4;
 /// Whether literals encode their kind as an additional u32 field and idents their rawness as a u32 field.
 pub const EXTENDED_LEAF_DATA: u32 = 5;
+pub const HASHED_AST_ID: u32 = 6;
 
 /// Current API version of the proc-macro protocol.
-pub const CURRENT_API_VERSION: u32 = EXTENDED_LEAF_DATA;
+pub const CURRENT_API_VERSION: u32 = HASHED_AST_ID;
 
 /// Represents requests sent from the client to the proc-macro-srv.
 #[derive(Debug, Serialize, Deserialize)]
@@ -201,7 +202,9 @@ type ProtocolWrite<W: Write> = for<'o, 'msg> fn(out: &'o mut W, msg: &'msg str)
 #[cfg(test)]
 mod tests {
     use intern::{Symbol, sym};
-    use span::{Edition, ErasedFileAstId, Span, SpanAnchor, SyntaxContext, TextRange, TextSize};
+    use span::{
+        Edition, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SyntaxContext, TextRange, TextSize,
+    };
     use tt::{
         Delimiter, DelimiterKind, Ident, Leaf, Literal, Punct, Spacing, TopSubtree,
         TopSubtreeBuilder,
@@ -215,7 +218,7 @@ mod tests {
                 span::FileId::from_raw(0xe4e4e),
                 span::Edition::CURRENT,
             ),
-            ast_id: ErasedFileAstId::from_raw(0),
+            ast_id: ROOT_ERASED_FILE_AST_ID,
         };
 
         let mut builder = TopSubtreeBuilder::new(Delimiter {
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
index 25c30b6db4a..516c7418bde 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
@@ -12,13 +12,13 @@ pub mod legacy_protocol {
 mod process;
 
 use paths::{AbsPath, AbsPathBuf};
-use span::Span;
+use span::{ErasedFileAstId, FIXUP_ERASED_FILE_AST_ID_MARKER, Span};
 use std::{fmt, io, sync::Arc, time::SystemTime};
 
 use crate::{
     legacy_protocol::msg::{
-        ExpandMacro, ExpandMacroData, ExpnGlobals, FlatTree, HAS_GLOBAL_SPANS, PanicMessage,
-        RUST_ANALYZER_SPAN_SUPPORT, Request, Response, SpanDataIndexMap,
+        ExpandMacro, ExpandMacroData, ExpnGlobals, FlatTree, HAS_GLOBAL_SPANS, HASHED_AST_ID,
+        PanicMessage, RUST_ANALYZER_SPAN_SUPPORT, Request, Response, SpanDataIndexMap,
         deserialize_span_data_index_map, flat::serialize_span_data_index_map,
     },
     process::ProcMacroServerProcess,
@@ -161,6 +161,38 @@ impl ProcMacro {
         self.kind
     }
 
+    fn needs_fixup_change(&self) -> bool {
+        let version = self.process.version();
+        (RUST_ANALYZER_SPAN_SUPPORT..HASHED_AST_ID).contains(&version)
+    }
+
+    /// On some server versions, the fixup ast id is different than ours. So change it to match.
+    fn change_fixup_to_match_old_server(&self, tt: &mut tt::TopSubtree<Span>) {
+        const OLD_FIXUP_AST_ID: ErasedFileAstId = ErasedFileAstId::from_raw(!0 - 1);
+        let change_ast_id = |ast_id: &mut ErasedFileAstId| {
+            if *ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER {
+                *ast_id = OLD_FIXUP_AST_ID;
+            } else if *ast_id == OLD_FIXUP_AST_ID {
+                // Swap between them, that means no collision plus the change can be reversed by doing itself.
+                *ast_id = FIXUP_ERASED_FILE_AST_ID_MARKER;
+            }
+        };
+
+        for tt in &mut tt.0 {
+            match tt {
+                tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { span, .. }))
+                | tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { span, .. }))
+                | tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { span, .. })) => {
+                    change_ast_id(&mut span.anchor.ast_id);
+                }
+                tt::TokenTree::Subtree(subtree) => {
+                    change_ast_id(&mut subtree.delimiter.open.anchor.ast_id);
+                    change_ast_id(&mut subtree.delimiter.close.anchor.ast_id);
+                }
+            }
+        }
+    }
+
     /// Expands the procedural macro by sending an expansion request to the server.
     /// This includes span information and environmental context.
     pub fn expand(
@@ -173,6 +205,20 @@ impl ProcMacro {
         mixed_site: Span,
         current_dir: String,
     ) -> Result<Result<tt::TopSubtree<Span>, PanicMessage>, ServerError> {
+        let (mut subtree, mut attr) = (subtree, attr);
+        let (mut subtree_changed, mut attr_changed);
+        if self.needs_fixup_change() {
+            subtree_changed = tt::TopSubtree::from_subtree(subtree);
+            self.change_fixup_to_match_old_server(&mut subtree_changed);
+            subtree = subtree_changed.view();
+
+            if let Some(attr) = &mut attr {
+                attr_changed = tt::TopSubtree::from_subtree(*attr);
+                self.change_fixup_to_match_old_server(&mut attr_changed);
+                *attr = attr_changed.view();
+            }
+        }
+
         let version = self.process.version();
 
         let mut span_data_table = SpanDataIndexMap::default();
@@ -205,15 +251,23 @@ impl ProcMacro {
         let response = self.process.send_task(Request::ExpandMacro(Box::new(task)))?;
 
         match response {
-            Response::ExpandMacro(it) => {
-                Ok(it.map(|tree| FlatTree::to_subtree_resolved(tree, version, &span_data_table)))
-            }
+            Response::ExpandMacro(it) => Ok(it.map(|tree| {
+                let mut expanded = FlatTree::to_subtree_resolved(tree, version, &span_data_table);
+                if self.needs_fixup_change() {
+                    self.change_fixup_to_match_old_server(&mut expanded);
+                }
+                expanded
+            })),
             Response::ExpandMacroExtended(it) => Ok(it.map(|resp| {
-                FlatTree::to_subtree_resolved(
+                let mut expanded = FlatTree::to_subtree_resolved(
                     resp.tree,
                     version,
                     &deserialize_span_data_index_map(&resp.span_data_table),
-                )
+                );
+                if self.needs_fixup_change() {
+                    self.change_fixup_to_match_old_server(&mut expanded);
+                }
+                expanded
             })),
             _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }),
         }
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/Cargo.toml
index eddefb33c0f..c416d997a89 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/Cargo.toml
@@ -9,4 +9,4 @@ license = "MIT OR Apache-2.0"
 [lib]
 
 [build-dependencies]
-cargo_metadata = "0.19.2"
+cargo_metadata = "0.20.0"
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs
index 6820e4b3353..2a72e50f911 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs
@@ -31,6 +31,7 @@ pub fn fn_like_mk_literals(_args: TokenStream) -> TokenStream {
         TokenTree::from(Literal::byte_string(b"byte_string")),
         TokenTree::from(Literal::character('c')),
         TokenTree::from(Literal::string("string")),
+        TokenTree::from(Literal::string("-string")),
         TokenTree::from(Literal::c_string(c"cstring")),
         // as of 2022-07-21, there's no method on `Literal` to build a raw
         // string or a raw byte string
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs
index ad285990334..dd576f23ae9 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs
@@ -199,37 +199,29 @@ pub(super) fn from_token_tree<Span: Copy>(
         }
 
         bridge::TokenTree::Literal(literal) => {
-            let token_trees =
-                if let Some((_minus, symbol)) = literal.symbol.as_str().split_once('-') {
-                    let punct = tt::Punct {
-                        spacing: tt::Spacing::Alone,
-                        span: literal.span,
-                        char: '-' as char,
-                    };
-                    let leaf: tt::Leaf<Span> = tt::Leaf::from(punct);
-                    let minus_tree = tt::TokenTree::from(leaf);
-
-                    let literal = tt::Literal {
-                        symbol: Symbol::intern(symbol),
-                        suffix: literal.suffix,
-                        span: literal.span,
-                        kind: literal_kind_to_internal(literal.kind),
-                    };
-                    let leaf: tt::Leaf<Span> = tt::Leaf::from(literal);
-                    let tree = tt::TokenTree::from(leaf);
-                    vec![minus_tree, tree]
-                } else {
-                    let literal = tt::Literal {
-                        symbol: literal.symbol,
-                        suffix: literal.suffix,
-                        span: literal.span,
-                        kind: literal_kind_to_internal(literal.kind),
-                    };
-
-                    let leaf: tt::Leaf<Span> = tt::Leaf::from(literal);
-                    let tree = tt::TokenTree::from(leaf);
-                    vec![tree]
-                };
+            let mut token_trees = Vec::new();
+            let mut symbol = literal.symbol;
+            if matches!(
+                literal.kind,
+                proc_macro::bridge::LitKind::Integer | proc_macro::bridge::LitKind::Float
+            ) && symbol.as_str().starts_with('-')
+            {
+                token_trees.push(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
+                    spacing: tt::Spacing::Alone,
+                    span: literal.span,
+                    char: '-' as char,
+                })));
+                symbol = Symbol::intern(&symbol.as_str()[1..]);
+            }
+            let literal = tt::Literal {
+                symbol,
+                suffix: literal.suffix,
+                span: literal.span,
+                kind: literal_kind_to_internal(literal.kind),
+            };
+            let leaf: tt::Leaf<Span> = tt::Leaf::from(literal);
+            let tree = tt::TokenTree::from(leaf);
+            token_trees.push(tree);
             TokenStream { token_trees }
         }
 
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
index 5d1271ba81e..a1863efafbb 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
@@ -318,7 +318,7 @@ mod tests {
             range: TextRange::empty(TextSize::new(0)),
             anchor: span::SpanAnchor {
                 file_id: EditionedFileId::current_edition(FileId::from_raw(0)),
-                ast_id: span::ErasedFileAstId::from_raw(0),
+                ast_id: span::ROOT_ERASED_FILE_AST_ID,
             },
             ctx: SyntaxContext::root(span::Edition::CURRENT),
         };
@@ -360,7 +360,7 @@ mod tests {
             range: TextRange::empty(TextSize::new(0)),
             anchor: span::SpanAnchor {
                 file_id: EditionedFileId::current_edition(FileId::from_raw(0)),
-                ast_id: span::ErasedFileAstId::from_raw(0),
+                ast_id: span::ROOT_ERASED_FILE_AST_ID,
             },
             ctx: SyntaxContext::root(span::Edition::CURRENT),
         };
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
index 3a6ce639d13..08495f50bff 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
@@ -21,14 +21,14 @@ fn test_derive_empty() {
 
             SUBTREE $$ 1 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-              IDENT   struct 42:2@0..6#ROOT2024
-              IDENT   S 42:2@7..8#ROOT2024
-              PUNCH   ; [alone] 42:2@8..9#ROOT2024
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+              IDENT   struct 42:Root[0000, 0]@0..6#ROOT2024
+              IDENT   S 42:Root[0000, 0]@7..8#ROOT2024
+              PUNCH   ; [alone] 42:Root[0000, 0]@8..9#ROOT2024
 
 
 
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024"#]],
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024"#]],
     );
 }
 
@@ -52,19 +52,19 @@ fn test_derive_error() {
                 LITERAL Str #[derive(DeriveError)] struct S ; 1
               PUNCH   ; [alone] 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-              IDENT   struct 42:2@0..6#ROOT2024
-              IDENT   S 42:2@7..8#ROOT2024
-              PUNCH   ; [alone] 42:2@8..9#ROOT2024
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+              IDENT   struct 42:Root[0000, 0]@0..6#ROOT2024
+              IDENT   S 42:Root[0000, 0]@7..8#ROOT2024
+              PUNCH   ; [alone] 42:Root[0000, 0]@8..9#ROOT2024
 
 
 
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-              IDENT   compile_error 42:2@0..100#ROOT2024
-              PUNCH   ! [alone] 42:2@0..100#ROOT2024
-              SUBTREE () 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-                LITERAL Str #[derive(DeriveError)] struct S ; 42:2@0..100#ROOT2024
-              PUNCH   ; [alone] 42:2@0..100#ROOT2024"#]],
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+              IDENT   compile_error 42:Root[0000, 0]@0..100#ROOT2024
+              PUNCH   ! [alone] 42:Root[0000, 0]@0..100#ROOT2024
+              SUBTREE () 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+                LITERAL Str #[derive(DeriveError)] struct S ; 42:Root[0000, 0]@0..100#ROOT2024
+              PUNCH   ; [alone] 42:Root[0000, 0]@0..100#ROOT2024"#]],
     );
 }
 
@@ -94,25 +94,25 @@ fn test_fn_like_macro_noop() {
               PUNCH   , [alone] 1
               SUBTREE [] 1 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-              IDENT   ident 42:2@0..5#ROOT2024
-              PUNCH   , [alone] 42:2@5..6#ROOT2024
-              LITERAL Integer 0 42:2@7..8#ROOT2024
-              PUNCH   , [alone] 42:2@8..9#ROOT2024
-              LITERAL Integer 1 42:2@10..11#ROOT2024
-              PUNCH   , [alone] 42:2@11..12#ROOT2024
-              SUBTREE [] 42:2@13..14#ROOT2024 42:2@14..15#ROOT2024
-
-
-
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-              IDENT   ident 42:2@0..5#ROOT2024
-              PUNCH   , [alone] 42:2@5..6#ROOT2024
-              LITERAL Integer 0 42:2@7..8#ROOT2024
-              PUNCH   , [alone] 42:2@8..9#ROOT2024
-              LITERAL Integer 1 42:2@10..11#ROOT2024
-              PUNCH   , [alone] 42:2@11..12#ROOT2024
-              SUBTREE [] 42:2@13..14#ROOT2024 42:2@14..15#ROOT2024"#]],
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+              IDENT   ident 42:Root[0000, 0]@0..5#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@5..6#ROOT2024
+              LITERAL Integer 0 42:Root[0000, 0]@7..8#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@8..9#ROOT2024
+              LITERAL Integer 1 42:Root[0000, 0]@10..11#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@11..12#ROOT2024
+              SUBTREE [] 42:Root[0000, 0]@13..14#ROOT2024 42:Root[0000, 0]@14..15#ROOT2024
+
+
+
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+              IDENT   ident 42:Root[0000, 0]@0..5#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@5..6#ROOT2024
+              LITERAL Integer 0 42:Root[0000, 0]@7..8#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@8..9#ROOT2024
+              LITERAL Integer 1 42:Root[0000, 0]@10..11#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@11..12#ROOT2024
+              SUBTREE [] 42:Root[0000, 0]@13..14#ROOT2024 42:Root[0000, 0]@14..15#ROOT2024"#]],
     );
 }
 
@@ -134,17 +134,17 @@ fn test_fn_like_macro_clone_ident_subtree() {
               PUNCH   , [alone] 1
               SUBTREE [] 1 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-              IDENT   ident 42:2@0..5#ROOT2024
-              PUNCH   , [alone] 42:2@5..6#ROOT2024
-              SUBTREE [] 42:2@7..8#ROOT2024 42:2@8..9#ROOT2024
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+              IDENT   ident 42:Root[0000, 0]@0..5#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@5..6#ROOT2024
+              SUBTREE [] 42:Root[0000, 0]@7..8#ROOT2024 42:Root[0000, 0]@8..9#ROOT2024
 
 
 
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-              IDENT   ident 42:2@0..5#ROOT2024
-              PUNCH   , [alone] 42:2@5..6#ROOT2024
-              SUBTREE [] 42:2@7..9#ROOT2024 42:2@7..9#ROOT2024"#]],
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+              IDENT   ident 42:Root[0000, 0]@0..5#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@5..6#ROOT2024
+              SUBTREE [] 42:Root[0000, 0]@7..9#ROOT2024 42:Root[0000, 0]@7..9#ROOT2024"#]],
     );
 }
 
@@ -162,13 +162,13 @@ fn test_fn_like_macro_clone_raw_ident() {
             SUBTREE $$ 1 1
               IDENT   r#async 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-              IDENT   r#async 42:2@0..7#ROOT2024
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+              IDENT   r#async 42:Root[0000, 0]@0..7#ROOT2024
 
 
 
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-              IDENT   r#async 42:2@0..7#ROOT2024"#]],
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+              IDENT   r#async 42:Root[0000, 0]@0..7#ROOT2024"#]],
     );
 }
 
@@ -187,14 +187,14 @@ fn test_fn_like_fn_like_span_join() {
             SUBTREE $$ 1 1
               IDENT   r#joined 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-              IDENT   foo 42:2@0..3#ROOT2024
-              IDENT   bar 42:2@8..11#ROOT2024
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+              IDENT   foo 42:Root[0000, 0]@0..3#ROOT2024
+              IDENT   bar 42:Root[0000, 0]@8..11#ROOT2024
 
 
 
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-              IDENT   r#joined 42:2@0..11#ROOT2024"#]],
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+              IDENT   r#joined 42:Root[0000, 0]@0..11#ROOT2024"#]],
     );
 }
 
@@ -216,17 +216,17 @@ fn test_fn_like_fn_like_span_ops() {
               IDENT   resolved_at_def_site 1
               IDENT   start_span 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-              IDENT   set_def_site 42:2@0..12#ROOT2024
-              IDENT   resolved_at_def_site 42:2@13..33#ROOT2024
-              IDENT   start_span 42:2@34..44#ROOT2024
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+              IDENT   set_def_site 42:Root[0000, 0]@0..12#ROOT2024
+              IDENT   resolved_at_def_site 42:Root[0000, 0]@13..33#ROOT2024
+              IDENT   start_span 42:Root[0000, 0]@34..44#ROOT2024
 
 
 
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-              IDENT   set_def_site 41:1@0..150#ROOT2024
-              IDENT   resolved_at_def_site 42:2@13..33#ROOT2024
-              IDENT   start_span 42:2@34..34#ROOT2024"#]],
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+              IDENT   set_def_site 41:Root[0000, 0]@0..150#ROOT2024
+              IDENT   resolved_at_def_site 42:Root[0000, 0]@13..33#ROOT2024
+              IDENT   start_span 42:Root[0000, 0]@34..34#ROOT2024"#]],
     );
 }
 
@@ -244,6 +244,7 @@ fn test_fn_like_mk_literals() {
               LITERAL ByteStr byte_string 1
               LITERAL Char c 1
               LITERAL Str string 1
+              LITERAL Str -string 1
               LITERAL CStr cstring 1
               LITERAL Float 3.14f64 1
               PUNCH   - [alone] 1
@@ -258,27 +259,28 @@ fn test_fn_like_mk_literals() {
               PUNCH   - [alone] 1
               LITERAL Integer 123 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-
-
-
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-              LITERAL ByteStr byte_string 42:2@0..100#ROOT2024
-              LITERAL Char c 42:2@0..100#ROOT2024
-              LITERAL Str string 42:2@0..100#ROOT2024
-              LITERAL CStr cstring 42:2@0..100#ROOT2024
-              LITERAL Float 3.14f64 42:2@0..100#ROOT2024
-              PUNCH   - [alone] 42:2@0..100#ROOT2024
-              LITERAL Float 3.14f64 42:2@0..100#ROOT2024
-              LITERAL Float 3.14 42:2@0..100#ROOT2024
-              PUNCH   - [alone] 42:2@0..100#ROOT2024
-              LITERAL Float 3.14 42:2@0..100#ROOT2024
-              LITERAL Integer 123i64 42:2@0..100#ROOT2024
-              PUNCH   - [alone] 42:2@0..100#ROOT2024
-              LITERAL Integer 123i64 42:2@0..100#ROOT2024
-              LITERAL Integer 123 42:2@0..100#ROOT2024
-              PUNCH   - [alone] 42:2@0..100#ROOT2024
-              LITERAL Integer 123 42:2@0..100#ROOT2024"#]],
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+
+
+
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+              LITERAL ByteStr byte_string 42:Root[0000, 0]@0..100#ROOT2024
+              LITERAL Char c 42:Root[0000, 0]@0..100#ROOT2024
+              LITERAL Str string 42:Root[0000, 0]@0..100#ROOT2024
+              LITERAL Str -string 42:Root[0000, 0]@0..100#ROOT2024
+              LITERAL CStr cstring 42:Root[0000, 0]@0..100#ROOT2024
+              LITERAL Float 3.14f64 42:Root[0000, 0]@0..100#ROOT2024
+              PUNCH   - [alone] 42:Root[0000, 0]@0..100#ROOT2024
+              LITERAL Float 3.14f64 42:Root[0000, 0]@0..100#ROOT2024
+              LITERAL Float 3.14 42:Root[0000, 0]@0..100#ROOT2024
+              PUNCH   - [alone] 42:Root[0000, 0]@0..100#ROOT2024
+              LITERAL Float 3.14 42:Root[0000, 0]@0..100#ROOT2024
+              LITERAL Integer 123i64 42:Root[0000, 0]@0..100#ROOT2024
+              PUNCH   - [alone] 42:Root[0000, 0]@0..100#ROOT2024
+              LITERAL Integer 123i64 42:Root[0000, 0]@0..100#ROOT2024
+              LITERAL Integer 123 42:Root[0000, 0]@0..100#ROOT2024
+              PUNCH   - [alone] 42:Root[0000, 0]@0..100#ROOT2024
+              LITERAL Integer 123 42:Root[0000, 0]@0..100#ROOT2024"#]],
     );
 }
 
@@ -296,13 +298,13 @@ fn test_fn_like_mk_idents() {
               IDENT   standard 1
               IDENT   r#raw 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
 
 
 
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-              IDENT   standard 42:2@0..100#ROOT2024
-              IDENT   r#raw 42:2@0..100#ROOT2024"#]],
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+              IDENT   standard 42:Root[0000, 0]@0..100#ROOT2024
+              IDENT   r#raw 42:Root[0000, 0]@0..100#ROOT2024"#]],
     );
 }
 
@@ -358,51 +360,51 @@ fn test_fn_like_macro_clone_literals() {
               PUNCH   , [alone] 1
               LITERAL CStr null 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-              LITERAL Integer 1u16 42:2@0..4#ROOT2024
-              PUNCH   , [alone] 42:2@4..5#ROOT2024
-              LITERAL Integer 2_u32 42:2@6..11#ROOT2024
-              PUNCH   , [alone] 42:2@11..12#ROOT2024
-              PUNCH   - [alone] 42:2@13..14#ROOT2024
-              LITERAL Integer 4i64 42:2@14..18#ROOT2024
-              PUNCH   , [alone] 42:2@18..19#ROOT2024
-              LITERAL Float 3.14f32 42:2@20..27#ROOT2024
-              PUNCH   , [alone] 42:2@27..28#ROOT2024
-              LITERAL Str hello bridge 42:2@29..43#ROOT2024
-              PUNCH   , [alone] 42:2@43..44#ROOT2024
-              LITERAL Str suffixedsuffix 42:2@45..61#ROOT2024
-              PUNCH   , [alone] 42:2@61..62#ROOT2024
-              LITERAL StrRaw(2) raw 42:2@63..73#ROOT2024
-              PUNCH   , [alone] 42:2@73..74#ROOT2024
-              LITERAL Char a 42:2@75..78#ROOT2024
-              PUNCH   , [alone] 42:2@78..79#ROOT2024
-              LITERAL Byte b 42:2@80..84#ROOT2024
-              PUNCH   , [alone] 42:2@84..85#ROOT2024
-              LITERAL CStr null 42:2@86..93#ROOT2024
-
-
-
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-              LITERAL Integer 1u16 42:2@0..4#ROOT2024
-              PUNCH   , [alone] 42:2@4..5#ROOT2024
-              LITERAL Integer 2_u32 42:2@6..11#ROOT2024
-              PUNCH   , [alone] 42:2@11..12#ROOT2024
-              PUNCH   - [alone] 42:2@13..14#ROOT2024
-              LITERAL Integer 4i64 42:2@14..18#ROOT2024
-              PUNCH   , [alone] 42:2@18..19#ROOT2024
-              LITERAL Float 3.14f32 42:2@20..27#ROOT2024
-              PUNCH   , [alone] 42:2@27..28#ROOT2024
-              LITERAL Str hello bridge 42:2@29..43#ROOT2024
-              PUNCH   , [alone] 42:2@43..44#ROOT2024
-              LITERAL Str suffixedsuffix 42:2@45..61#ROOT2024
-              PUNCH   , [alone] 42:2@61..62#ROOT2024
-              LITERAL StrRaw(2) raw 42:2@63..73#ROOT2024
-              PUNCH   , [alone] 42:2@73..74#ROOT2024
-              LITERAL Char a 42:2@75..78#ROOT2024
-              PUNCH   , [alone] 42:2@78..79#ROOT2024
-              LITERAL Byte b 42:2@80..84#ROOT2024
-              PUNCH   , [alone] 42:2@84..85#ROOT2024
-              LITERAL CStr null 42:2@86..93#ROOT2024"#]],
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+              LITERAL Integer 1u16 42:Root[0000, 0]@0..4#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@4..5#ROOT2024
+              LITERAL Integer 2_u32 42:Root[0000, 0]@6..11#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@11..12#ROOT2024
+              PUNCH   - [alone] 42:Root[0000, 0]@13..14#ROOT2024
+              LITERAL Integer 4i64 42:Root[0000, 0]@14..18#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@18..19#ROOT2024
+              LITERAL Float 3.14f32 42:Root[0000, 0]@20..27#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@27..28#ROOT2024
+              LITERAL Str hello bridge 42:Root[0000, 0]@29..43#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@43..44#ROOT2024
+              LITERAL Str suffixedsuffix 42:Root[0000, 0]@45..61#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@61..62#ROOT2024
+              LITERAL StrRaw(2) raw 42:Root[0000, 0]@63..73#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@73..74#ROOT2024
+              LITERAL Char a 42:Root[0000, 0]@75..78#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@78..79#ROOT2024
+              LITERAL Byte b 42:Root[0000, 0]@80..84#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@84..85#ROOT2024
+              LITERAL CStr null 42:Root[0000, 0]@86..93#ROOT2024
+
+
+
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+              LITERAL Integer 1u16 42:Root[0000, 0]@0..4#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@4..5#ROOT2024
+              LITERAL Integer 2_u32 42:Root[0000, 0]@6..11#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@11..12#ROOT2024
+              PUNCH   - [alone] 42:Root[0000, 0]@13..14#ROOT2024
+              LITERAL Integer 4i64 42:Root[0000, 0]@14..18#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@18..19#ROOT2024
+              LITERAL Float 3.14f32 42:Root[0000, 0]@20..27#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@27..28#ROOT2024
+              LITERAL Str hello bridge 42:Root[0000, 0]@29..43#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@43..44#ROOT2024
+              LITERAL Str suffixedsuffix 42:Root[0000, 0]@45..61#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@61..62#ROOT2024
+              LITERAL StrRaw(2) raw 42:Root[0000, 0]@63..73#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@73..74#ROOT2024
+              LITERAL Char a 42:Root[0000, 0]@75..78#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@78..79#ROOT2024
+              LITERAL Byte b 42:Root[0000, 0]@80..84#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@84..85#ROOT2024
+              LITERAL CStr null 42:Root[0000, 0]@86..93#ROOT2024"#]],
     );
 }
 
@@ -440,33 +442,33 @@ fn test_fn_like_macro_negative_literals() {
               PUNCH   - [alone] 1
               LITERAL Float 2.7 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-              PUNCH   - [alone] 42:2@0..1#ROOT2024
-              LITERAL Integer 1u16 42:2@1..5#ROOT2024
-              PUNCH   , [alone] 42:2@5..6#ROOT2024
-              PUNCH   - [alone] 42:2@7..8#ROOT2024
-              LITERAL Integer 2_u32 42:2@9..14#ROOT2024
-              PUNCH   , [alone] 42:2@14..15#ROOT2024
-              PUNCH   - [alone] 42:2@16..17#ROOT2024
-              LITERAL Float 3.14f32 42:2@17..24#ROOT2024
-              PUNCH   , [alone] 42:2@24..25#ROOT2024
-              PUNCH   - [alone] 42:2@26..27#ROOT2024
-              LITERAL Float 2.7 42:2@28..31#ROOT2024
-
-
-
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-              PUNCH   - [alone] 42:2@0..1#ROOT2024
-              LITERAL Integer 1u16 42:2@1..5#ROOT2024
-              PUNCH   , [alone] 42:2@5..6#ROOT2024
-              PUNCH   - [alone] 42:2@7..8#ROOT2024
-              LITERAL Integer 2_u32 42:2@9..14#ROOT2024
-              PUNCH   , [alone] 42:2@14..15#ROOT2024
-              PUNCH   - [alone] 42:2@16..17#ROOT2024
-              LITERAL Float 3.14f32 42:2@17..24#ROOT2024
-              PUNCH   , [alone] 42:2@24..25#ROOT2024
-              PUNCH   - [alone] 42:2@26..27#ROOT2024
-              LITERAL Float 2.7 42:2@28..31#ROOT2024"#]],
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+              PUNCH   - [alone] 42:Root[0000, 0]@0..1#ROOT2024
+              LITERAL Integer 1u16 42:Root[0000, 0]@1..5#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@5..6#ROOT2024
+              PUNCH   - [alone] 42:Root[0000, 0]@7..8#ROOT2024
+              LITERAL Integer 2_u32 42:Root[0000, 0]@9..14#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@14..15#ROOT2024
+              PUNCH   - [alone] 42:Root[0000, 0]@16..17#ROOT2024
+              LITERAL Float 3.14f32 42:Root[0000, 0]@17..24#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@24..25#ROOT2024
+              PUNCH   - [alone] 42:Root[0000, 0]@26..27#ROOT2024
+              LITERAL Float 2.7 42:Root[0000, 0]@28..31#ROOT2024
+
+
+
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+              PUNCH   - [alone] 42:Root[0000, 0]@0..1#ROOT2024
+              LITERAL Integer 1u16 42:Root[0000, 0]@1..5#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@5..6#ROOT2024
+              PUNCH   - [alone] 42:Root[0000, 0]@7..8#ROOT2024
+              LITERAL Integer 2_u32 42:Root[0000, 0]@9..14#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@14..15#ROOT2024
+              PUNCH   - [alone] 42:Root[0000, 0]@16..17#ROOT2024
+              LITERAL Float 3.14f32 42:Root[0000, 0]@17..24#ROOT2024
+              PUNCH   , [alone] 42:Root[0000, 0]@24..25#ROOT2024
+              PUNCH   - [alone] 42:Root[0000, 0]@26..27#ROOT2024
+              LITERAL Float 2.7 42:Root[0000, 0]@28..31#ROOT2024"#]],
     );
 }
 
@@ -496,21 +498,21 @@ fn test_attr_macro() {
                 LITERAL Str #[attr_error(some arguments)] mod m {} 1
               PUNCH   ; [alone] 1"#]],
         expect![[r#"
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-              IDENT   mod 42:2@0..3#ROOT2024
-              IDENT   m 42:2@4..5#ROOT2024
-              SUBTREE {} 42:2@6..7#ROOT2024 42:2@7..8#ROOT2024
-
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-              IDENT   some 42:2@0..4#ROOT2024
-              IDENT   arguments 42:2@5..14#ROOT2024
-
-            SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-              IDENT   compile_error 42:2@0..100#ROOT2024
-              PUNCH   ! [alone] 42:2@0..100#ROOT2024
-              SUBTREE () 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
-                LITERAL Str #[attr_error(some arguments)] mod m {} 42:2@0..100#ROOT2024
-              PUNCH   ; [alone] 42:2@0..100#ROOT2024"#]],
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+              IDENT   mod 42:Root[0000, 0]@0..3#ROOT2024
+              IDENT   m 42:Root[0000, 0]@4..5#ROOT2024
+              SUBTREE {} 42:Root[0000, 0]@6..7#ROOT2024 42:Root[0000, 0]@7..8#ROOT2024
+
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+              IDENT   some 42:Root[0000, 0]@0..4#ROOT2024
+              IDENT   arguments 42:Root[0000, 0]@5..14#ROOT2024
+
+            SUBTREE $$ 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+              IDENT   compile_error 42:Root[0000, 0]@0..100#ROOT2024
+              PUNCH   ! [alone] 42:Root[0000, 0]@0..100#ROOT2024
+              SUBTREE () 42:Root[0000, 0]@0..100#ROOT2024 42:Root[0000, 0]@0..100#ROOT2024
+                LITERAL Str #[attr_error(some arguments)] mod m {} 42:Root[0000, 0]@0..100#ROOT2024
+              PUNCH   ; [alone] 42:Root[0000, 0]@0..100#ROOT2024"#]],
     );
 }
 
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs
index a0a45b269e4..10af5662b5c 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs
@@ -1,7 +1,9 @@
 //! utils used in proc-macro tests
 
 use expect_test::Expect;
-use span::{EditionedFileId, ErasedFileAstId, FileId, Span, SpanAnchor, SyntaxContext, TokenId};
+use span::{
+    EditionedFileId, FileId, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SyntaxContext, TokenId,
+};
 use tt::TextRange;
 
 use crate::{EnvSnapshot, ProcMacroSrv, dylib, proc_macro_test_dylib_path};
@@ -76,7 +78,7 @@ fn assert_expand_impl(
         range: TextRange::new(0.into(), 150.into()),
         anchor: SpanAnchor {
             file_id: EditionedFileId::current_edition(FileId::from_raw(41)),
-            ast_id: ErasedFileAstId::from_raw(1),
+            ast_id: ROOT_ERASED_FILE_AST_ID,
         },
         ctx: SyntaxContext::root(span::Edition::CURRENT),
     };
@@ -84,7 +86,7 @@ fn assert_expand_impl(
         range: TextRange::new(0.into(), 100.into()),
         anchor: SpanAnchor {
             file_id: EditionedFileId::current_edition(FileId::from_raw(42)),
-            ast_id: ErasedFileAstId::from_raw(2),
+            ast_id: ROOT_ERASED_FILE_AST_ID,
         },
         ctx: SyntaxContext::root(span::Edition::CURRENT),
     };
diff --git a/src/tools/rust-analyzer/crates/profile/Cargo.toml b/src/tools/rust-analyzer/crates/profile/Cargo.toml
index 1fb13832720..bae891c1984 100644
--- a/src/tools/rust-analyzer/crates/profile/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/profile/Cargo.toml
@@ -12,7 +12,7 @@ rust-version.workspace = true
 [lib]
 
 [dependencies]
-cfg-if = "1.0.0"
+cfg-if = "1.0.1"
 jemalloc-ctl = { version = "0.5.4", package = "tikv-jemalloc-ctl", optional = true }
 
 [target.'cfg(all(target_os = "linux", not(target_env = "ohos")))'.dependencies]
@@ -22,7 +22,7 @@ perf-event = "=0.4.7"
 libc.workspace = true
 
 [target.'cfg(windows)'.dependencies]
-windows-sys = { version = "0.59", features = [
+windows-sys = { version = "0.60", features = [
     "Win32_System_Threading",
     "Win32_System_ProcessStatus",
 ] }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
index bb02284a513..1fade7b3323 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
@@ -492,7 +492,7 @@ impl CargoWorkspace {
             is_virtual_workspace &= manifest != ws_manifest_path;
             let pkg = packages.alloc(PackageData {
                 id: id.repr.clone(),
-                name,
+                name: name.to_string(),
                 version,
                 manifest: manifest.clone(),
                 targets: Vec::new(),
@@ -547,10 +547,12 @@ impl CargoWorkspace {
                 .flat_map(|dep| DepKind::iter(&dep.dep_kinds).map(move |kind| (dep, kind)));
             for (dep_node, kind) in dependencies {
                 let &pkg = pkg_by_id.get(&dep_node.pkg).unwrap();
-                let dep = PackageDependency { name: dep_node.name.clone(), pkg, kind };
+                let dep = PackageDependency { name: dep_node.name.to_string(), pkg, kind };
                 packages[source].dependencies.push(dep);
             }
-            packages[source].active_features.extend(node.features);
+            packages[source]
+                .active_features
+                .extend(node.features.into_iter().map(|it| it.to_string()));
         }
 
         CargoWorkspace {
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 d4055d9a0af..ebd86e3dc48 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
@@ -339,7 +339,7 @@ impl Sysroot {
                     Some(_) => {
                         tracing::warn!("unknown rustc-std-workspace-* crate: {}", package.name)
                     }
-                    None => match &*package.name {
+                    None => match &**package.name {
                         "core" => real_core = Some(package.id.clone()),
                         "alloc" => real_alloc = Some(package.id.clone()),
                         "std" => real_std = Some(package.id.clone()),
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
index b59d06838e0..5e63521d747 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
@@ -29,7 +29,7 @@ indexmap.workspace = true
 itertools.workspace = true
 scip = "0.5.2"
 lsp-types = { version = "=0.95.0", features = ["proposed"] }
-parking_lot = "0.12.3"
+parking_lot = "0.12.4"
 xflags = "0.3.2"
 oorandom = "11.1.5"
 rayon.workspace = true
@@ -37,19 +37,19 @@ rustc-hash.workspace = true
 serde_json = { workspace = true, features = ["preserve_order"] }
 serde.workspace = true
 serde_derive.workspace = true
-tenthash = "1.0.0"
-num_cpus = "1.16.0"
-mimalloc = { version = "0.1.44", default-features = false, optional = true }
+tenthash = "1.1.0"
+num_cpus = "1.17.0"
+mimalloc = { version = "0.1.46", default-features = false, optional = true }
 lsp-server.workspace = true
 tracing.workspace = true
 tracing-subscriber.workspace = true
 tracing-tree.workspace = true
 triomphe.workspace = true
-toml = "0.8.20"
+toml = "0.8.23"
 nohash-hasher.workspace = true
 walkdir = "2.5.0"
 semver.workspace = true
-memchr = "2.7.4"
+memchr = "2.7.5"
 cargo_metadata.workspace = true
 process-wrap.workspace = true
 
@@ -75,7 +75,7 @@ vfs.workspace = true
 paths.workspace = true
 
 [target.'cfg(windows)'.dependencies]
-windows-sys = { version = "0.59", features = [
+windows-sys = { version = "0.60", features = [
   "Win32_System_Diagnostics_Debug",
   "Win32_System_Threading",
 ] }
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 5cbea9c2b3d..762b63f54b0 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -760,6 +760,8 @@ config_data! {
         /// though Cargo might be the eventual consumer.
         vfs_extraIncludes: Vec<String> = vec![],
 
+        /// Exclude imports from symbol search.
+        workspace_symbol_search_excludeImports: bool = false,
         /// Workspace symbol search kind.
         workspace_symbol_search_kind: WorkspaceSymbolSearchKindDef = WorkspaceSymbolSearchKindDef::OnlyTypes,
         /// Limits the number of items returned from a workspace symbol search (Defaults to 128).
@@ -1352,6 +1354,8 @@ pub struct RunnablesConfig {
 /// Configuration for workspace symbol search requests.
 #[derive(Debug, Clone)]
 pub struct WorkspaceSymbolConfig {
+    /// Should imports be excluded.
+    pub search_exclude_imports: bool,
     /// In what scope should the symbol be searched in.
     pub search_scope: WorkspaceSymbolSearchScope,
     /// What kind of symbol is being searched for.
@@ -2280,6 +2284,7 @@ impl Config {
 
     pub fn workspace_symbol(&self, source_root: Option<SourceRootId>) -> WorkspaceSymbolConfig {
         WorkspaceSymbolConfig {
+            search_exclude_imports: *self.workspace_symbol_search_excludeImports(source_root),
             search_scope: match self.workspace_symbol_search_scope(source_root) {
                 WorkspaceSymbolSearchScopeDef::Workspace => WorkspaceSymbolSearchScope::Workspace,
                 WorkspaceSymbolSearchScopeDef::WorkspaceAndDependencies => {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
index 6d46ce68ed4..afd9eff5264 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
@@ -658,6 +658,9 @@ pub(crate) fn handle_workspace_symbol(
         if libs {
             q.libs();
         }
+        if config.search_exclude_imports {
+            q.exclude_imports();
+        }
         q
     };
     let mut res = exec_query(&snap, query, config.search_limit)?;
diff --git a/src/tools/rust-analyzer/crates/span/Cargo.toml b/src/tools/rust-analyzer/crates/span/Cargo.toml
index b3b401c3db4..966962bab38 100644
--- a/src/tools/rust-analyzer/crates/span/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/span/Cargo.toml
@@ -22,6 +22,9 @@ vfs.workspace = true
 syntax.workspace = true
 stdx.workspace = true
 
+[dev-dependencies]
+syntax.workspace = true
+
 [features]
 default = ["salsa"]
 
diff --git a/src/tools/rust-analyzer/crates/span/src/ast_id.rs b/src/tools/rust-analyzer/crates/span/src/ast_id.rs
index 228fba1fa09..8e959711981 100644
--- a/src/tools/rust-analyzer/crates/span/src/ast_id.rs
+++ b/src/tools/rust-analyzer/crates/span/src/ast_id.rs
@@ -4,137 +4,535 @@
 //! Specifically, it enumerates all items in a file and uses position of a an
 //! item as an ID. That way, id's don't change unless the set of items itself
 //! changes.
+//!
+//! These IDs are tricky. If one of them invalidates, its interned ID invalidates,
+//! and this can cause *a lot* to be recomputed. For example, if you invalidate the ID
+//! of a struct, and that struct has an impl (any impl!) this will cause the `Self`
+//! type of the impl to invalidate, which will cause the all impls queries to be
+//! invalidated, which will cause every trait solve query in this crate *and* all
+//! transitive reverse dependencies to be invalidated, which is pretty much the worst
+//! thing that can happen incrementality wise.
+//!
+//! So we want these IDs to stay as stable as possible. For top-level items, we store
+//! their kind and name, which should be unique, but since they can still not be, we
+//! also store an index disambiguator. For nested items, we also store the ID of their
+//! parent. For macro calls, we store the macro name and an index. There aren't usually
+//! a lot of macro calls in item position, and invalidation in bodies is not much of
+//! a problem, so this should be enough.
 
 use std::{
     any::type_name,
     fmt,
-    hash::{BuildHasher, BuildHasherDefault, Hash, Hasher},
+    hash::{BuildHasher, Hash, Hasher},
     marker::PhantomData,
 };
 
 use la_arena::{Arena, Idx, RawIdx};
-use rustc_hash::FxHasher;
-use syntax::{AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, ast};
+use rustc_hash::{FxBuildHasher, FxHashMap};
+use syntax::{
+    AstNode, AstPtr, SyntaxKind, SyntaxNode, SyntaxNodePtr,
+    ast::{self, HasName},
+    match_ast,
+};
+
+// The first index is always the root node's AstId
+/// The root ast id always points to the encompassing file, using this in spans is discouraged as
+/// any range relative to it will be effectively absolute, ruining the entire point of anchored
+/// relative text ranges.
+pub const ROOT_ERASED_FILE_AST_ID: ErasedFileAstId =
+    ErasedFileAstId(pack_hash_index_and_kind(0, 0, ErasedFileAstIdKind::Root as u32));
+
+/// ErasedFileAstId used as the span for syntax node fixups. Any Span containing this file id is to be
+/// considered fake.
+pub const FIXUP_ERASED_FILE_AST_ID_MARKER: ErasedFileAstId =
+    ErasedFileAstId(pack_hash_index_and_kind(0, 0, ErasedFileAstIdKind::Fixup as u32));
 
-/// See crates\hir-expand\src\ast_id_map.rs
 /// This is a type erased FileAstId.
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub struct ErasedFileAstId(u32);
 
+impl fmt::Debug for ErasedFileAstId {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let kind = self.kind();
+        macro_rules! kind {
+            ($($kind:ident),* $(,)?) => {
+                if false {
+                    // Ensure we covered all variants.
+                    match ErasedFileAstIdKind::Root {
+                        $( ErasedFileAstIdKind::$kind => {} )*
+                    }
+                    unreachable!()
+                }
+                $( else if kind == ErasedFileAstIdKind::$kind as u32 {
+                    stringify!($kind)
+                } )*
+                else {
+                    "Unknown"
+                }
+            };
+        }
+        let kind = kind!(
+            Root,
+            Enum,
+            Struct,
+            Union,
+            ExternCrate,
+            MacroDef,
+            MacroRules,
+            Module,
+            Static,
+            Trait,
+            TraitAlias,
+            Variant,
+            Const,
+            Fn,
+            MacroCall,
+            TypeAlias,
+            ExternBlock,
+            Use,
+            Impl,
+            BlockExpr,
+            Fixup,
+        );
+        if f.alternate() {
+            write!(f, "{kind}[{:04X}, {}]", self.hash_value(), self.index())
+        } else {
+            f.debug_struct("ErasedFileAstId")
+                .field("kind", &format_args!("{kind}"))
+                .field("index", &self.index())
+                .field("hash", &format_args!("{:04X}", self.hash_value()))
+                .finish()
+        }
+    }
+}
+
+#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
+enum ErasedFileAstIdKind {
+    /// This needs to not change because it's depended upon by the proc macro server.
+    Fixup,
+    // The following are associated with `ErasedHasNameFileAstId`.
+    Enum,
+    Struct,
+    Union,
+    ExternCrate,
+    MacroDef,
+    MacroRules,
+    Module,
+    Static,
+    Trait,
+    TraitAlias,
+    // Until here associated with `ErasedHasNameFileAstId`.
+    // The following are associated with `ErasedAssocItemFileAstId`.
+    Variant,
+    Const,
+    Fn,
+    MacroCall,
+    TypeAlias,
+    // Until here associated with `ErasedAssocItemFileAstId`.
+    // Extern blocks don't really have any identifying property unfortunately.
+    ExternBlock,
+    // FIXME: If we store the final `UseTree` instead of the top-level `Use`, we can store its name,
+    // and be way more granular for incrementality, at the expense of increased memory usage.
+    // Use IDs aren't used a lot. The main thing that stores them is the def map. So everything that
+    // uses the def map will be invalidated. That includes infers, and so is pretty bad, but our
+    // def map incrementality story is pretty bad anyway and needs to be improved (see
+    // https://rust-lang.zulipchat.com/#narrow/channel/185405-t-compiler.2Frust-analyzer/topic/.60infer.60.20queries.20and.20splitting.20.60DefMap.60).
+    // So I left this as-is for now, as the def map improvement should also mitigate this.
+    Use,
+    /// Associated with [`ImplFileAstId`].
+    Impl,
+    /// Associated with [`BlockExprFileAstId`].
+    BlockExpr,
+    /// Keep this last.
+    Root,
+}
+
+// First hash, then index, then kind.
+const HASH_BITS: u32 = 16;
+const INDEX_BITS: u32 = 11;
+const KIND_BITS: u32 = 5;
+const _: () = assert!(ErasedFileAstIdKind::Fixup as u32 <= ((1 << KIND_BITS) - 1));
+const _: () = assert!(HASH_BITS + INDEX_BITS + KIND_BITS == u32::BITS);
+
+#[inline]
+const fn u16_hash(hash: u64) -> u16 {
+    // We do basically the same as `FxHasher`. We don't use rustc-hash and truncate because the
+    // higher bits have more entropy, but unlike rustc-hash we don't rotate because it rotates
+    // for hashmaps that just use the low bits, but we compare all bits.
+    const K: u16 = 0xecc5;
+    let (part1, part2, part3, part4) =
+        (hash as u16, (hash >> 16) as u16, (hash >> 32) as u16, (hash >> 48) as u16);
+    part1
+        .wrapping_add(part2)
+        .wrapping_mul(K)
+        .wrapping_add(part3)
+        .wrapping_mul(K)
+        .wrapping_add(part4)
+        .wrapping_mul(K)
+}
+
+#[inline]
+const fn pack_hash_index_and_kind(hash: u16, index: u32, kind: u32) -> u32 {
+    (hash as u32) | (index << HASH_BITS) | (kind << (HASH_BITS + INDEX_BITS))
+}
+
 impl ErasedFileAstId {
-    pub const fn into_raw(self) -> u32 {
-        self.0
+    #[inline]
+    fn hash_value(self) -> u16 {
+        self.0 as u16
     }
-    pub const fn from_raw(u32: u32) -> Self {
-        Self(u32)
+
+    #[inline]
+    fn index(self) -> u32 {
+        (self.0 << KIND_BITS) >> (HASH_BITS + KIND_BITS)
     }
-}
 
-impl fmt::Display for ErasedFileAstId {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.0.fmt(f)
+    #[inline]
+    fn kind(self) -> u32 {
+        self.0 >> (HASH_BITS + INDEX_BITS)
     }
-}
-impl fmt::Debug for ErasedFileAstId {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        self.0.fmt(f)
+
+    fn ast_id_for(
+        node: &SyntaxNode,
+        index_map: &mut ErasedAstIdNextIndexMap,
+        parent: Option<&ErasedFileAstId>,
+    ) -> Option<ErasedFileAstId> {
+        // Blocks are deliberately not here - we only want to allocate a block if it contains items.
+        has_name_ast_id(node, index_map)
+            .or_else(|| assoc_item_ast_id(node, index_map, parent))
+            .or_else(|| extern_block_ast_id(node, index_map))
+            .or_else(|| use_ast_id(node, index_map))
+            .or_else(|| impl_ast_id(node, index_map))
+    }
+
+    fn should_alloc(node: &SyntaxNode) -> bool {
+        should_alloc_has_name(node)
+            || should_alloc_assoc_item(node)
+            || ast::ExternBlock::can_cast(node.kind())
+            || ast::Use::can_cast(node.kind())
+            || ast::Impl::can_cast(node.kind())
+    }
+
+    #[inline]
+    pub fn into_raw(self) -> u32 {
+        self.0
+    }
+
+    #[inline]
+    pub const fn from_raw(v: u32) -> Self {
+        Self(v)
     }
 }
 
+pub trait AstIdNode: AstNode {}
+
 /// `AstId` points to an AST node in a specific file.
-pub struct FileAstId<N: AstIdNode> {
+pub struct FileAstId<N> {
     raw: ErasedFileAstId,
-    covariant: PhantomData<fn() -> N>,
+    _marker: PhantomData<fn() -> N>,
 }
 
-impl<N: AstIdNode> Clone for FileAstId<N> {
+/// Traits are manually implemented because `derive` adds redundant bounds.
+impl<N> Clone for FileAstId<N> {
+    #[inline]
     fn clone(&self) -> FileAstId<N> {
         *self
     }
 }
-impl<N: AstIdNode> Copy for FileAstId<N> {}
+impl<N> Copy for FileAstId<N> {}
 
-impl<N: AstIdNode> PartialEq for FileAstId<N> {
+impl<N> PartialEq for FileAstId<N> {
     fn eq(&self, other: &Self) -> bool {
         self.raw == other.raw
     }
 }
-impl<N: AstIdNode> Eq for FileAstId<N> {}
-impl<N: AstIdNode> Hash for FileAstId<N> {
+impl<N> Eq for FileAstId<N> {}
+impl<N> Hash for FileAstId<N> {
     fn hash<H: Hasher>(&self, hasher: &mut H) {
         self.raw.hash(hasher);
     }
 }
 
-impl<N: AstIdNode> fmt::Debug for FileAstId<N> {
+impl<N> fmt::Debug for FileAstId<N> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "FileAstId::<{}>({})", type_name::<N>(), self.raw)
+        write!(f, "FileAstId::<{}>({:?})", type_name::<N>(), self.raw)
     }
 }
 
-impl<N: AstIdNode> FileAstId<N> {
+impl<N> FileAstId<N> {
     // Can't make this a From implementation because of coherence
+    #[inline]
     pub fn upcast<M: AstIdNode>(self) -> FileAstId<M>
     where
         N: Into<M>,
     {
-        FileAstId { raw: self.raw, covariant: PhantomData }
+        FileAstId { raw: self.raw, _marker: PhantomData }
     }
 
+    #[inline]
     pub fn erase(self) -> ErasedFileAstId {
         self.raw
     }
 }
 
-pub trait AstIdNode: AstNode {}
-macro_rules! register_ast_id_node {
+#[derive(Hash)]
+struct ErasedHasNameFileAstId<'a> {
+    kind: SyntaxKind,
+    name: &'a str,
+}
+
+/// This holds the ast ID for variants too (they're a kind of assoc item).
+#[derive(Hash)]
+struct ErasedAssocItemFileAstId<'a> {
+    /// Subtle: items in `extern` blocks **do not** store the ID of the extern block here.
+    /// Instead this is left empty. The reason is that `ExternBlockFileAstId` is pretty unstable
+    /// (it contains only an index), and extern blocks don't introduce a new scope, so storing
+    /// the extern block ID will do more harm to incrementality than help.
+    parent: Option<ErasedFileAstId>,
+    properties: ErasedHasNameFileAstId<'a>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+struct ImplFileAstId<'a> {
+    /// This can be `None` if the `Self` type is not a named type, or if it is inside a macro call.
+    self_ty_name: Option<&'a str>,
+    /// This can be `None` if this is an inherent impl, or if the trait name is inside a macro call.
+    trait_name: Option<&'a str>,
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+struct BlockExprFileAstId {
+    parent: Option<ErasedFileAstId>,
+}
+
+impl AstIdNode for ast::ExternBlock {}
+
+fn extern_block_ast_id(
+    node: &SyntaxNode,
+    index_map: &mut ErasedAstIdNextIndexMap,
+) -> Option<ErasedFileAstId> {
+    if ast::ExternBlock::can_cast(node.kind()) {
+        Some(index_map.new_id(ErasedFileAstIdKind::ExternBlock, ()))
+    } else {
+        None
+    }
+}
+
+impl AstIdNode for ast::Use {}
+
+fn use_ast_id(
+    node: &SyntaxNode,
+    index_map: &mut ErasedAstIdNextIndexMap,
+) -> Option<ErasedFileAstId> {
+    if ast::Use::can_cast(node.kind()) {
+        Some(index_map.new_id(ErasedFileAstIdKind::Use, ()))
+    } else {
+        None
+    }
+}
+
+impl AstIdNode for ast::Impl {}
+
+fn impl_ast_id(
+    node: &SyntaxNode,
+    index_map: &mut ErasedAstIdNextIndexMap,
+) -> Option<ErasedFileAstId> {
+    if let Some(node) = ast::Impl::cast(node.clone()) {
+        let type_as_name = |ty: Option<ast::Type>| match ty? {
+            ast::Type::PathType(it) => Some(it.path()?.segment()?.name_ref()?),
+            _ => None,
+        };
+        let self_ty_name = type_as_name(node.self_ty());
+        let trait_name = type_as_name(node.trait_());
+        let data = ImplFileAstId {
+            self_ty_name: self_ty_name.as_ref().map(|it| it.text_non_mutable()),
+            trait_name: trait_name.as_ref().map(|it| it.text_non_mutable()),
+        };
+        Some(index_map.new_id(ErasedFileAstIdKind::Impl, data))
+    } else {
+        None
+    }
+}
+
+// Blocks aren't `AstIdNode`s deliberately, because unlike other nodes, not all blocks get their own
+// ast id, only if they have items. To account for that we have a different, fallible, API for blocks.
+// impl !AstIdNode for ast::BlockExpr {}
+
+fn block_expr_ast_id(
+    node: &SyntaxNode,
+    index_map: &mut ErasedAstIdNextIndexMap,
+    parent: Option<&ErasedFileAstId>,
+) -> Option<ErasedFileAstId> {
+    if ast::BlockExpr::can_cast(node.kind()) {
+        Some(
+            index_map.new_id(
+                ErasedFileAstIdKind::BlockExpr,
+                BlockExprFileAstId { parent: parent.copied() },
+            ),
+        )
+    } else {
+        None
+    }
+}
+
+#[derive(Default)]
+struct ErasedAstIdNextIndexMap(FxHashMap<(ErasedFileAstIdKind, u16), u32>);
+
+impl ErasedAstIdNextIndexMap {
+    #[inline]
+    fn new_id(&mut self, kind: ErasedFileAstIdKind, data: impl Hash) -> ErasedFileAstId {
+        let hash = FxBuildHasher.hash_one(&data);
+        let initial_hash = u16_hash(hash);
+        // Even though 2^INDEX_BITS=2048 items with the same hash seems like a lot,
+        // it could happen with macro calls or `use`s in macro-generated files. So we want
+        // to handle it gracefully. We just increment the hash.
+        let mut hash = initial_hash;
+        let index = loop {
+            match self.0.entry((kind, hash)) {
+                std::collections::hash_map::Entry::Occupied(mut entry) => {
+                    let i = entry.get_mut();
+                    if *i < ((1 << INDEX_BITS) - 1) {
+                        *i += 1;
+                        break *i;
+                    }
+                }
+                std::collections::hash_map::Entry::Vacant(entry) => {
+                    entry.insert(0);
+                    break 0;
+                }
+            }
+            hash = hash.wrapping_add(1);
+            if hash == initial_hash {
+                // That's 2^27=134,217,728 items!
+                panic!("you have way too many items in the same file!");
+            }
+        };
+        let kind = kind as u32;
+        ErasedFileAstId(pack_hash_index_and_kind(hash, index, kind))
+    }
+}
+
+macro_rules! register_enum_ast_id {
     (impl AstIdNode for $($ident:ident),+ ) => {
         $(
             impl AstIdNode for ast::$ident {}
         )+
-        fn should_alloc_id(kind: syntax::SyntaxKind) -> bool {
-            $(
-                ast::$ident::can_cast(kind)
-            )||+
+    };
+}
+register_enum_ast_id! {
+    impl AstIdNode for
+    Item, AnyHasGenericParams, Adt, Macro,
+    AssocItem
+}
+
+macro_rules! register_has_name_ast_id {
+    (impl AstIdNode for $($ident:ident = $name_method:ident),+ ) => {
+        $(
+            impl AstIdNode for ast::$ident {}
+        )+
+
+        fn has_name_ast_id(node: &SyntaxNode, index_map: &mut ErasedAstIdNextIndexMap) -> Option<ErasedFileAstId> {
+            let kind = node.kind();
+            match_ast! {
+                match node {
+                    $(
+                        ast::$ident(node) => {
+                            let name = node.$name_method();
+                            let name = name.as_ref().map_or("", |it| it.text_non_mutable());
+                            let result = ErasedHasNameFileAstId {
+                                kind,
+                                name,
+                            };
+                            Some(index_map.new_id(ErasedFileAstIdKind::$ident, result))
+                        },
+                    )*
+                    _ => None,
+                }
+            }
+        }
+
+        fn should_alloc_has_name(node: &SyntaxNode) -> bool {
+            let kind = node.kind();
+            false $( || ast::$ident::can_cast(kind) )*
         }
     };
 }
-register_ast_id_node! {
+register_has_name_ast_id! {
     impl AstIdNode for
-    Item, AnyHasGenericParams,
-        Adt,
-            Enum,
-                Variant,
-            Struct,
-            Union,
-        AssocItem,
-            Const,
-            Fn,
-            MacroCall,
-            TypeAlias,
-        ExternBlock,
-        ExternCrate,
-        Impl,
-        Macro,
-            MacroDef,
-            MacroRules,
-        Module,
-        Static,
-        Trait,
-        TraitAlias,
-        Use,
-    BlockExpr, ConstArg
+        Enum = name,
+        Struct = name,
+        Union = name,
+        ExternCrate = name_ref,
+        MacroDef = name,
+        MacroRules = name,
+        Module = name,
+        Static = name,
+        Trait = name,
+        TraitAlias = name
+}
+
+macro_rules! register_assoc_item_ast_id {
+    (impl AstIdNode for $($ident:ident = $name_callback:expr),+ ) => {
+        $(
+            impl AstIdNode for ast::$ident {}
+        )+
+
+        fn assoc_item_ast_id(
+            node: &SyntaxNode,
+            index_map: &mut ErasedAstIdNextIndexMap,
+            parent: Option<&ErasedFileAstId>,
+        ) -> Option<ErasedFileAstId> {
+            let kind = node.kind();
+            match_ast! {
+                match node {
+                    $(
+                        ast::$ident(node) => {
+                            let name = $name_callback(node);
+                            let name = name.as_ref().map_or("", |it| it.text_non_mutable());
+                            let properties = ErasedHasNameFileAstId {
+                                kind,
+                                name,
+                            };
+                            let result = ErasedAssocItemFileAstId {
+                                parent: parent.copied(),
+                                properties,
+                            };
+                            Some(index_map.new_id(ErasedFileAstIdKind::$ident, result))
+                        },
+                    )*
+                    _ => None,
+                }
+            }
+        }
+
+        fn should_alloc_assoc_item(node: &SyntaxNode) -> bool {
+            let kind = node.kind();
+            false $( || ast::$ident::can_cast(kind) )*
+        }
+    };
+}
+register_assoc_item_ast_id! {
+    impl AstIdNode for
+    Variant = |it: ast::Variant| it.name(),
+    Const = |it: ast::Const| it.name(),
+    Fn = |it: ast::Fn| it.name(),
+    MacroCall = |it: ast::MacroCall| it.path().and_then(|path| path.segment()?.name_ref()),
+    TypeAlias = |it: ast::TypeAlias| it.name()
 }
 
 /// Maps items' `SyntaxNode`s to `ErasedFileAstId`s and back.
 #[derive(Default)]
 pub struct AstIdMap {
-    /// Maps stable id to unstable ptr.
-    arena: Arena<SyntaxNodePtr>,
-    /// Reverse: map ptr to id.
-    map: hashbrown::HashTable<Idx<SyntaxNodePtr>>,
+    /// An arena of the ptrs and their associated ID.
+    arena: Arena<(SyntaxNodePtr, ErasedFileAstId)>,
+    /// Map ptr to id.
+    ptr_map: hashbrown::HashTable<ArenaId>,
+    /// Map id to ptr.
+    id_map: hashbrown::HashTable<ArenaId>,
 }
 
+type ArenaId = Idx<(SyntaxNodePtr, ErasedFileAstId)>;
+
 impl fmt::Debug for AstIdMap {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_struct("AstIdMap").field("arena", &self.arena).finish()
@@ -148,31 +546,116 @@ impl PartialEq for AstIdMap {
 }
 impl Eq for AstIdMap {}
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+enum ContainsItems {
+    Yes,
+    No,
+}
+
 impl AstIdMap {
     pub fn from_source(node: &SyntaxNode) -> AstIdMap {
         assert!(node.parent().is_none());
         let mut res = AstIdMap::default();
+        let mut index_map = ErasedAstIdNextIndexMap::default();
+
+        // Ensure we allocate the root.
+        res.arena.alloc((SyntaxNodePtr::new(node), ROOT_ERASED_FILE_AST_ID));
 
-        // make sure to allocate the root node
-        if !should_alloc_id(node.kind()) {
-            res.alloc(node);
-        }
         // By walking the tree in breadth-first order we make sure that parents
         // get lower ids then children. That is, adding a new child does not
         // change parent's id. This means that, say, adding a new function to a
         // trait does not change ids of top-level items, which helps caching.
-        bdfs(node, |it| {
-            if should_alloc_id(it.kind()) {
-                res.alloc(&it);
-                TreeOrder::BreadthFirst
-            } else {
-                TreeOrder::DepthFirst
+
+        // This contains the stack of the `BlockExpr`s we are under. We do this
+        // so we only allocate `BlockExpr`s if they contain items.
+        // The general idea is: when we enter a block we push `(block, false)` here.
+        // Items inside the block are attributed to the block's container, not the block.
+        // For the first item we find inside a block, we make this `(block, true)`
+        // and create an ast id for the block. When exiting the block we pop it,
+        // whether or not we created an ast id for it.
+        // It may seem that with this setup we will generate an ID for blocks that
+        // have no items directly but have items inside other items inside them.
+        // This is true, but it doesn't matter, because such blocks can't exist.
+        // After all, the block will then contain the *outer* item, so we allocate
+        // an ID for it anyway.
+        let mut blocks = Vec::new();
+        let mut curr_layer = vec![(node.clone(), None)];
+        let mut next_layer = vec![];
+        while !curr_layer.is_empty() {
+            curr_layer.drain(..).for_each(|(node, parent_idx)| {
+                let mut preorder = node.preorder();
+                while let Some(event) = preorder.next() {
+                    match event {
+                        syntax::WalkEvent::Enter(node) => {
+                            if ast::BlockExpr::can_cast(node.kind()) {
+                                blocks.push((node, ContainsItems::No));
+                            } else if ErasedFileAstId::should_alloc(&node) {
+                                // Allocate blocks on-demand, only if they have items.
+                                // We don't associate items with blocks, only with items, since block IDs can be quite unstable.
+                                // FIXME: Is this the correct thing to do? Macro calls might actually be more incremental if
+                                // associated with blocks (not sure). Either way it's not a big deal.
+                                if let Some((
+                                    last_block_node,
+                                    already_allocated @ ContainsItems::No,
+                                )) = blocks.last_mut()
+                                {
+                                    let block_ast_id = block_expr_ast_id(
+                                        last_block_node,
+                                        &mut index_map,
+                                        parent_of(parent_idx, &res),
+                                    )
+                                    .expect("not a BlockExpr");
+                                    res.arena
+                                        .alloc((SyntaxNodePtr::new(last_block_node), block_ast_id));
+                                    *already_allocated = ContainsItems::Yes;
+                                }
+
+                                let parent = parent_of(parent_idx, &res);
+                                let ast_id =
+                                    ErasedFileAstId::ast_id_for(&node, &mut index_map, parent)
+                                        .expect("this node should have an ast id");
+                                let idx = res.arena.alloc((SyntaxNodePtr::new(&node), ast_id));
+
+                                next_layer.extend(node.children().map(|child| (child, Some(idx))));
+                                preorder.skip_subtree();
+                            }
+                        }
+                        syntax::WalkEvent::Leave(node) => {
+                            if ast::BlockExpr::can_cast(node.kind()) {
+                                assert_eq!(
+                                    blocks.pop().map(|it| it.0),
+                                    Some(node),
+                                    "left a BlockExpr we never entered"
+                                );
+                            }
+                        }
+                    }
+                }
+            });
+            std::mem::swap(&mut curr_layer, &mut next_layer);
+            assert!(blocks.is_empty(), "didn't leave all BlockExprs");
+        }
+
+        res.ptr_map = hashbrown::HashTable::with_capacity(res.arena.len());
+        res.id_map = hashbrown::HashTable::with_capacity(res.arena.len());
+        for (idx, (ptr, ast_id)) in res.arena.iter() {
+            let ptr_hash = hash_ptr(ptr);
+            let ast_id_hash = hash_ast_id(ast_id);
+            match res.ptr_map.entry(
+                ptr_hash,
+                |idx2| *idx2 == idx,
+                |&idx| hash_ptr(&res.arena[idx].0),
+            ) {
+                hashbrown::hash_table::Entry::Occupied(_) => unreachable!(),
+                hashbrown::hash_table::Entry::Vacant(entry) => {
+                    entry.insert(idx);
+                }
             }
-        });
-        res.map = hashbrown::HashTable::with_capacity(res.arena.len());
-        for (idx, ptr) in res.arena.iter() {
-            let hash = hash_ptr(ptr);
-            match res.map.entry(hash, |&idx2| idx2 == idx, |&idx| hash_ptr(&res.arena[idx])) {
+            match res.id_map.entry(
+                ast_id_hash,
+                |idx2| *idx2 == idx,
+                |&idx| hash_ast_id(&res.arena[idx].1),
+            ) {
                 hashbrown::hash_table::Entry::Occupied(_) => unreachable!(),
                 hashbrown::hash_table::Entry::Vacant(entry) => {
                     entry.insert(idx);
@@ -180,98 +663,235 @@ impl AstIdMap {
             }
         }
         res.arena.shrink_to_fit();
-        res
+        return res;
+
+        fn parent_of(parent_idx: Option<ArenaId>, res: &AstIdMap) -> Option<&ErasedFileAstId> {
+            let mut parent = parent_idx.map(|parent_idx| &res.arena[parent_idx].1);
+            if parent.is_some_and(|parent| parent.kind() == ErasedFileAstIdKind::ExternBlock as u32)
+            {
+                // See the comment on `ErasedAssocItemFileAstId` for why is this.
+                // FIXME: Technically there could be an extern block inside another item, e.g.:
+                // ```
+                // fn foo() {
+                //     extern "C" {
+                //         fn bar();
+                //     }
+                // }
+                // ```
+                // Here we want to make `foo()` the parent of `bar()`, but we make it `None`.
+                // Shouldn't be a big deal though.
+                parent = None;
+            }
+            parent
+        }
     }
 
     /// The [`AstId`] of the root node
     pub fn root(&self) -> SyntaxNodePtr {
-        self.arena[Idx::from_raw(RawIdx::from_u32(0))]
+        self.arena[Idx::from_raw(RawIdx::from_u32(0))].0
     }
 
     pub fn ast_id<N: AstIdNode>(&self, item: &N) -> FileAstId<N> {
-        let raw = self.erased_ast_id(item.syntax());
-        FileAstId { raw, covariant: PhantomData }
+        self.ast_id_for_ptr(AstPtr::new(item))
+    }
+
+    /// Blocks may not be allocated (if they have no items), so they have a different API.
+    pub fn ast_id_for_block(&self, block: &ast::BlockExpr) -> Option<FileAstId<ast::BlockExpr>> {
+        self.ast_id_for_ptr_for_block(AstPtr::new(block))
     }
 
     pub fn ast_id_for_ptr<N: AstIdNode>(&self, ptr: AstPtr<N>) -> FileAstId<N> {
         let ptr = ptr.syntax_node_ptr();
-        let hash = hash_ptr(&ptr);
-        match self.map.find(hash, |&idx| self.arena[idx] == ptr) {
-            Some(&raw) => FileAstId {
-                raw: ErasedFileAstId(raw.into_raw().into_u32()),
-                covariant: PhantomData,
-            },
-            None => panic!(
-                "Can't find {:?} in AstIdMap:\n{:?}",
+        FileAstId { raw: self.erased_ast_id(ptr), _marker: PhantomData }
+    }
+
+    /// Blocks may not be allocated (if they have no items), so they have a different API.
+    pub fn ast_id_for_ptr_for_block(
+        &self,
+        ptr: AstPtr<ast::BlockExpr>,
+    ) -> Option<FileAstId<ast::BlockExpr>> {
+        let ptr = ptr.syntax_node_ptr();
+        self.try_erased_ast_id(ptr).map(|raw| FileAstId { raw, _marker: PhantomData })
+    }
+
+    fn erased_ast_id(&self, ptr: SyntaxNodePtr) -> ErasedFileAstId {
+        self.try_erased_ast_id(ptr).unwrap_or_else(|| {
+            panic!(
+                "Can't find SyntaxNodePtr {:?} in AstIdMap:\n{:?}",
                 ptr,
                 self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
-            ),
-        }
+            )
+        })
     }
 
-    pub fn get<N: AstIdNode>(&self, id: FileAstId<N>) -> AstPtr<N> {
-        AstPtr::try_from_raw(self.arena[Idx::from_raw(RawIdx::from_u32(id.raw.into_raw()))])
-            .unwrap()
+    fn try_erased_ast_id(&self, ptr: SyntaxNodePtr) -> Option<ErasedFileAstId> {
+        let hash = hash_ptr(&ptr);
+        let idx = *self.ptr_map.find(hash, |&idx| self.arena[idx].0 == ptr)?;
+        Some(self.arena[idx].1)
     }
 
-    pub fn get_erased(&self, id: ErasedFileAstId) -> SyntaxNodePtr {
-        self.arena[Idx::from_raw(RawIdx::from_u32(id.into_raw()))]
+    // Don't bound on `AstIdNode` here, because `BlockExpr`s are also valid here (`ast::BlockExpr`
+    // doesn't always have a matching `FileAstId`, but a `FileAstId<ast::BlockExpr>` always has
+    // a matching node).
+    pub fn get<N: AstNode>(&self, id: FileAstId<N>) -> AstPtr<N> {
+        let ptr = self.get_erased(id.raw);
+        AstPtr::try_from_raw(ptr)
+            .unwrap_or_else(|| panic!("AstIdMap node mismatch with node `{ptr:?}`"))
     }
 
-    fn erased_ast_id(&self, item: &SyntaxNode) -> ErasedFileAstId {
-        let ptr = SyntaxNodePtr::new(item);
-        let hash = hash_ptr(&ptr);
-        match self.map.find(hash, |&idx| self.arena[idx] == ptr) {
-            Some(&idx) => ErasedFileAstId(idx.into_raw().into_u32()),
+    pub fn get_erased(&self, id: ErasedFileAstId) -> SyntaxNodePtr {
+        let hash = hash_ast_id(&id);
+        match self.id_map.find(hash, |&idx| self.arena[idx].1 == id) {
+            Some(&idx) => self.arena[idx].0,
             None => panic!(
-                "Can't find {:?} in AstIdMap:\n{:?}\n source text: {}",
-                item,
+                "Can't find ast id {:?} in AstIdMap:\n{:?}",
+                id,
                 self.arena.iter().map(|(_id, i)| i).collect::<Vec<_>>(),
-                item
             ),
         }
     }
-
-    fn alloc(&mut self, item: &SyntaxNode) -> ErasedFileAstId {
-        ErasedFileAstId(self.arena.alloc(SyntaxNodePtr::new(item)).into_raw().into_u32())
-    }
 }
 
+#[inline]
 fn hash_ptr(ptr: &SyntaxNodePtr) -> u64 {
-    BuildHasherDefault::<FxHasher>::default().hash_one(ptr)
-}
-
-#[derive(Copy, Clone, PartialEq, Eq)]
-enum TreeOrder {
-    BreadthFirst,
-    DepthFirst,
-}
-
-/// Walks the subtree in bdfs order, calling `f` for each node. What is bdfs
-/// order? It is a mix of breadth-first and depth first orders. Nodes for which
-/// `f` returns [`TreeOrder::BreadthFirst`] are visited breadth-first, all the other nodes are explored
-/// [`TreeOrder::DepthFirst`].
-///
-/// In other words, the size of the bfs queue is bound by the number of "true"
-/// nodes.
-fn bdfs(node: &SyntaxNode, mut f: impl FnMut(SyntaxNode) -> TreeOrder) {
-    let mut curr_layer = vec![node.clone()];
-    let mut next_layer = vec![];
-    while !curr_layer.is_empty() {
-        curr_layer.drain(..).for_each(|node| {
-            let mut preorder = node.preorder();
-            while let Some(event) = preorder.next() {
-                match event {
-                    syntax::WalkEvent::Enter(node) => {
-                        if f(node.clone()) == TreeOrder::BreadthFirst {
-                            next_layer.extend(node.children());
-                            preorder.skip_subtree();
-                        }
-                    }
-                    syntax::WalkEvent::Leave(_) => {}
-                }
+    FxBuildHasher.hash_one(ptr)
+}
+
+#[inline]
+fn hash_ast_id(ptr: &ErasedFileAstId) -> u64 {
+    FxBuildHasher.hash_one(ptr)
+}
+
+#[cfg(test)]
+mod tests {
+    use syntax::{AstNode, Edition, SourceFile, SyntaxKind, SyntaxNodePtr, WalkEvent, ast};
+
+    use crate::AstIdMap;
+
+    #[test]
+    fn check_all_nodes() {
+        let syntax = SourceFile::parse(
+            r#"
+extern crate foo;
+fn foo() {
+    union U {}
+}
+struct S;
+macro_rules! m {}
+macro m2() {}
+trait Trait {}
+impl Trait for S {}
+impl S {}
+impl m!() {}
+impl m2!() for m!() {}
+type T = i32;
+enum E {
+    V1(),
+    V2 {},
+    V3,
+}
+struct S; // duplicate
+extern "C" {
+    static S: i32;
+}
+static mut S: i32 = 0;
+const FOO: i32 = 0;
+        "#,
+            Edition::CURRENT,
+        )
+        .syntax_node();
+        let ast_id_map = AstIdMap::from_source(&syntax);
+        for node in syntax.preorder() {
+            let WalkEvent::Enter(node) = node else { continue };
+            if !matches!(
+                node.kind(),
+                SyntaxKind::EXTERN_CRATE
+                    | SyntaxKind::FN
+                    | SyntaxKind::UNION
+                    | SyntaxKind::STRUCT
+                    | SyntaxKind::MACRO_RULES
+                    | SyntaxKind::MACRO_DEF
+                    | SyntaxKind::MACRO_CALL
+                    | SyntaxKind::TRAIT
+                    | SyntaxKind::IMPL
+                    | SyntaxKind::TYPE_ALIAS
+                    | SyntaxKind::ENUM
+                    | SyntaxKind::VARIANT
+                    | SyntaxKind::EXTERN_BLOCK
+                    | SyntaxKind::STATIC
+                    | SyntaxKind::CONST
+            ) {
+                continue;
             }
-        });
-        std::mem::swap(&mut curr_layer, &mut next_layer);
+            let ptr = SyntaxNodePtr::new(&node);
+            let ast_id = ast_id_map.erased_ast_id(ptr);
+            let turn_back = ast_id_map.get_erased(ast_id);
+            assert_eq!(ptr, turn_back);
+        }
+    }
+
+    #[test]
+    fn different_names_get_different_hashes() {
+        let syntax = SourceFile::parse(
+            r#"
+fn foo() {}
+fn bar() {}
+        "#,
+            Edition::CURRENT,
+        )
+        .syntax_node();
+        let ast_id_map = AstIdMap::from_source(&syntax);
+        let fns = syntax.descendants().filter_map(ast::Fn::cast).collect::<Vec<_>>();
+        let [foo_fn, bar_fn] = fns.as_slice() else {
+            panic!("not exactly 2 functions");
+        };
+        let foo_fn_id = ast_id_map.ast_id(foo_fn);
+        let bar_fn_id = ast_id_map.ast_id(bar_fn);
+        assert_ne!(foo_fn_id.raw.hash_value(), bar_fn_id.raw.hash_value(), "hashes are equal");
+    }
+
+    #[test]
+    fn different_parents_get_different_hashes() {
+        let syntax = SourceFile::parse(
+            r#"
+fn foo() {
+    m!();
+}
+fn bar() {
+    m!();
+}
+        "#,
+            Edition::CURRENT,
+        )
+        .syntax_node();
+        let ast_id_map = AstIdMap::from_source(&syntax);
+        let macro_calls = syntax.descendants().filter_map(ast::MacroCall::cast).collect::<Vec<_>>();
+        let [macro_call_foo, macro_call_bar] = macro_calls.as_slice() else {
+            panic!("not exactly 2 macro calls");
+        };
+        let macro_call_foo_id = ast_id_map.ast_id(macro_call_foo);
+        let macro_call_bar_id = ast_id_map.ast_id(macro_call_bar);
+        assert_ne!(
+            macro_call_foo_id.raw.hash_value(),
+            macro_call_bar_id.raw.hash_value(),
+            "hashes are equal"
+        );
+    }
+
+    #[test]
+    fn blocks_with_no_items_have_no_id() {
+        let syntax = SourceFile::parse(
+            r#"
+fn foo() {
+    let foo = 1;
+    bar(foo);
+}
+        "#,
+            Edition::CURRENT,
+        )
+        .syntax_node();
+        let ast_id_map = AstIdMap::from_source(&syntax);
+        let block = syntax.descendants().find_map(ast::BlockExpr::cast).expect("no block");
+        assert!(ast_id_map.ast_id_for_block(&block).is_none());
     }
 }
diff --git a/src/tools/rust-analyzer/crates/span/src/lib.rs b/src/tools/rust-analyzer/crates/span/src/lib.rs
index f81648ac42c..b81d08eed6d 100644
--- a/src/tools/rust-analyzer/crates/span/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/span/src/lib.rs
@@ -6,7 +6,10 @@ mod hygiene;
 mod map;
 
 pub use self::{
-    ast_id::{AstIdMap, AstIdNode, ErasedFileAstId, FileAstId},
+    ast_id::{
+        AstIdMap, AstIdNode, ErasedFileAstId, FIXUP_ERASED_FILE_AST_ID_MARKER, FileAstId,
+        ROOT_ERASED_FILE_AST_ID,
+    },
     hygiene::{SyntaxContext, Transparency},
     map::{RealSpanMap, SpanMap},
 };
@@ -15,19 +18,6 @@ pub use syntax::Edition;
 pub use text_size::{TextRange, TextSize};
 pub use vfs::FileId;
 
-// The first index is always the root node's AstId
-/// The root ast id always points to the encompassing file, using this in spans is discouraged as
-/// any range relative to it will be effectively absolute, ruining the entire point of anchored
-/// relative text ranges.
-pub const ROOT_ERASED_FILE_AST_ID: ErasedFileAstId = ErasedFileAstId::from_raw(0);
-
-/// FileId used as the span for syntax node fixups. Any Span containing this file id is to be
-/// considered fake.
-pub const FIXUP_ERASED_FILE_AST_ID_MARKER: ErasedFileAstId =
-    // we pick the second to last for this in case we ever consider making this a NonMaxU32, this
-    // is required to be stable for the proc-macro-server
-    ErasedFileAstId::from_raw(!0 - 1);
-
 pub type Span = SpanData<SyntaxContext>;
 
 impl Span {
@@ -60,7 +50,7 @@ impl<Ctx: fmt::Debug> fmt::Debug for SpanData<Ctx> {
         if f.alternate() {
             fmt::Debug::fmt(&self.anchor.file_id.file_id().index(), f)?;
             f.write_char(':')?;
-            fmt::Debug::fmt(&self.anchor.ast_id.into_raw(), f)?;
+            write!(f, "{:#?}", self.anchor.ast_id)?;
             f.write_char('@')?;
             fmt::Debug::fmt(&self.range, f)?;
             f.write_char('#')?;
@@ -85,7 +75,7 @@ impl fmt::Display for Span {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt::Debug::fmt(&self.anchor.file_id.file_id().index(), f)?;
         f.write_char(':')?;
-        fmt::Debug::fmt(&self.anchor.ast_id.into_raw(), f)?;
+        write!(f, "{:#?}", self.anchor.ast_id)?;
         f.write_char('@')?;
         fmt::Debug::fmt(&self.range, f)?;
         f.write_char('#')?;
@@ -101,7 +91,7 @@ pub struct SpanAnchor {
 
 impl fmt::Debug for SpanAnchor {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_tuple("SpanAnchor").field(&self.file_id).field(&self.ast_id.into_raw()).finish()
+        f.debug_tuple("SpanAnchor").field(&self.file_id).field(&self.ast_id).finish()
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/span/src/map.rs b/src/tools/rust-analyzer/crates/span/src/map.rs
index cc7a886643a..f58201793da 100644
--- a/src/tools/rust-analyzer/crates/span/src/map.rs
+++ b/src/tools/rust-analyzer/crates/span/src/map.rs
@@ -169,7 +169,7 @@ impl fmt::Display for RealSpanMap {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         writeln!(f, "RealSpanMap({:?}):", self.file_id)?;
         for span in self.pairs.iter() {
-            writeln!(f, "{}: {}", u32::from(span.0), span.1.into_raw())?;
+            writeln!(f, "{}: {:#?}", u32::from(span.0), span.1)?;
         }
         Ok(())
     }
diff --git a/src/tools/rust-analyzer/crates/stdx/Cargo.toml b/src/tools/rust-analyzer/crates/stdx/Cargo.toml
index b37aded6f68..a6d57816608 100644
--- a/src/tools/rust-analyzer/crates/stdx/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/stdx/Cargo.toml
@@ -12,7 +12,7 @@ rust-version.workspace = true
 [lib]
 
 [dependencies]
-backtrace = { version = "0.3.74", optional = true }
+backtrace = { version = "0.3.75", optional = true }
 jod-thread = "1.0.0"
 crossbeam-channel.workspace = true
 itertools.workspace = true
@@ -25,7 +25,7 @@ libc.workspace = true
 
 [target.'cfg(windows)'.dependencies]
 miow = "0.6.0"
-windows-sys = { version = "0.59", features = ["Win32_Foundation"] }
+windows-sys = { version = "0.60", features = ["Win32_Foundation"] }
 
 [features]
 # Uncomment to enable for the whole crate graph
diff --git a/src/tools/rust-analyzer/crates/syntax/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/Cargo.toml
index 4c7704803ef..9d3aaa8d4e3 100644
--- a/src/tools/rust-analyzer/crates/syntax/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/syntax/Cargo.toml
@@ -27,7 +27,7 @@ stdx.workspace = true
 [dev-dependencies]
 rayon.workspace = true
 expect-test = "1.5.1"
-rustc_apfloat = "0.2.2"
+rustc_apfloat = "0.2.3"
 
 test-utils.workspace = true
 
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
index dcf853427e5..f5530c5fffd 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs
@@ -30,6 +30,16 @@ impl ast::Name {
     pub fn text(&self) -> TokenText<'_> {
         text_of_first_token(self.syntax())
     }
+    pub fn text_non_mutable(&self) -> &str {
+        fn first_token(green_ref: &GreenNodeData) -> &GreenTokenData {
+            green_ref.children().next().and_then(NodeOrToken::into_token).unwrap()
+        }
+
+        match self.syntax().green() {
+            Cow::Borrowed(green_ref) => first_token(green_ref).text(),
+            Cow::Owned(_) => unreachable!(),
+        }
+    }
 }
 
 impl ast::NameRef {
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 8eb48f8d93e..8937e53175a 100644
--- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
@@ -1,5 +1,5 @@
 //! A set of high-level utility fixture methods to use in tests.
-use std::{mem, str::FromStr, sync};
+use std::{any::TypeId, mem, str::FromStr, sync};
 
 use base_db::{
     Crate, CrateDisplayName, CrateGraphBuilder, CrateName, CrateOrigin, CrateWorkspaceData,
@@ -677,6 +677,10 @@ impl ProcMacroExpander for IdentityProcMacroExpander {
     ) -> Result<TopSubtree, ProcMacroExpansionError> {
         Ok(subtree.clone())
     }
+
+    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
+        other.type_id() == TypeId::of::<Self>()
+    }
 }
 
 // Expands to a macro_rules! macro, for issue #18089.
@@ -708,6 +712,10 @@ impl ProcMacroExpander for Issue18089ProcMacroExpander {
             #subtree
         })
     }
+
+    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
+        other.type_id() == TypeId::of::<Self>()
+    }
 }
 
 // Pastes the attribute input as its output
@@ -728,6 +736,10 @@ impl ProcMacroExpander for AttributeInputReplaceProcMacroExpander {
             .cloned()
             .ok_or_else(|| ProcMacroExpansionError::Panic("Expected attribute input".into()))
     }
+
+    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
+        other.type_id() == TypeId::of::<Self>()
+    }
 }
 
 #[derive(Debug)]
@@ -759,6 +771,10 @@ impl ProcMacroExpander for Issue18840ProcMacroExpander {
         top_subtree_delimiter_mut.close = def_site;
         Ok(result)
     }
+
+    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
+        other.type_id() == TypeId::of::<Self>()
+    }
 }
 
 #[derive(Debug)]
@@ -790,6 +806,10 @@ impl ProcMacroExpander for MirrorProcMacroExpander {
         traverse(&mut builder, input.iter());
         Ok(builder.build())
     }
+
+    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
+        other.type_id() == TypeId::of::<Self>()
+    }
 }
 
 // Replaces every literal with an empty string literal and every identifier with its first letter,
@@ -830,6 +850,10 @@ impl ProcMacroExpander for ShortenProcMacroExpander {
             }
         }
     }
+
+    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
+        other.type_id() == TypeId::of::<Self>()
+    }
 }
 
 // Reads ident type within string quotes, for issue #17479.
@@ -855,6 +879,10 @@ impl ProcMacroExpander for Issue17479ProcMacroExpander {
             #symbol()
         })
     }
+
+    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
+        other.type_id() == TypeId::of::<Self>()
+    }
 }
 
 // Reads ident type within string quotes, for issue #17479.
@@ -906,6 +934,10 @@ impl ProcMacroExpander for Issue18898ProcMacroExpander {
             }
         })
     }
+
+    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
+        other.type_id() == TypeId::of::<Self>()
+    }
 }
 
 // Reads ident type within string quotes, for issue #17479.
@@ -933,6 +965,10 @@ impl ProcMacroExpander for DisallowCfgProcMacroExpander {
         }
         Ok(subtree.clone())
     }
+
+    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
+        other.type_id() == TypeId::of::<Self>()
+    }
 }
 
 // Generates a new type by adding a suffix to the original name
@@ -987,4 +1023,8 @@ impl ProcMacroExpander for GenerateSuffixedTypeProcMacroExpander {
 
         Ok(ret)
     }
+
+    fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
+        other.type_id() == TypeId::of::<Self>()
+    }
 }
diff --git a/src/tools/rust-analyzer/docs/book/README.md b/src/tools/rust-analyzer/docs/book/README.md
index 464ea02512f..0a3161f3af3 100644
--- a/src/tools/rust-analyzer/docs/book/README.md
+++ b/src/tools/rust-analyzer/docs/book/README.md
@@ -19,7 +19,7 @@ mdbook will rebuild the documentation as changes are made.
 
 ## Making updates
 
-While not required, installing the mdbook binary can be helfpul in order to see the changes.
+While not required, installing the mdbook binary can be helpful in order to see the changes.
 Start with the mdbook [User Guide](https://rust-lang.github.io/mdBook/guide/installation.html) to familiarize yourself with the tool.
 
 ## Generated documentation
diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
index 0e07dadfb7c..4eb9cfc4e5b 100644
--- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
+++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
@@ -1531,6 +1531,13 @@ buck2's `rust-project` will likely be useful:
 https://github.com/facebook/buck2/tree/main/integrations/rust-project.
 
 
+## rust-analyzer.workspace.symbol.search.excludeImports {#workspace.symbol.search.excludeImports}
+
+Default: `false`
+
+Exclude imports from symbol search.
+
+
 ## rust-analyzer.workspace.symbol.search.kind {#workspace.symbol.search.kind}
 
 Default: `"only_types"`
diff --git a/src/tools/rust-analyzer/docs/book/src/contributing/README.md b/src/tools/rust-analyzer/docs/book/src/contributing/README.md
index 05286b54292..beb94cdfc41 100644
--- a/src/tools/rust-analyzer/docs/book/src/contributing/README.md
+++ b/src/tools/rust-analyzer/docs/book/src/contributing/README.md
@@ -13,7 +13,7 @@ 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.
 
-We also publish rustdoc docs to pages: https://rust-lang.github.io/rust-analyzer/ide/.
+We also publish rustdoc docs to <https://rust-lang.github.io/rust-analyzer/ide/>.
 Note though, that the internal documentation is very incomplete.
 
 Various organizational and process issues are discussed in this document.
@@ -30,7 +30,7 @@ Discussion happens in this Zulip stream:
 
 # Issue Labels
 
-* [good-first-issue](https://github.com/rust-lang/rust-analyzer/labels/good%20first%20issue)
+* [good-first-issue](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aissue%20state%3Aopen%20label%3A%22good%20first%20issue%22)
   are good issues to get into the project.
 * [E-has-instructions](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-has-instructions)
   issues have links to the code in question and tests.
diff --git a/src/tools/rust-analyzer/docs/book/src/troubleshooting.md b/src/tools/rust-analyzer/docs/book/src/troubleshooting.md
index 4092b9de990..1b2841421a4 100644
--- a/src/tools/rust-analyzer/docs/book/src/troubleshooting.md
+++ b/src/tools/rust-analyzer/docs/book/src/troubleshooting.md
@@ -46,5 +46,4 @@ It is especially useful when the `repo` doesn’t use external crates or
 the standard library.
 
 If you want to go as far as to modify the source code to debug the
-problem, be sure to take a look at the [dev
-docs](https://github.com/rust-lang/rust-analyzer/tree/master/docs/dev)!
+problem, be sure to take a look at the [contribution guide](contributing/index.html)!
diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json
index ab431140c10..57d67a69b2e 100644
--- a/src/tools/rust-analyzer/editors/code/package-lock.json
+++ b/src/tools/rust-analyzer/editors/code/package-lock.json
@@ -695,9 +695,9 @@
             }
         },
         "node_modules/@eslint/config-array/node_modules/brace-expansion": {
-            "version": "1.1.11",
-            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
-            "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+            "version": "1.1.12",
+            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+            "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
@@ -756,9 +756,9 @@
             }
         },
         "node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
-            "version": "1.1.11",
-            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
-            "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+            "version": "1.1.12",
+            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+            "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
@@ -1407,9 +1407,9 @@
             ]
         },
         "node_modules/@vscode/vsce/node_modules/brace-expansion": {
-            "version": "1.1.11",
-            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
-            "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+            "version": "1.1.12",
+            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+            "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
@@ -1599,9 +1599,9 @@
             "license": "ISC"
         },
         "node_modules/brace-expansion": {
-            "version": "2.0.1",
-            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
-            "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+            "version": "2.0.2",
+            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+            "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
             "license": "MIT",
             "dependencies": {
                 "balanced-match": "^1.0.0"
@@ -2981,9 +2981,9 @@
             }
         },
         "node_modules/eslint/node_modules/brace-expansion": {
-            "version": "1.1.11",
-            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
-            "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+            "version": "1.1.12",
+            "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+            "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
             "dev": true,
             "license": "MIT",
             "dependencies": {
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index c8c36cd85c8..dcdb4fe30ee 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -2894,6 +2894,16 @@
             {
                 "title": "workspace",
                 "properties": {
+                    "rust-analyzer.workspace.symbol.search.excludeImports": {
+                        "markdownDescription": "Exclude imports from symbol search.",
+                        "default": false,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "workspace",
+                "properties": {
                     "rust-analyzer.workspace.symbol.search.kind": {
                         "markdownDescription": "Workspace symbol search kind.",
                         "default": "only_types",
diff --git a/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml b/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml
index 1dc6d3ce5db..35a5a4d82b2 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml
+++ b/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml
@@ -7,7 +7,7 @@ repository = "https://github.com/rust-lang/rust-analyzer/tree/master/lib/lsp-ser
 edition = "2024"
 
 [dependencies]
-log = "0.4.26"
+log = "0.4.27"
 serde_json = "1.0.140"
 serde = { version = "1.0.219" }
 serde_derive = { version = "1.0.219" }
@@ -15,7 +15,7 @@ crossbeam-channel.workspace = true
 
 [dev-dependencies]
 lsp-types = "=0.95"
-ctrlc = "3.4.5"
+ctrlc = "3.4.7"
 
 [lints]
 workspace = true
diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs b/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs
index 2749557b91a..399d674e41d 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs
+++ b/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs
@@ -283,12 +283,12 @@ fn read_msg_text(inp: &mut dyn BufRead) -> io::Result<Option<String>> {
     buf.resize(size, 0);
     inp.read_exact(&mut buf)?;
     let buf = String::from_utf8(buf).map_err(invalid_data)?;
-    log::debug!("< {}", buf);
+    log::debug!("< {buf}");
     Ok(Some(buf))
 }
 
 fn write_msg_text(out: &mut dyn Write, msg: &str) -> io::Result<()> {
-    log::debug!("> {}", msg);
+    log::debug!("> {msg}");
     write!(out, "Content-Length: {}\r\n\r\n", msg.len())?;
     out.write_all(msg.as_bytes())?;
     out.flush()?;
diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/stdio.rs b/src/tools/rust-analyzer/lib/lsp-server/src/stdio.rs
index c558b6c6e77..eccc89fd59c 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/src/stdio.rs
+++ b/src/tools/rust-analyzer/lib/lsp-server/src/stdio.rs
@@ -38,7 +38,7 @@ pub(crate) fn stdio_transport() -> (Sender<Message>, Receiver<Message>, IoThread
             while let Some(msg) = Message::read(&mut stdin)? {
                 let is_exit = matches!(&msg, Message::Notification(n) if n.is_exit());
 
-                debug!("sending message {:#?}", msg);
+                debug!("sending message {msg:#?}");
                 if let Err(e) = reader_sender.send(msg) {
                     return Err(io::Error::other(e));
                 }
diff --git a/src/tools/rust-analyzer/xtask/Cargo.toml b/src/tools/rust-analyzer/xtask/Cargo.toml
index bb7d83c4b7d..8cd5811c0a6 100644
--- a/src/tools/rust-analyzer/xtask/Cargo.toml
+++ b/src/tools/rust-analyzer/xtask/Cargo.toml
@@ -9,14 +9,14 @@ rust-version.workspace = true
 [dependencies]
 anyhow.workspace = true
 directories = "6.0"
-flate2 = "1.1.0"
+flate2 = "1.1.2"
 write-json = "0.1.4"
 xshell.workspace = true
 xflags = "0.3.2"
 time = { version = "0.3", default-features = false }
-zip = { version = "3.0", default-features = false, features = ["deflate-flate2", "time"] }
+zip = { version = "4.0", default-features = false, features = ["deflate-flate2", "time"] }
 stdx.workspace = true
-proc-macro2 = "1.0.94"
+proc-macro2 = "1.0.95"
 quote = "1.0.40"
 ungrammar = "1.16.1"
 either.workspace = true
diff --git a/tests/assembly/naked-functions/wasm32.rs b/tests/assembly/naked-functions/wasm32.rs
index 71e4d80764a..984152f2b45 100644
--- a/tests/assembly/naked-functions/wasm32.rs
+++ b/tests/assembly/naked-functions/wasm32.rs
@@ -1,10 +1,10 @@
-// FIXME: add wasm32-unknown when the wasm32-unknown-unknown ABI is fixed
-// see https://github.com/rust-lang/rust/issues/115666
-//@ revisions: wasm64-unknown wasm32-wasip1
+//@ revisions: wasm32-unknown wasm64-unknown wasm32-wasip1
 //@ add-core-stubs
 //@ assembly-output: emit-asm
+//@ [wasm32-unknown] compile-flags: --target wasm32-unknown-unknown
 //@ [wasm64-unknown] compile-flags: --target wasm64-unknown-unknown
 //@ [wasm32-wasip1] compile-flags: --target wasm32-wasip1
+//@ [wasm32-unknown] needs-llvm-components: webassembly
 //@ [wasm64-unknown] needs-llvm-components: webassembly
 //@ [wasm32-wasip1] needs-llvm-components: webassembly
 
@@ -97,6 +97,7 @@ extern "C" fn fn_i64_i64(num: i64) -> i64 {
 }
 
 // CHECK-LABEL: fn_i128_i128:
+// wasm32-unknown: .functype fn_i128_i128 (i32, i64, i64) -> ()
 // wasm32-wasip1: .functype fn_i128_i128 (i32, i64, i64) -> ()
 // wasm64-unknown: .functype fn_i128_i128 (i64, i64, i64) -> ()
 #[allow(improper_ctypes_definitions)]
@@ -114,6 +115,7 @@ extern "C" fn fn_i128_i128(num: i128) -> i128 {
 }
 
 // CHECK-LABEL: fn_f128_f128:
+// wasm32-unknown: .functype fn_f128_f128 (i32, i64, i64) -> ()
 // wasm32-wasip1: .functype fn_f128_f128 (i32, i64, i64) -> ()
 // wasm64-unknown: .functype fn_f128_f128 (i64, i64, i64) -> ()
 #[no_mangle]
@@ -136,6 +138,7 @@ struct Compound {
 }
 
 // CHECK-LABEL: fn_compound_compound:
+// wasm32-unknown: .functype fn_compound_compound (i32, i32) -> ()
 // wasm32-wasip1: .functype fn_compound_compound (i32, i32) -> ()
 // wasm64-unknown: .functype fn_compound_compound (i64, i64) -> ()
 #[no_mangle]
diff --git a/tests/assembly/nvptx-c-abi-arg-v7.rs b/tests/assembly/nvptx-c-abi-arg-v7.rs
index 27b64b58f04..be98b167470 100644
--- a/tests/assembly/nvptx-c-abi-arg-v7.rs
+++ b/tests/assembly/nvptx-c-abi-arg-v7.rs
@@ -10,8 +10,12 @@
 #![feature(abi_ptx, lang_items, no_core)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+trait PointeeSized {}
+#[lang = "meta_sized"]
+trait MetaSized: PointeeSized {}
 #[lang = "sized"]
-trait Sized {}
+trait Sized: MetaSized {}
 #[lang = "copy"]
 trait Copy {}
 
diff --git a/tests/assembly/nvptx-c-abi-ret-v7.rs b/tests/assembly/nvptx-c-abi-ret-v7.rs
index 56ab182fcce..c68c71c872c 100644
--- a/tests/assembly/nvptx-c-abi-ret-v7.rs
+++ b/tests/assembly/nvptx-c-abi-ret-v7.rs
@@ -10,8 +10,12 @@
 #![feature(abi_ptx, lang_items, no_core)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+trait PointeeSized {}
+#[lang = "meta_sized"]
+trait MetaSized: PointeeSized {}
 #[lang = "sized"]
-trait Sized {}
+trait Sized: MetaSized {}
 #[lang = "copy"]
 trait Copy {}
 
diff --git a/tests/assembly/nvptx-kernel-abi/nvptx-kernel-args-abi-v7.rs b/tests/assembly/nvptx-kernel-abi/nvptx-kernel-args-abi-v7.rs
index b3bfc66a5a5..f245b4460f2 100644
--- a/tests/assembly/nvptx-kernel-abi/nvptx-kernel-args-abi-v7.rs
+++ b/tests/assembly/nvptx-kernel-abi/nvptx-kernel-args-abi-v7.rs
@@ -20,8 +20,12 @@
 #![feature(abi_ptx, lang_items, no_core)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+trait PointeeSized {}
+#[lang = "meta_sized"]
+trait MetaSized: PointeeSized {}
 #[lang = "sized"]
-trait Sized {}
+trait Sized: MetaSized {}
 #[lang = "copy"]
 trait Copy {}
 
diff --git a/tests/assembly/riscv-float-struct-abi.rs b/tests/assembly/riscv-float-struct-abi.rs
new file mode 100644
index 00000000000..5d9ac9d70b8
--- /dev/null
+++ b/tests/assembly/riscv-float-struct-abi.rs
@@ -0,0 +1,177 @@
+//@ add-core-stubs
+//@ assembly-output: emit-asm
+//@ compile-flags: -Copt-level=3 --target riscv64gc-unknown-linux-gnu
+//@ needs-llvm-components: riscv
+
+#![feature(no_core, lang_items)]
+#![no_std]
+#![no_core]
+#![crate_type = "lib"]
+
+extern crate minicore;
+use minicore::*;
+
+#[repr(C, align(64))]
+struct Aligned(f64);
+
+#[repr(C)]
+struct Padded(u8, Aligned);
+
+#[repr(C, packed)]
+struct Packed(u8, f32);
+
+impl Copy for Aligned {}
+impl Copy for Padded {}
+impl Copy for Packed {}
+
+extern "C" {
+    fn take_padded(x: Padded);
+    fn get_padded() -> Padded;
+    fn take_packed(x: Packed);
+    fn get_packed() -> Packed;
+}
+
+// CHECK-LABEL: pass_padded
+#[unsafe(no_mangle)]
+extern "C" fn pass_padded(out: &mut Padded, x: Padded) {
+    // CHECK: sb a1, 0(a0)
+    // CHECK-NEXT: fsd fa0, 64(a0)
+    // CHECK-NEXT: ret
+    *out = x;
+}
+
+// CHECK-LABEL: ret_padded
+#[unsafe(no_mangle)]
+extern "C" fn ret_padded(x: &Padded) -> Padded {
+    // CHECK: fld fa0, 64(a0)
+    // CHECK-NEXT: lbu a0, 0(a0)
+    // CHECK-NEXT: ret
+    *x
+}
+
+#[unsafe(no_mangle)]
+extern "C" fn call_padded(x: &Padded) {
+    // CHECK: fld fa0, 64(a0)
+    // CHECK-NEXT: lbu a0, 0(a0)
+    // CHECK-NEXT: tail take_padded
+    unsafe {
+        take_padded(*x);
+    }
+}
+
+#[unsafe(no_mangle)]
+extern "C" fn receive_padded(out: &mut Padded) {
+    // CHECK: addi sp, sp, -16
+    // CHECK-NEXT: .cfi_def_cfa_offset 16
+    // CHECK-NEXT: sd ra, [[#%d,RA_SPILL:]](sp)
+    // CHECK-NEXT: sd [[TEMP:.*]], [[#%d,TEMP_SPILL:]](sp)
+    // CHECK-NEXT: .cfi_offset ra, [[#%d,RA_SPILL - 16]]
+    // CHECK-NEXT: .cfi_offset [[TEMP]], [[#%d,TEMP_SPILL - 16]]
+    // CHECK-NEXT: mv [[TEMP]], a0
+    // CHECK-NEXT: call get_padded
+    // CHECK-NEXT: sb a0, 0([[TEMP]])
+    // CHECK-NEXT: fsd fa0, 64([[TEMP]])
+    // CHECK-NEXT: ld ra, [[#%d,RA_SPILL]](sp)
+    // CHECK-NEXT: ld [[TEMP]], [[#%d,TEMP_SPILL]](sp)
+    // CHECK: addi sp, sp, 16
+    // CHECK: ret
+    unsafe {
+        *out = get_padded();
+    }
+}
+
+// CHECK-LABEL: pass_packed
+#[unsafe(no_mangle)]
+extern "C" fn pass_packed(out: &mut Packed, x: Packed) {
+    // CHECK: addi sp, sp, -16
+    // CHECK-NEXT: .cfi_def_cfa_offset 16
+    // CHECK-NEXT: sb a1, 0(a0)
+    // CHECK-NEXT: fsw fa0, 8(sp)
+    // CHECK-NEXT: lw [[VALUE:.*]], 8(sp)
+    // CHECK-DAG: srli [[BYTE4:.*]], [[VALUE]], 24
+    // CHECK-DAG: srli [[BYTE3:.*]], [[VALUE]], 16
+    // CHECK-DAG: srli [[BYTE2:.*]], [[VALUE]], 8
+    // CHECK-DAG: sb [[VALUE]], 1(a0)
+    // CHECK-DAG: sb [[BYTE2]], 2(a0)
+    // CHECK-DAG: sb [[BYTE3]], 3(a0)
+    // CHECK-DAG: sb [[BYTE4]], 4(a0)
+    // CHECK-NEXT: addi sp, sp, 16
+    // CHECK: ret
+    *out = x;
+}
+
+// CHECK-LABEL: ret_packed
+#[unsafe(no_mangle)]
+extern "C" fn ret_packed(x: &Packed) -> Packed {
+    // CHECK: addi sp, sp, -16
+    // CHECK-NEXT: .cfi_def_cfa_offset 16
+    // CHECK-NEXT: lbu [[BYTE2:.*]], 2(a0)
+    // CHECK-NEXT: lbu [[BYTE1:.*]], 1(a0)
+    // CHECK-NEXT: lbu [[BYTE3:.*]], 3(a0)
+    // CHECK-NEXT: lbu [[BYTE4:.*]], 4(a0)
+    // CHECK-NEXT: slli [[SHIFTED2:.*]], [[BYTE2]], 8
+    // CHECK-NEXT: or [[BYTE12:.*]], [[SHIFTED2]], [[BYTE1]]
+    // CHECK-NEXT: slli [[SHIFTED3:.*]], [[BYTE3]], 16
+    // CHECK-NEXT: slli [[SHIFTED4:.*]], [[BYTE4]], 24
+    // CHECK-NEXT: or [[BYTE34:.*]], [[SHIFTED3]], [[SHIFTED4]]
+    // CHECK-NEXT: or [[VALUE:.*]], [[BYTE12]], [[BYTE34]]
+    // CHECK-NEXT: sw [[VALUE]], 8(sp)
+    // CHECK-NEXT: flw fa0, 8(sp)
+    // CHECK-NEXT: lbu a0, 0(a0)
+    // CHECK-NEXT: addi sp, sp, 16
+    // CHECK: ret
+    *x
+}
+
+#[unsafe(no_mangle)]
+extern "C" fn call_packed(x: &Packed) {
+    // CHECK: addi sp, sp, -16
+    // CHECK-NEXT: .cfi_def_cfa_offset 16
+    // CHECK-NEXT: lbu [[BYTE2:.*]], 2(a0)
+    // CHECK-NEXT: lbu [[BYTE1:.*]], 1(a0)
+    // CHECK-NEXT: lbu [[BYTE3:.*]], 3(a0)
+    // CHECK-NEXT: lbu [[BYTE4:.*]], 4(a0)
+    // CHECK-NEXT: slli [[SHIFTED2:.*]], [[BYTE2]], 8
+    // CHECK-NEXT: or [[BYTE12:.*]], [[SHIFTED2]], [[BYTE1]]
+    // CHECK-NEXT: slli [[SHIFTED3:.*]], [[BYTE3]], 16
+    // CHECK-NEXT: slli [[SHIFTED4:.*]], [[BYTE4]], 24
+    // CHECK-NEXT: or [[BYTE34:.*]], [[SHIFTED3]], [[SHIFTED4]]
+    // CHECK-NEXT: or [[VALUE:.*]], [[BYTE12]], [[BYTE34]]
+    // CHECK-NEXT: sw [[VALUE]], 8(sp)
+    // CHECK-NEXT: flw fa0, 8(sp)
+    // CHECK-NEXT: lbu a0, 0(a0)
+    // CHECK-NEXT: addi sp, sp, 16
+    // CHECK: tail take_packed
+    unsafe {
+        take_packed(*x);
+    }
+}
+
+#[unsafe(no_mangle)]
+extern "C" fn receive_packed(out: &mut Packed) {
+    // CHECK: addi sp, sp, -32
+    // CHECK-NEXT: .cfi_def_cfa_offset 32
+    // CHECK-NEXT: sd ra, [[#%d,RA_SPILL:]](sp)
+    // CHECK-NEXT: sd [[TEMP:.*]], [[#%d,TEMP_SPILL:]](sp)
+    // CHECK-NEXT: .cfi_offset ra, [[#%d,RA_SPILL - 32]]
+    // CHECK-NEXT: .cfi_offset [[TEMP]], [[#%d,TEMP_SPILL - 32]]
+    // CHECK-NEXT: mv [[TEMP]], a0
+    // CHECK-NEXT: call get_packed
+    // CHECK-NEXT: sb a0, 0([[TEMP]])
+    // CHECK-NEXT: fsw fa0, [[FLOAT_SPILL:.*]](sp)
+    // CHECK-NEXT: lw [[VALUE:.*]], [[FLOAT_SPILL]](sp)
+    // CHECK-DAG: srli [[BYTE4:.*]], [[VALUE]], 24
+    // CHECK-DAG: srli [[BYTE3:.*]], [[VALUE]], 16
+    // CHECK-DAG: srli [[BYTE2:.*]], [[VALUE]], 8
+    // CHECK-DAG: sb [[VALUE]], 1([[TEMP]])
+    // CHECK-DAG: sb [[BYTE2]], 2([[TEMP]])
+    // CHECK-DAG: sb [[BYTE3]], 3([[TEMP]])
+    // CHECK-DAG: sb [[BYTE4]], 4([[TEMP]])
+    // CHECK-NEXT: ld ra, [[#%d,RA_SPILL]](sp)
+    // CHECK-NEXT: ld [[TEMP]], [[#%d,TEMP_SPILL]](sp)
+    // CHECK: addi sp, sp, 32
+    // CHECK: ret
+    unsafe {
+        *out = get_packed();
+    }
+}
diff --git a/tests/assembly/rust-abi-arg-attr.rs b/tests/assembly/rust-abi-arg-attr.rs
index 5b5eeb29f0f..4f3673ccfc3 100644
--- a/tests/assembly/rust-abi-arg-attr.rs
+++ b/tests/assembly/rust-abi-arg-attr.rs
@@ -13,12 +13,16 @@
 #![crate_type = "lib"]
 #![no_std]
 #![no_core]
-
 // FIXME: Migrate these code after PR #130693 is landed.
-// vvvvv core
+
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
 
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 
 #[lang = "copy"]
 trait Copy {}
diff --git a/tests/assembly/s390x-vector-abi.rs b/tests/assembly/s390x-vector-abi.rs
index e159a357685..fcf42664034 100644
--- a/tests/assembly/s390x-vector-abi.rs
+++ b/tests/assembly/s390x-vector-abi.rs
@@ -15,12 +15,17 @@
 #![no_core]
 #![crate_type = "lib"]
 #![allow(non_camel_case_types)]
-
 // Cases where vector feature is disabled are rejected.
 // See tests/ui/simd-abi-checks-s390x.rs for test for them.
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-pub trait Sized {}
+pub trait Sized: MetaSized {}
 #[lang = "copy"]
 pub trait Copy {}
 #[lang = "freeze"]
diff --git a/tests/assembly/small_data_threshold.rs b/tests/assembly/small_data_threshold.rs
index bed515915b8..2abe8687d8b 100644
--- a/tests/assembly/small_data_threshold.rs
+++ b/tests/assembly/small_data_threshold.rs
@@ -19,8 +19,14 @@
 #![no_core]
 #![crate_type = "lib"]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 
 #[lang = "drop_in_place"]
 fn drop_in_place<T>(_: *mut T) {}
diff --git a/tests/auxiliary/minicore.rs b/tests/auxiliary/minicore.rs
index 941c4abed46..db11549382f 100644
--- a/tests/auxiliary/minicore.rs
+++ b/tests/auxiliary/minicore.rs
@@ -39,13 +39,19 @@ macro_rules! impl_marker_trait {
     }
 }
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-pub trait Sized {}
+pub trait Sized: MetaSized {}
 
 #[lang = "legacy_receiver"]
 pub trait LegacyReceiver {}
-impl<T: ?Sized> LegacyReceiver for &T {}
-impl<T: ?Sized> LegacyReceiver for &mut T {}
+impl<T: PointeeSized> LegacyReceiver for &T {}
+impl<T: PointeeSized> LegacyReceiver for &mut T {}
 
 #[lang = "copy"]
 pub trait Copy: Sized {}
@@ -67,14 +73,14 @@ impl_marker_trait!(
         f16, f32, f64, f128,
     ]
 );
-impl<'a, T: ?Sized> Copy for &'a T {}
-impl<T: ?Sized> Copy for *const T {}
-impl<T: ?Sized> Copy for *mut T {}
+impl<'a, T: PointeeSized> Copy for &'a T {}
+impl<T: PointeeSized> Copy for *const T {}
+impl<T: PointeeSized> Copy for *mut T {}
 impl<T: Copy, const N: usize> Copy for [T; N] {}
 
 #[lang = "phantom_data"]
-pub struct PhantomData<T: ?Sized>;
-impl<T: ?Sized> Copy for PhantomData<T> {}
+pub struct PhantomData<T: PointeeSized>;
+impl<T: PointeeSized> Copy for PhantomData<T> {}
 
 pub enum Option<T> {
     None,
@@ -90,17 +96,17 @@ impl<T: Copy, E: Copy> Copy for Result<T, E> {}
 
 #[lang = "manually_drop"]
 #[repr(transparent)]
-pub struct ManuallyDrop<T: ?Sized> {
+pub struct ManuallyDrop<T: PointeeSized> {
     value: T,
 }
-impl<T: Copy + ?Sized> Copy for ManuallyDrop<T> {}
+impl<T: Copy + PointeeSized> Copy for ManuallyDrop<T> {}
 
 #[lang = "unsafe_cell"]
 #[repr(transparent)]
-pub struct UnsafeCell<T: ?Sized> {
+pub struct UnsafeCell<T: PointeeSized> {
     value: T,
 }
-impl<T: ?Sized> !Freeze for UnsafeCell<T> {}
+impl<T: PointeeSized> !Freeze for UnsafeCell<T> {}
 
 #[lang = "tuple_trait"]
 pub trait Tuple {}
@@ -176,15 +182,15 @@ pub trait Fn<Args: Tuple>: FnMut<Args> {
 #[lang = "dispatch_from_dyn"]
 trait DispatchFromDyn<T> {}
 
-impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
+impl<'a, T: PointeeSized + Unsize<U>, U: PointeeSized> DispatchFromDyn<&'a U> for &'a T {}
 
 #[lang = "unsize"]
-trait Unsize<T: ?Sized> {}
+trait Unsize<T: PointeeSized>: PointeeSized {}
 
 #[lang = "coerce_unsized"]
-pub trait CoerceUnsized<T: ?Sized> {}
+pub trait CoerceUnsized<T: PointeeSized> {}
 
-impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
+impl<'a, 'b: 'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a U> for &'b T {}
 
 #[lang = "drop"]
 trait Drop {
diff --git a/tests/codegen-units/item-collection/implicit-panic-call.rs b/tests/codegen-units/item-collection/implicit-panic-call.rs
index 6d3a17d8d4a..612132f056b 100644
--- a/tests/codegen-units/item-collection/implicit-panic-call.rs
+++ b/tests/codegen-units/item-collection/implicit-panic-call.rs
@@ -28,8 +28,14 @@ fn panic_div_overflow() -> ! {
     loop {}
 }
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 
 #[lang = "copy"]
 trait Copy {}
diff --git a/tests/codegen/abi-x86-sse.rs b/tests/codegen/abi-x86-sse.rs
index 90757e601af..68d2acfb527 100644
--- a/tests/codegen/abi-x86-sse.rs
+++ b/tests/codegen/abi-x86-sse.rs
@@ -17,7 +17,13 @@
 #![crate_type = "lib"]
 
 #[lang = "sized"]
-trait Sized {}
+trait Sized: MetaSized {}
+
+#[lang = "meta_sized"]
+trait MetaSized: PointeeSized {}
+
+#[lang = "pointee_sized"]
+trait PointeeSized {}
 
 #[lang = "copy"]
 trait Copy {}
diff --git a/tests/codegen/dst-offset.rs b/tests/codegen/dst-offset.rs
index 7177a960432..2cf5fa9fac6 100644
--- a/tests/codegen/dst-offset.rs
+++ b/tests/codegen/dst-offset.rs
@@ -3,8 +3,9 @@
 //@ compile-flags: -C no-prepopulate-passes -Copt-level=0
 
 #![crate_type = "lib"]
-#![feature(extern_types)]
+#![feature(extern_types, sized_hierarchy)]
 
+use std::marker::PointeeSized;
 use std::ptr::addr_of;
 
 // Hack to get the correct type for usize
@@ -12,7 +13,7 @@ use std::ptr::addr_of;
 #[no_mangle]
 pub fn helper(_: usize) {}
 
-struct Dst<T: ?Sized> {
+struct Dst<T: PointeeSized> {
     x: u32,
     y: u8,
     z: T,
diff --git a/tests/codegen/emscripten-catch-unwind-js-eh.rs b/tests/codegen/emscripten-catch-unwind-js-eh.rs
index 3ab4b5c9c63..f43869cf218 100644
--- a/tests/codegen/emscripten-catch-unwind-js-eh.rs
+++ b/tests/codegen/emscripten-catch-unwind-js-eh.rs
@@ -9,8 +9,14 @@
 #![no_std]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 #[lang = "freeze"]
 trait Freeze {}
 #[lang = "copy"]
diff --git a/tests/codegen/emscripten-catch-unwind-wasm-eh.rs b/tests/codegen/emscripten-catch-unwind-wasm-eh.rs
index d0571e4df08..b0750d52268 100644
--- a/tests/codegen/emscripten-catch-unwind-wasm-eh.rs
+++ b/tests/codegen/emscripten-catch-unwind-wasm-eh.rs
@@ -8,8 +8,14 @@
 #![no_std]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 #[lang = "freeze"]
 trait Freeze {}
 #[lang = "copy"]
diff --git a/tests/codegen/iter-repeat-n-trivial-drop.rs b/tests/codegen/iter-repeat-n-trivial-drop.rs
index 3bb942d11d5..28173530324 100644
--- a/tests/codegen/iter-repeat-n-trivial-drop.rs
+++ b/tests/codegen/iter-repeat-n-trivial-drop.rs
@@ -1,5 +1,6 @@
 //@ compile-flags: -C opt-level=3
 //@ only-x86_64
+//@ needs-deterministic-layouts
 
 #![crate_type = "lib"]
 #![feature(iter_repeat_n)]
@@ -25,10 +26,10 @@ pub fn iter_repeat_n_next(it: &mut std::iter::RepeatN<NotCopy>) -> Option<NotCop
     // CHECK-NEXT: br i1 %[[COUNT_ZERO]], label %[[EMPTY:.+]], label %[[NOT_EMPTY:.+]]
 
     // CHECK: [[NOT_EMPTY]]:
-    // CHECK-NEXT: %[[DEC:.+]] = add i64 %[[COUNT]], -1
-    // CHECK-NEXT: store i64 %[[DEC]]
     // CHECK-NOT: br
-    // CHECK: %[[VAL:.+]] = load i16
+    // CHECK: %[[DEC:.+]] = add i64 %[[COUNT]], -1
+    // CHECK-NEXT: %[[VAL:.+]] = load i16
+    // CHECK-NEXT: store i64 %[[DEC]]
     // CHECK-NEXT: br label %[[EMPTY]]
 
     // CHECK: [[EMPTY]]:
diff --git a/tests/codegen/riscv-abi/cast-local-large-enough.rs b/tests/codegen/riscv-abi/cast-local-large-enough.rs
new file mode 100644
index 00000000000..9d21d73b459
--- /dev/null
+++ b/tests/codegen/riscv-abi/cast-local-large-enough.rs
@@ -0,0 +1,44 @@
+//@ add-core-stubs
+//@ compile-flags: -Copt-level=0 -Cdebuginfo=0 --target riscv64gc-unknown-linux-gnu
+//@ needs-llvm-components: riscv
+
+#![feature(no_core, lang_items)]
+#![no_std]
+#![no_core]
+#![crate_type = "lib"]
+
+extern crate minicore;
+use minicore::*;
+
+#[repr(C, align(64))]
+struct Aligned(f64);
+
+#[repr(C, align(64))]
+struct AlignedPair(f32, f64);
+
+impl Copy for Aligned {}
+impl Copy for AlignedPair {}
+
+// CHECK-LABEL: define double @read_aligned
+#[unsafe(no_mangle)]
+pub extern "C" fn read_aligned(x: &Aligned) -> Aligned {
+    // CHECK: %[[TEMP:.*]] = alloca [64 x i8], align 64
+    // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 64 %[[TEMP]], ptr align 64 %[[PTR:.*]], i64 64, i1 false)
+    // CHECK-NEXT: %[[RES:.*]] = load double, ptr %[[TEMP]], align 64
+    // CHECK-NEXT: ret double %[[RES]]
+    *x
+}
+
+// CHECK-LABEL: define { float, double } @read_aligned_pair
+#[unsafe(no_mangle)]
+pub extern "C" fn read_aligned_pair(x: &AlignedPair) -> AlignedPair {
+    // CHECK: %[[TEMP:.*]] = alloca [64 x i8], align 64
+    // CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 64 %[[TEMP]], ptr align 64 %[[PTR:.*]], i64 64, i1 false)
+    // CHECK-NEXT: %[[FIRST:.*]] = load float, ptr %[[TEMP]], align 64
+    // CHECK-NEXT: %[[SECOND_PTR:.*]] = getelementptr inbounds i8, ptr %[[TEMP]], i64 8
+    // CHECK-NEXT: %[[SECOND:.*]] = load double, ptr %[[SECOND_PTR]], align 8
+    // CHECK-NEXT: %[[RES1:.*]] = insertvalue { float, double } poison, float %[[FIRST]], 0
+    // CHECK-NEXT: %[[RES2:.*]] = insertvalue { float, double } %[[RES1]], double %[[SECOND]], 1
+    // CHECK-NEXT: ret { float, double } %[[RES2]]
+    *x
+}
diff --git a/tests/codegen/terminating-catchpad.rs b/tests/codegen/terminating-catchpad.rs
index 17d88796300..a2ec19871d1 100644
--- a/tests/codegen/terminating-catchpad.rs
+++ b/tests/codegen/terminating-catchpad.rs
@@ -15,8 +15,14 @@
 #![no_std]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 
 unsafe extern "C-unwind" {
     safe fn unwinds();
diff --git a/tests/codegen/unwind-abis/aapcs-unwind-abi.rs b/tests/codegen/unwind-abis/aapcs-unwind-abi.rs
index 0d9c7757883..ecace722e0d 100644
--- a/tests/codegen/unwind-abis/aapcs-unwind-abi.rs
+++ b/tests/codegen/unwind-abis/aapcs-unwind-abi.rs
@@ -2,8 +2,15 @@
 //@ compile-flags: --target=armv7-unknown-linux-gnueabihf --crate-type=rlib -Cno-prepopulate-passes
 #![no_core]
 #![feature(no_core, lang_items)]
+
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 
 // Test that `nounwind` attributes are correctly applied to exported `aapcs` and
 // `aapcs-unwind` extern functions. `aapcs-unwind` functions MUST NOT have this attribute. We
diff --git a/tests/codegen/unwind-abis/fastcall-unwind-abi.rs b/tests/codegen/unwind-abis/fastcall-unwind-abi.rs
index 4c7b2856e2e..7df46813ed1 100644
--- a/tests/codegen/unwind-abis/fastcall-unwind-abi.rs
+++ b/tests/codegen/unwind-abis/fastcall-unwind-abi.rs
@@ -2,8 +2,15 @@
 //@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes
 #![no_core]
 #![feature(no_core, lang_items)]
+
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 
 // Test that `nounwind` attributes are correctly applied to exported `fastcall` and
 // `fastcall-unwind` extern functions. `fastcall-unwind` functions MUST NOT have this attribute. We
diff --git a/tests/codegen/unwind-abis/stdcall-unwind-abi.rs b/tests/codegen/unwind-abis/stdcall-unwind-abi.rs
index ffc11d1faef..cc06ee12549 100644
--- a/tests/codegen/unwind-abis/stdcall-unwind-abi.rs
+++ b/tests/codegen/unwind-abis/stdcall-unwind-abi.rs
@@ -2,8 +2,15 @@
 //@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes
 #![no_core]
 #![feature(no_core, lang_items)]
+
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 
 // Test that `nounwind` attributes are correctly applied to exported `stdcall` and `stdcall-unwind`
 // extern functions. `stdcall-unwind` functions MUST NOT have this attribute. We disable
diff --git a/tests/codegen/unwind-abis/sysv64-unwind-abi.rs b/tests/codegen/unwind-abis/sysv64-unwind-abi.rs
index c869ca7e2b8..69bfaf80b4b 100644
--- a/tests/codegen/unwind-abis/sysv64-unwind-abi.rs
+++ b/tests/codegen/unwind-abis/sysv64-unwind-abi.rs
@@ -2,8 +2,15 @@
 //@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib -Cno-prepopulate-passes
 #![no_core]
 #![feature(no_core, lang_items)]
+
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 
 // Test that `nounwind` attributes are correctly applied to exported `sysv64` and
 // `sysv64-unwind` extern functions. `sysv64-unwind` functions MUST NOT have this attribute. We
diff --git a/tests/codegen/unwind-abis/thiscall-unwind-abi.rs b/tests/codegen/unwind-abis/thiscall-unwind-abi.rs
index 19b23ee47ba..05f6b8b70e1 100644
--- a/tests/codegen/unwind-abis/thiscall-unwind-abi.rs
+++ b/tests/codegen/unwind-abis/thiscall-unwind-abi.rs
@@ -2,8 +2,15 @@
 //@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes
 #![no_core]
 #![feature(no_core, lang_items)]
+
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 
 // Test that `nounwind` attributes are correctly applied to exported `thiscall` and
 // `thiscall-unwind` extern functions. `thiscall-unwind` functions MUST NOT have this attribute. We
diff --git a/tests/codegen/unwind-abis/vectorcall-unwind-abi.rs b/tests/codegen/unwind-abis/vectorcall-unwind-abi.rs
index b420f67ca9b..d001a16b32a 100644
--- a/tests/codegen/unwind-abis/vectorcall-unwind-abi.rs
+++ b/tests/codegen/unwind-abis/vectorcall-unwind-abi.rs
@@ -2,8 +2,15 @@
 //@ compile-flags: --target=i686-pc-windows-msvc --crate-type=rlib -Cno-prepopulate-passes
 #![no_core]
 #![feature(no_core, lang_items, abi_vectorcall)]
+
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 
 // Test that `nounwind` attributes are correctly applied to exported `vectorcall` and
 // `vectorcall-unwind` extern functions. `vectorcall-unwind` functions MUST NOT have this attribute.
diff --git a/tests/codegen/unwind-abis/win64-unwind-abi.rs b/tests/codegen/unwind-abis/win64-unwind-abi.rs
index 2697d3cbcd6..257f00b54e4 100644
--- a/tests/codegen/unwind-abis/win64-unwind-abi.rs
+++ b/tests/codegen/unwind-abis/win64-unwind-abi.rs
@@ -2,8 +2,15 @@
 //@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib -Cno-prepopulate-passes
 #![no_core]
 #![feature(no_core, lang_items)]
+
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 
 // Test that `nounwind` attributes are correctly applied to exported `win64` and
 // `win64-unwind` extern functions. `win64-unwind` functions MUST NOT have this attribute. We
diff --git a/tests/crashes/120033.rs b/tests/crashes/120033.rs
index f1502978dc5..7584f98ec90 100644
--- a/tests/crashes/120033.rs
+++ b/tests/crashes/120033.rs
@@ -1,8 +1,10 @@
 //@ known-bug: #120033
 #![feature(non_lifetime_binders)]
+#![allow(sized_hierarchy_migration)]
+#![feature(sized_hierarchy)] // added to keep parameters unconstrained
 
-pub trait Foo<T: ?Sized> {
-    type Bar<K: ?Sized>;
+pub trait Foo<T: std::marker::PointeeSized> {
+    type Bar<K: std::marker::PointeeSized>;
 }
 
 pub struct Bar<T: ?AutoTrait> {}
diff --git a/tests/debuginfo/recursive-type-with-gat.rs b/tests/debuginfo/recursive-type-with-gat.rs
index b8a67d8d24b..a4a1736ef5f 100644
--- a/tests/debuginfo/recursive-type-with-gat.rs
+++ b/tests/debuginfo/recursive-type-with-gat.rs
@@ -1,6 +1,8 @@
 //@ compile-flags: -Cdebuginfo=2
+#![allow(sized_hierarchy_migration)]
+#![feature(sized_hierarchy)] // added to keep parameters unconstrained
 
-pub trait Functor
+pub trait Functor: std::marker::PointeeSized
 {
     type With<T>: Functor;
 }
@@ -17,20 +19,20 @@ impl<T> Functor for Vec<T> {
 
 pub struct Compose<F1, F2, T>(F1::With<F2::With<T>>)
 where
-    F1: Functor + ?Sized,
-    F2: Functor + ?Sized;
+    F1: Functor + std::marker::PointeeSized,
+    F2: Functor + std::marker::PointeeSized;
 
 impl<F1, F2, T> Functor for Compose<F1, F2, T>
 where
-    F1: Functor + ?Sized,
-    F2: Functor + ?Sized
+    F1: Functor + std::marker::PointeeSized,
+    F2: Functor + std::marker::PointeeSized,
 {
     type With<T2> = F1::With<F2::With<T2>> ;
 }
 
 pub enum Value<F>
 where
-    F: Functor + ?Sized,
+    F: Functor + std::marker::PointeeSized,
 {
     SignedInt(*mut F::With<i64>),
     Array(*mut Value<Compose<F, Vec<()>, ()>>),
diff --git a/tests/incremental/hashes/trait_defs.rs b/tests/incremental/hashes/trait_defs.rs
index 7141ddb0d7e..50b56441cca 100644
--- a/tests/incremental/hashes/trait_defs.rs
+++ b/tests/incremental/hashes/trait_defs.rs
@@ -30,7 +30,7 @@ trait TraitVisibility { }
 #[cfg(not(any(cfail1,cfail4)))]
 #[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes")]
+#[rustc_clean(cfg="cfail5", except="opt_hir_owner_nodes,predicates_of")]
 #[rustc_clean(cfg="cfail6")]
 pub trait TraitVisibility { }
 
@@ -43,7 +43,7 @@ trait TraitUnsafety { }
 #[cfg(not(any(cfail1,cfail4)))]
 #[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")]
+#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 unsafe trait TraitUnsafety { }
 
@@ -57,7 +57,7 @@ trait TraitAddMethod {
 #[cfg(not(any(cfail1,cfail4)))]
 #[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail5")]
+#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 pub trait TraitAddMethod {
     fn method();
@@ -74,7 +74,7 @@ trait TraitChangeMethodName {
 #[cfg(not(any(cfail1,cfail4)))]
 #[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail5")]
+#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitChangeMethodName {
     fn methodChanged();
@@ -559,7 +559,7 @@ trait TraitAddBuiltinBoundToMethodTypeParameter {
 #[cfg(not(any(cfail1,cfail4)))]
 #[rustc_clean(cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail5")]
+#[rustc_clean(except="opt_hir_owner_nodes,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddBuiltinBoundToMethodTypeParameter {
     #[rustc_clean(except="opt_hir_owner_nodes", cfg="cfail2")]
@@ -827,7 +827,7 @@ trait TraitAddAssociatedConstant {
 #[cfg(not(any(cfail1,cfail4)))]
 #[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail5")]
+#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 trait TraitAddAssociatedConstant {
     const Value: u32;
diff --git a/tests/incremental/hashes/trait_impls.rs b/tests/incremental/hashes/trait_impls.rs
index a5003a8d432..8faf6806b90 100644
--- a/tests/incremental/hashes/trait_impls.rs
+++ b/tests/incremental/hashes/trait_impls.rs
@@ -34,7 +34,7 @@ impl ChangeMethodNameTrait for Foo {
 #[cfg(not(any(cfail1,cfail4)))]
 #[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail2")]
 #[rustc_clean(cfg="cfail3")]
-#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids", cfg="cfail5")]
+#[rustc_clean(except="opt_hir_owner_nodes,associated_item_def_ids,predicates_of", cfg="cfail5")]
 #[rustc_clean(cfg="cfail6")]
 pub trait ChangeMethodNameTrait {
     #[rustc_clean(cfg="cfail3")]
diff --git a/tests/mir-opt/inline/inline_instruction_set.rs b/tests/mir-opt/inline/inline_instruction_set.rs
index 44faf3a4ed9..fe2aaffa2a0 100644
--- a/tests/mir-opt/inline/inline_instruction_set.rs
+++ b/tests/mir-opt/inline/inline_instruction_set.rs
@@ -22,8 +22,14 @@ macro_rules! asm {
     };
 }
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 #[lang = "copy"]
 trait Copy {}
 
diff --git a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs
index ba887b3d791..8824a498306 100644
--- a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs
+++ b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 // ignore-tidy-linelength
 
 // Check that the `CURRENT_RUSTC_VERSION` placeholder is correctly replaced by the current
diff --git a/tests/run-make/allow-warnings-cmdline-stability/rmake.rs b/tests/run-make/allow-warnings-cmdline-stability/rmake.rs
index 22a31266176..66ca3eb3383 100644
--- a/tests/run-make/allow-warnings-cmdline-stability/rmake.rs
+++ b/tests/run-make/allow-warnings-cmdline-stability/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 // Test that `-Awarnings` suppresses warnings for unstable APIs.
 
 use run_make_support::rustc;
diff --git a/tests/run-make/amdgpu-kd/foo.rs b/tests/run-make/amdgpu-kd/foo.rs
index a0d803ab813..a097e9211a7 100644
--- a/tests/run-make/amdgpu-kd/foo.rs
+++ b/tests/run-make/amdgpu-kd/foo.rs
@@ -4,8 +4,14 @@
 #![no_std]
 
 // This is needed because of #![no_core]:
+#[lang = "pointee_sized"]
+trait PointeeSized {}
+
+#[lang = "meta_sized"]
+trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+trait Sized: MetaSized {}
 
 #[no_mangle]
 extern "gpu-kernel" fn kernel() {}
diff --git a/tests/run-make/artifact-incr-cache-no-obj/rmake.rs b/tests/run-make/artifact-incr-cache-no-obj/rmake.rs
index d5bc46dff47..8395b38f612 100644
--- a/tests/run-make/artifact-incr-cache-no-obj/rmake.rs
+++ b/tests/run-make/artifact-incr-cache-no-obj/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // emitting an object file is not necessary if user didn't ask for one
 //
 // This test is similar to run-make/artifact-incr-cache but it doesn't
diff --git a/tests/run-make/artifact-incr-cache/rmake.rs b/tests/run-make/artifact-incr-cache/rmake.rs
index b4b63313cfc..670c851e1e0 100644
--- a/tests/run-make/artifact-incr-cache/rmake.rs
+++ b/tests/run-make/artifact-incr-cache/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // rustc should be able to emit required files (asm, llvm-*, etc) during incremental
 // compilation on the first pass by running the code gen as well as on subsequent runs -
 // extracting them from the cache
diff --git a/tests/run-make/atomic-lock-free/atomic_lock_free.rs b/tests/run-make/atomic-lock-free/atomic_lock_free.rs
index e8bbd420cc4..f5c3b360ee8 100644
--- a/tests/run-make/atomic-lock-free/atomic_lock_free.rs
+++ b/tests/run-make/atomic-lock-free/atomic_lock_free.rs
@@ -16,8 +16,14 @@ pub enum AtomicOrdering {
 #[rustc_intrinsic]
 unsafe fn atomic_xadd<T, const ORD: AtomicOrdering>(dst: *mut T, src: T) -> T;
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 #[lang = "copy"]
 trait Copy {}
 #[lang = "freeze"]
diff --git a/tests/run-make/avr-rjmp-offset/avr-rjmp-offsets.rs b/tests/run-make/avr-rjmp-offset/avr-rjmp-offsets.rs
index c91cd695cee..07fda1f3f4a 100644
--- a/tests/run-make/avr-rjmp-offset/avr-rjmp-offsets.rs
+++ b/tests/run-make/avr-rjmp-offset/avr-rjmp-offsets.rs
@@ -24,14 +24,20 @@ pub fn main() -> ! {
 
 // FIXME: replace with proper minicore once available (#130693)
 mod minicore {
+    #[lang = "pointee_sized"]
+    pub trait PointeeSized {}
+
+    #[lang = "meta_sized"]
+    pub trait MetaSized: PointeeSized {}
+
     #[lang = "sized"]
-    pub trait Sized {}
+    pub trait Sized: MetaSized {}
 
     #[lang = "copy"]
     pub trait Copy {}
     impl Copy for u32 {}
     impl Copy for &u32 {}
-    impl<T: ?Sized> Copy for *mut T {}
+    impl<T: PointeeSized> Copy for *mut T {}
 
     pub mod ptr {
         #[inline]
diff --git a/tests/run-make/bin-emit-no-symbols/rmake.rs b/tests/run-make/bin-emit-no-symbols/rmake.rs
index 5586e53c050..2faeb20025b 100644
--- a/tests/run-make/bin-emit-no-symbols/rmake.rs
+++ b/tests/run-make/bin-emit-no-symbols/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // When setting the crate type as a "bin" (in app.rs),
 // this could cause a bug where some symbols would not be
 // emitted in the object files. This has been fixed, and
diff --git a/tests/run-make/box-struct-no-segfault/rmake.rs b/tests/run-make/box-struct-no-segfault/rmake.rs
index 1bbefd03541..06dcf61e9cc 100644
--- a/tests/run-make/box-struct-no-segfault/rmake.rs
+++ b/tests/run-make/box-struct-no-segfault/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // The crate "foo" tied to this test executes a very specific function,
 // which involves boxing an instance of the struct Foo. However,
 // this once caused a segmentation fault in cargo release builds due to an LLVM
diff --git a/tests/run-make/checksum-freshness/rmake.rs b/tests/run-make/checksum-freshness/rmake.rs
index 071db6b145b..60e4f81269b 100644
--- a/tests/run-make/checksum-freshness/rmake.rs
+++ b/tests/run-make/checksum-freshness/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 use run_make_support::{rfs, rustc};
 
 fn main() {
diff --git a/tests/run-make/compiler-lookup-paths-2/rmake.rs b/tests/run-make/compiler-lookup-paths-2/rmake.rs
index 99efb157b53..5401787b9bf 100644
--- a/tests/run-make/compiler-lookup-paths-2/rmake.rs
+++ b/tests/run-make/compiler-lookup-paths-2/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // This test checks that extern crate declarations in Cargo without a corresponding declaration
 // in the manifest of a dependency are NOT allowed. The last rustc call does it anyways, which
 // should result in a compilation failure.
diff --git a/tests/run-make/compiler-lookup-paths/rmake.rs b/tests/run-make/compiler-lookup-paths/rmake.rs
index 3ffa6e0592f..0e00f9b3400 100644
--- a/tests/run-make/compiler-lookup-paths/rmake.rs
+++ b/tests/run-make/compiler-lookup-paths/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // Since #19941, rustc can accept specifications on its library search paths.
 // This test runs Rust programs with varied library dependencies, expecting them
 // to succeed or fail depending on the situation.
diff --git a/tests/run-make/const-trait-stable-toolchain/rmake.rs b/tests/run-make/const-trait-stable-toolchain/rmake.rs
index 241de11ed59..09a7c27a106 100644
--- a/tests/run-make/const-trait-stable-toolchain/rmake.rs
+++ b/tests/run-make/const-trait-stable-toolchain/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // Test output of const super trait errors in both stable and nightly.
 // We don't want to provide suggestions on stable that only make sense in nightly.
 
diff --git a/tests/run-make/crate-circular-deps-link/rmake.rs b/tests/run-make/crate-circular-deps-link/rmake.rs
index 7cc28ac93e1..6771fdec7e8 100644
--- a/tests/run-make/crate-circular-deps-link/rmake.rs
+++ b/tests/run-make/crate-circular-deps-link/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // Test that previously triggered a linker failure with root cause
 // similar to one found in the issue #69368.
 //
diff --git a/tests/run-make/cross-lang-lto-riscv-abi/riscv-xlto.rs b/tests/run-make/cross-lang-lto-riscv-abi/riscv-xlto.rs
index c31cf27f9ae..dbccf8cea03 100644
--- a/tests/run-make/cross-lang-lto-riscv-abi/riscv-xlto.rs
+++ b/tests/run-make/cross-lang-lto-riscv-abi/riscv-xlto.rs
@@ -2,8 +2,12 @@
 #![feature(no_core, lang_items)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+trait PointeeSized {}
+#[lang = "meta_sized"]
+trait MetaSized: PointeeSized {}
 #[lang = "sized"]
-trait Sized {}
+trait Sized: MetaSized {}
 
 #[no_mangle]
 pub fn hello() {}
diff --git a/tests/run-make/cross-lang-lto-upstream-rlibs/rmake.rs b/tests/run-make/cross-lang-lto-upstream-rlibs/rmake.rs
index f0b8fa75bee..7fb0f690397 100644
--- a/tests/run-make/cross-lang-lto-upstream-rlibs/rmake.rs
+++ b/tests/run-make/cross-lang-lto-upstream-rlibs/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // When using the flag -C linker-plugin-lto, static libraries could lose their upstream object
 // files during compilation. This bug was fixed in #53031, and this test compiles a staticlib
 // dependent on upstream, checking that the upstream object file still exists after no LTO and
diff --git a/tests/run-make/cross-lang-lto/rmake.rs b/tests/run-make/cross-lang-lto/rmake.rs
index 50d37460d8d..8773070b1a9 100644
--- a/tests/run-make/cross-lang-lto/rmake.rs
+++ b/tests/run-make/cross-lang-lto/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // This test checks that the object files we generate are actually
 // LLVM bitcode files (as used by linker LTO plugins) when compiling with
 // -Clinker-plugin-lto.
diff --git a/tests/run-make/debugger-visualizer-dep-info/rmake.rs b/tests/run-make/debugger-visualizer-dep-info/rmake.rs
index f5cf39157ac..95a095e49d8 100644
--- a/tests/run-make/debugger-visualizer-dep-info/rmake.rs
+++ b/tests/run-make/debugger-visualizer-dep-info/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // This test checks that files referenced via #[debugger_visualizer] are
 // included in `--emit dep-info` output.
 // See https://github.com/rust-lang/rust/pull/111641
diff --git a/tests/run-make/dep-info/rmake.rs b/tests/run-make/dep-info/rmake.rs
index 508569b7671..8cef6e87f7c 100644
--- a/tests/run-make/dep-info/rmake.rs
+++ b/tests/run-make/dep-info/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // This is a simple smoke test for rustc's `--emit dep-info` feature. It prints out
 // information about dependencies in a Makefile-compatible format, as a `.d` file.
 // Note that this test does not check that the `.d` file is Makefile-compatible.
diff --git a/tests/run-make/diagnostics-traits-from-duplicate-crates/rmake.rs b/tests/run-make/diagnostics-traits-from-duplicate-crates/rmake.rs
index 32c4cf33896..5bc0a0c9519 100644
--- a/tests/run-make/diagnostics-traits-from-duplicate-crates/rmake.rs
+++ b/tests/run-make/diagnostics-traits-from-duplicate-crates/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // Non-regression test for issue #132920 where multiple versions of the same crate are present in
 // the dependency graph, and an unexpected error in a dependent crate caused an ICE in the
 // unsatisfied bounds diagnostics for traits present in multiple crate versions.
diff --git a/tests/run-make/doctests-merge/rmake.rs b/tests/run-make/doctests-merge/rmake.rs
index a88b050c50f..8236997d72d 100644
--- a/tests/run-make/doctests-merge/rmake.rs
+++ b/tests/run-make/doctests-merge/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 use std::path::Path;
 
 use run_make_support::{cwd, diff, rustc, rustdoc};
diff --git a/tests/run-make/doctests-runtool/rmake.rs b/tests/run-make/doctests-runtool/rmake.rs
index 817001c514b..aaba4174910 100644
--- a/tests/run-make/doctests-runtool/rmake.rs
+++ b/tests/run-make/doctests-runtool/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // Tests behavior of rustdoc `--test-runtool`.
 
 use std::path::PathBuf;
diff --git a/tests/run-make/dump-ice-to-disk/rmake.rs b/tests/run-make/dump-ice-to-disk/rmake.rs
index a7a98d31f50..09a34cdeb5e 100644
--- a/tests/run-make/dump-ice-to-disk/rmake.rs
+++ b/tests/run-make/dump-ice-to-disk/rmake.rs
@@ -17,14 +17,14 @@
 //!
 //! # Test history
 //!
-//! - The previous rmake.rs iteration of this test was flakey for unknown reason on `i686-mingw`
-//!   *specifically*, so assertion failures in this test was made extremely verbose to help
-//!   diagnose why the ICE messages was different *specifically* on `i686-mingw`.
-//! - An attempt is made to re-enable this test on `i686-mingw` (by removing `ignore-windows`). If
-//!   this test is still flakey, please restore the `ignore-windows` directive.
-
-//@ ignore-windows
-//FIXME(#128911): still flakey on i686-mingw.
+//! The previous rmake.rs iteration of this test was flaky for unknown reason on
+//! `i686-pc-windows-gnu` *specifically*, so assertion failures in this test was made extremely
+//! verbose to help diagnose why the ICE messages was different. It appears that backtraces on
+//! `i686-pc-windows-gnu` specifically are quite unpredictable in how many backtrace frames are
+//! involved.
+
+//@ ignore-cross-compile (exercising ICE dump on host)
+//@ ignore-i686-pc-windows-gnu (unwind mechanism produces unpredictable backtraces)
 
 use std::cell::OnceCell;
 use std::path::{Path, PathBuf};
diff --git a/tests/run-make/dump-mono-stats/rmake.rs b/tests/run-make/dump-mono-stats/rmake.rs
index f4142e0a31c..8ebc5758d9d 100644
--- a/tests/run-make/dump-mono-stats/rmake.rs
+++ b/tests/run-make/dump-mono-stats/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // A flag named dump-mono-stats was added to the compiler in 2022, which
 // collects stats on instantiation of items and their associated costs.
 // This test checks that the output stat file exists, and that it contains
diff --git a/tests/run-make/duplicate-output-flavors/rmake.rs b/tests/run-make/duplicate-output-flavors/rmake.rs
index 09545228807..f07339aceb9 100644
--- a/tests/run-make/duplicate-output-flavors/rmake.rs
+++ b/tests/run-make/duplicate-output-flavors/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 use run_make_support::rustc;
 
 fn main() {
diff --git a/tests/run-make/embed-metadata/rmake.rs b/tests/run-make/embed-metadata/rmake.rs
index acefb186484..a41716d1542 100644
--- a/tests/run-make/embed-metadata/rmake.rs
+++ b/tests/run-make/embed-metadata/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // Tests the -Zembed-metadata compiler flag.
 // Tracking issue: https://github.com/rust-lang/rust/issues/139165
 
diff --git a/tests/run-make/embed-source-dwarf/rmake.rs b/tests/run-make/embed-source-dwarf/rmake.rs
index 550c8b9b3c9..99fad359054 100644
--- a/tests/run-make/embed-source-dwarf/rmake.rs
+++ b/tests/run-make/embed-source-dwarf/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 //@ ignore-windows
 //@ ignore-apple
 
diff --git a/tests/run-make/emit-named-files/rmake.rs b/tests/run-make/emit-named-files/rmake.rs
index 1570e1adc25..b482fb3268b 100644
--- a/tests/run-make/emit-named-files/rmake.rs
+++ b/tests/run-make/emit-named-files/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 use std::path::Path;
 
 use run_make_support::{rfs, rustc};
diff --git a/tests/run-make/emit-path-unhashed/rmake.rs b/tests/run-make/emit-path-unhashed/rmake.rs
index a97153e37dd..5d5256621ce 100644
--- a/tests/run-make/emit-path-unhashed/rmake.rs
+++ b/tests/run-make/emit-path-unhashed/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // Specifying how rustc outputs a file can be done in different ways, such as
 // the output flag or the KIND=NAME syntax. However, some of these methods used
 // to result in different hashes on output files even though they yielded the
diff --git a/tests/run-make/emit-stack-sizes/rmake.rs b/tests/run-make/emit-stack-sizes/rmake.rs
index 53cc9ee5943..886e875cfae 100644
--- a/tests/run-make/emit-stack-sizes/rmake.rs
+++ b/tests/run-make/emit-stack-sizes/rmake.rs
@@ -6,6 +6,7 @@
 // this diagnostics information should be located.
 // See https://github.com/rust-lang/rust/pull/51946
 
+//@ needs-target-std
 //@ ignore-windows
 //@ ignore-apple
 // Reason: this feature only works when the output object format is ELF.
diff --git a/tests/run-make/emit-to-stdout/rmake.rs b/tests/run-make/emit-to-stdout/rmake.rs
index a9a3796731b..19c15b72fe4 100644
--- a/tests/run-make/emit-to-stdout/rmake.rs
+++ b/tests/run-make/emit-to-stdout/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 //! If `-o -` or `--emit KIND=-` is provided, output should be written to stdout
 //! instead. Binary output (`obj`, `llvm-bc`, `link` and `metadata`)
 //! being written this way will result in an error if stdout is a tty.
diff --git a/tests/run-make/env-dep-info/rmake.rs b/tests/run-make/env-dep-info/rmake.rs
index 5b51a5476f4..97006a63205 100644
--- a/tests/run-make/env-dep-info/rmake.rs
+++ b/tests/run-make/env-dep-info/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // Inside dep-info emit files, #71858 made it so all accessed environment
 // variables are usefully printed. This test checks that this feature works
 // as intended by checking if the environment variables used in compilation
diff --git a/tests/run-make/error-found-staticlib-instead-crate/rmake.rs b/tests/run-make/error-found-staticlib-instead-crate/rmake.rs
index 8c707092b7e..15f09c83e20 100644
--- a/tests/run-make/error-found-staticlib-instead-crate/rmake.rs
+++ b/tests/run-make/error-found-staticlib-instead-crate/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // When rustc is looking for a crate but is given a staticlib instead,
 // the error message should be helpful and indicate precisely the cause
 // of the compilation failure.
diff --git a/tests/run-make/exit-code/rmake.rs b/tests/run-make/exit-code/rmake.rs
index d3dcc04428c..5fdf920b55a 100644
--- a/tests/run-make/exit-code/rmake.rs
+++ b/tests/run-make/exit-code/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // Test that we exit with the correct exit code for successful / unsuccessful / ICE compilations
 
 use run_make_support::{rustc, rustdoc};
diff --git a/tests/run-make/export/disambiguator/rmake.rs b/tests/run-make/export/disambiguator/rmake.rs
index 743db1933fb..f855e42d08e 100644
--- a/tests/run-make/export/disambiguator/rmake.rs
+++ b/tests/run-make/export/disambiguator/rmake.rs
@@ -1,12 +1,7 @@
+//@ needs-target-std
 use run_make_support::rustc;
 
 fn main() {
-    rustc()
-        .env("RUSTC_FORCE_RUSTC_VERSION", "1")
-        .input("libr.rs")
-        .run();
-    rustc()
-        .env("RUSTC_FORCE_RUSTC_VERSION", "2")
-        .input("app.rs")
-        .run();
+    rustc().env("RUSTC_FORCE_RUSTC_VERSION", "1").input("libr.rs").run();
+    rustc().env("RUSTC_FORCE_RUSTC_VERSION", "2").input("app.rs").run();
 }
diff --git a/tests/run-make/export/extern-opt/rmake.rs b/tests/run-make/export/extern-opt/rmake.rs
index 821e2eb2149..a2f9ba28c2f 100644
--- a/tests/run-make/export/extern-opt/rmake.rs
+++ b/tests/run-make/export/extern-opt/rmake.rs
@@ -1,10 +1,8 @@
-use run_make_support::{rustc, dynamic_lib_name};
+//@ needs-target-std
+use run_make_support::{dynamic_lib_name, rustc};
 
 fn main() {
-    rustc()
-        .env("RUSTC_FORCE_RUSTC_VERSION", "1")
-        .input("libr.rs")
-        .run();
+    rustc().env("RUSTC_FORCE_RUSTC_VERSION", "1").input("libr.rs").run();
 
     rustc()
         .env("RUSTC_FORCE_RUSTC_VERSION", "2")
diff --git a/tests/run-make/export/simple/rmake.rs b/tests/run-make/export/simple/rmake.rs
index 743db1933fb..f855e42d08e 100644
--- a/tests/run-make/export/simple/rmake.rs
+++ b/tests/run-make/export/simple/rmake.rs
@@ -1,12 +1,7 @@
+//@ needs-target-std
 use run_make_support::rustc;
 
 fn main() {
-    rustc()
-        .env("RUSTC_FORCE_RUSTC_VERSION", "1")
-        .input("libr.rs")
-        .run();
-    rustc()
-        .env("RUSTC_FORCE_RUSTC_VERSION", "2")
-        .input("app.rs")
-        .run();
+    rustc().env("RUSTC_FORCE_RUSTC_VERSION", "1").input("libr.rs").run();
+    rustc().env("RUSTC_FORCE_RUSTC_VERSION", "2").input("app.rs").run();
 }
diff --git a/tests/run-make/extern-diff-internal-name/rmake.rs b/tests/run-make/extern-diff-internal-name/rmake.rs
index 1a7f34d65bc..1bae8decb05 100644
--- a/tests/run-make/extern-diff-internal-name/rmake.rs
+++ b/tests/run-make/extern-diff-internal-name/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // In the following scenario:
 // 1. The crate foo, is referenced multiple times
 // 2. --extern foo=./path/to/libbar.rlib is specified to rustc
diff --git a/tests/run-make/extern-flag-fun/rmake.rs b/tests/run-make/extern-flag-fun/rmake.rs
index c1825f6bbb8..181a76b7cfa 100644
--- a/tests/run-make/extern-flag-fun/rmake.rs
+++ b/tests/run-make/extern-flag-fun/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // The --extern flag can override the default crate search of
 // the compiler and directly fetch a given path. There are a few rules
 // to follow: for example, there can't be more than one rlib, the crates must
diff --git a/tests/run-make/extern-flag-rename-transitive/rmake.rs b/tests/run-make/extern-flag-rename-transitive/rmake.rs
index 0090d487f03..c5bff7bbb69 100644
--- a/tests/run-make/extern-flag-rename-transitive/rmake.rs
+++ b/tests/run-make/extern-flag-rename-transitive/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // In this test, baz.rs is looking for an extern crate "a" which
 // does not exist, and can only run through the --extern rustc flag
 // defining that the "a" crate is in fact just "foo". This test
diff --git a/tests/run-make/extern-multiple-copies/rmake.rs b/tests/run-make/extern-multiple-copies/rmake.rs
index 8b67e6d9fac..d9d769d178c 100644
--- a/tests/run-make/extern-multiple-copies/rmake.rs
+++ b/tests/run-make/extern-multiple-copies/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // In this test, the rust library foo1 exists in two different locations, but only one
 // is required by the --extern flag. This test checks that the copy is ignored (as --extern
 // demands fetching only the original instance of foo1) and that no error is emitted, resulting
diff --git a/tests/run-make/extern-multiple-copies2/rmake.rs b/tests/run-make/extern-multiple-copies2/rmake.rs
index 59913bfa42b..4188d5bdc18 100644
--- a/tests/run-make/extern-multiple-copies2/rmake.rs
+++ b/tests/run-make/extern-multiple-copies2/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // Almost identical to `extern-multiple-copies`, but with a variation in the --extern calls
 // and the addition of #[macro_use] in the rust code files, which used to break --extern
 // until #33625.
diff --git a/tests/run-make/ice-static-mir/rmake.rs b/tests/run-make/ice-static-mir/rmake.rs
index 2d4ffa379b6..b6a04bf877e 100644
--- a/tests/run-make/ice-static-mir/rmake.rs
+++ b/tests/run-make/ice-static-mir/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // Trying to access mid-level internal representation (MIR) in statics
 // used to cause an internal compiler error (ICE), now handled as a proper
 // error since #100211. This test checks that the correct error is printed
diff --git a/tests/run-make/include-all-symbols-linking/rmake.rs b/tests/run-make/include-all-symbols-linking/rmake.rs
index bab510fb5be..4f85ee179f5 100644
--- a/tests/run-make/include-all-symbols-linking/rmake.rs
+++ b/tests/run-make/include-all-symbols-linking/rmake.rs
@@ -7,6 +7,7 @@
 // See https://github.com/rust-lang/rust/pull/95604
 // See https://github.com/rust-lang/rust/issues/47384
 
+//@ needs-target-std
 //@ ignore-wasm differences in object file formats causes errors in the llvm_objdump step.
 //@ ignore-windows differences in object file formats causes errors in the llvm_objdump step.
 
diff --git a/tests/run-make/include-bytes-deps/rmake.rs b/tests/run-make/include-bytes-deps/rmake.rs
index ea371ddae56..2938f334243 100644
--- a/tests/run-make/include-bytes-deps/rmake.rs
+++ b/tests/run-make/include-bytes-deps/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // include_bytes! and include_str! in `main.rs`
 // should register the included file as of #24423,
 // and this test checks that this is still the case.
diff --git a/tests/run-make/incremental-debugger-visualizer/rmake.rs b/tests/run-make/incremental-debugger-visualizer/rmake.rs
index 07c920cc04a..3a4fc1d1792 100644
--- a/tests/run-make/incremental-debugger-visualizer/rmake.rs
+++ b/tests/run-make/incremental-debugger-visualizer/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // This test ensures that changes to files referenced via #[debugger_visualizer]
 // (in this case, foo.py and foo.natvis) are picked up when compiling incrementally.
 // See https://github.com/rust-lang/rust/pull/111641
diff --git a/tests/run-make/inline-always-many-cgu/rmake.rs b/tests/run-make/inline-always-many-cgu/rmake.rs
index 678b949bc70..18068578dd0 100644
--- a/tests/run-make/inline-always-many-cgu/rmake.rs
+++ b/tests/run-make/inline-always-many-cgu/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 use std::ffi::OsStr;
 
 use run_make_support::regex::Regex;
diff --git a/tests/run-make/invalid-so/rmake.rs b/tests/run-make/invalid-so/rmake.rs
index 754c53a49b9..ee886b5ee3a 100644
--- a/tests/run-make/invalid-so/rmake.rs
+++ b/tests/run-make/invalid-so/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // When a fake library was given to the compiler, it would
 // result in an obscure and unhelpful error message. This test
 // creates a false "foo" dylib, and checks that the standard error
diff --git a/tests/run-make/invalid-staticlib/rmake.rs b/tests/run-make/invalid-staticlib/rmake.rs
index ba9e07dd07b..4844bff329a 100644
--- a/tests/run-make/invalid-staticlib/rmake.rs
+++ b/tests/run-make/invalid-staticlib/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // If the static library provided is not valid (in this test,
 // created as an empty file),
 // rustc should print a normal error message and not throw
diff --git a/tests/run-make/invalid-symlink-search-path/rmake.rs b/tests/run-make/invalid-symlink-search-path/rmake.rs
index 7b7e7c79442..4eb6e6f7706 100644
--- a/tests/run-make/invalid-symlink-search-path/rmake.rs
+++ b/tests/run-make/invalid-symlink-search-path/rmake.rs
@@ -5,6 +5,7 @@
 //
 // See https://github.com/rust-lang/rust/issues/26006
 
+//@ needs-target-std
 //@ needs-symlink
 //Reason: symlink requires elevated permission in Windows
 
diff --git a/tests/run-make/invalid-tmpdir-env-var/rmake.rs b/tests/run-make/invalid-tmpdir-env-var/rmake.rs
index db44debb319..c5b9dca33a9 100644
--- a/tests/run-make/invalid-tmpdir-env-var/rmake.rs
+++ b/tests/run-make/invalid-tmpdir-env-var/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // When the TMP (on Windows) or TMPDIR (on Unix) variable is set to an invalid
 // or non-existing directory, this used to cause an internal compiler error (ICE). After the
 // addition of proper error handling in #28430, this test checks that the expected message is
diff --git a/tests/run-make/issue-107495-archive-permissions/rmake.rs b/tests/run-make/issue-107495-archive-permissions/rmake.rs
index 87d4faaa77a..80474ba32c2 100644
--- a/tests/run-make/issue-107495-archive-permissions/rmake.rs
+++ b/tests/run-make/issue-107495-archive-permissions/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 #[cfg(unix)]
 use std::os::unix::fs::PermissionsExt;
 use std::path::Path;
diff --git a/tests/run-make/issue-125484-used-dependencies/rmake.rs b/tests/run-make/issue-125484-used-dependencies/rmake.rs
index bc0a18de66e..afcea34783f 100644
--- a/tests/run-make/issue-125484-used-dependencies/rmake.rs
+++ b/tests/run-make/issue-125484-used-dependencies/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // Non-regression test for issues #125474, #125484, #125646, with the repro taken from #125484. Some
 // queries use "used dependencies" while others use "speculatively loaded dependencies", and an
 // indexing ICE appeared in some cases when these were unexpectedly used in the same context.
diff --git a/tests/run-make/json-error-no-offset/rmake.rs b/tests/run-make/json-error-no-offset/rmake.rs
index 629d9c4c16e..3f45778ca04 100644
--- a/tests/run-make/json-error-no-offset/rmake.rs
+++ b/tests/run-make/json-error-no-offset/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // The byte positions in json format error logging used to have a small, difficult
 // to predict offset. This was changed to be the top of the file every time in #42973,
 // and this test checks that the measurements appearing in the standard error are correct.
diff --git a/tests/run-make/lib-trait-for-trait-no-ice/rmake.rs b/tests/run-make/lib-trait-for-trait-no-ice/rmake.rs
index 0c5e12055e8..af42911502e 100644
--- a/tests/run-make/lib-trait-for-trait-no-ice/rmake.rs
+++ b/tests/run-make/lib-trait-for-trait-no-ice/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // Inside a library, implementing a trait for another trait
 // with a lifetime used to cause an internal compiler error (ICE).
 // This test checks that this bug does not make a resurgence -
diff --git a/tests/run-make/link-arg/rmake.rs b/tests/run-make/link-arg/rmake.rs
index c0bf8d972af..bfceaae0dba 100644
--- a/tests/run-make/link-arg/rmake.rs
+++ b/tests/run-make/link-arg/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // In 2016, the rustc flag "-C link-arg" was introduced - it can be repeatedly used
 // to add single arguments to the linker. This test passes 2 arguments to the linker using it,
 // then checks that the compiler's output contains the arguments passed to it.
diff --git a/tests/run-make/link-args-order/rmake.rs b/tests/run-make/link-args-order/rmake.rs
index fe0d02926ef..a4591ea3949 100644
--- a/tests/run-make/link-args-order/rmake.rs
+++ b/tests/run-make/link-args-order/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // Passing linker arguments to the compiler used to be lost or reordered in a messy way
 // as they were passed further to the linker. This was fixed in #70665, and this test
 // checks that linker arguments remain intact and in the order they were originally passed in.
diff --git a/tests/run-make/link-dedup/rmake.rs b/tests/run-make/link-dedup/rmake.rs
index f38603dee8c..0148817f987 100644
--- a/tests/run-make/link-dedup/rmake.rs
+++ b/tests/run-make/link-dedup/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // When native libraries are passed to the linker, there used to be an annoyance
 // where multiple instances of the same library in a row would cause duplication in
 // outputs. This has been fixed, and this test checks that it stays fixed.
diff --git a/tests/run-make/linker-warning/rmake.rs b/tests/run-make/linker-warning/rmake.rs
index bc21739fefc..eb1bbbff8ef 100644
--- a/tests/run-make/linker-warning/rmake.rs
+++ b/tests/run-make/linker-warning/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 use run_make_support::{Rustc, diff, regex, rustc};
 
 fn run_rustc() -> Rustc {
diff --git a/tests/run-make/llvm-outputs/rmake.rs b/tests/run-make/llvm-outputs/rmake.rs
index 2ce31b260a1..dabae38c141 100644
--- a/tests/run-make/llvm-outputs/rmake.rs
+++ b/tests/run-make/llvm-outputs/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 // test that directories get created when emitting llvm bitcode and IR
 
 use std::path::PathBuf;
diff --git a/tests/run-make/lto-avoid-object-duplication/rmake.rs b/tests/run-make/lto-avoid-object-duplication/rmake.rs
index b0e7494cb51..394aed2b881 100644
--- a/tests/run-make/lto-avoid-object-duplication/rmake.rs
+++ b/tests/run-make/lto-avoid-object-duplication/rmake.rs
@@ -8,6 +8,7 @@
 // This test makes sure that functions defined in the upstream crates do not
 // appear twice in the final staticlib when listing all the symbols from it.
 
+//@ needs-target-std
 //@ ignore-windows
 // Reason: `llvm-objdump`'s output looks different on windows than on other platforms.
 // Only checking on Unix platforms should suffice.
diff --git a/tests/run-make/manual-crate-name/rmake.rs b/tests/run-make/manual-crate-name/rmake.rs
index 9f480ec6b6a..ead3b669e2d 100644
--- a/tests/run-make/manual-crate-name/rmake.rs
+++ b/tests/run-make/manual-crate-name/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 use run_make_support::{path, rustc};
 
 fn main() {
diff --git a/tests/run-make/many-crates-but-no-match/rmake.rs b/tests/run-make/many-crates-but-no-match/rmake.rs
index 938ffce6a03..449b6e2908d 100644
--- a/tests/run-make/many-crates-but-no-match/rmake.rs
+++ b/tests/run-make/many-crates-but-no-match/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // An extended version of the ui/changing-crates.rs test, this test puts
 // multiple mismatching crates into the search path of crateC (A2 and A3)
 // and checks that the standard error contains helpful messages to indicate
diff --git a/tests/run-make/metadata-dep-info/rmake.rs b/tests/run-make/metadata-dep-info/rmake.rs
index f4bb3ea63fb..82fa4c014e1 100644
--- a/tests/run-make/metadata-dep-info/rmake.rs
+++ b/tests/run-make/metadata-dep-info/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // Emitting dep-info alongside metadata would present subtle discrepancies
 // in the output file, such as the filename transforming underscores_ into hyphens-.
 // After the fix in #114750, this test checks that the emitted files are identical
diff --git a/tests/run-make/metadata-only-crate-no-ice/rmake.rs b/tests/run-make/metadata-only-crate-no-ice/rmake.rs
index e6f852fca41..2e771d87933 100644
--- a/tests/run-make/metadata-only-crate-no-ice/rmake.rs
+++ b/tests/run-make/metadata-only-crate-no-ice/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // In a dependency hierarchy, metadata-only crates could cause an Internal
 // Compiler Error (ICE) due to a compiler bug - not correctly fetching sources for
 // metadata-only crates. This test is a minimal reproduction of a program that triggered
diff --git a/tests/run-make/min-global-align/min_global_align.rs b/tests/run-make/min-global-align/min_global_align.rs
index cd1ef8cb351..fd6f8357030 100644
--- a/tests/run-make/min-global-align/min_global_align.rs
+++ b/tests/run-make/min-global-align/min_global_align.rs
@@ -9,8 +9,14 @@ pub static mut STATIC_MUT_BOOL: bool = true;
 const CONST_BOOL: bool = true;
 pub static CONST_BOOL_REF: &'static bool = &CONST_BOOL;
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 
 #[lang = "copy"]
 trait Copy {}
diff --git a/tests/run-make/missing-crate-dependency/rmake.rs b/tests/run-make/missing-crate-dependency/rmake.rs
index dae77032f7d..7abdd11c509 100644
--- a/tests/run-make/missing-crate-dependency/rmake.rs
+++ b/tests/run-make/missing-crate-dependency/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // A simple smoke test to check that rustc fails compilation
 // and outputs a helpful message when a dependency is missing
 // in a dependency chain.
diff --git a/tests/run-make/multiple-emits/rmake.rs b/tests/run-make/multiple-emits/rmake.rs
index 8a5eb1d9d85..d8a008660c0 100644
--- a/tests/run-make/multiple-emits/rmake.rs
+++ b/tests/run-make/multiple-emits/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 use run_make_support::{path, rustc};
 
 fn main() {
diff --git a/tests/run-make/native-lib-alt-naming/rmake.rs b/tests/run-make/native-lib-alt-naming/rmake.rs
index d1ea0fc8687..a1dc002533f 100644
--- a/tests/run-make/native-lib-alt-naming/rmake.rs
+++ b/tests/run-make/native-lib-alt-naming/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // On MSVC the alternative naming format for static libraries (`libfoo.a`) is accepted in addition
 // to the default format (`foo.lib`).
 
diff --git a/tests/run-make/native-link-modifier-verbatim-linker/rmake.rs b/tests/run-make/native-link-modifier-verbatim-linker/rmake.rs
index 6868cb368cc..e06be13d9b9 100644
--- a/tests/run-make/native-link-modifier-verbatim-linker/rmake.rs
+++ b/tests/run-make/native-link-modifier-verbatim-linker/rmake.rs
@@ -3,6 +3,7 @@
 // This test is the same as native-link-modifier-rustc, but without rlibs.
 // See https://github.com/rust-lang/rust/issues/99425
 
+//@ needs-target-std
 //@ ignore-apple
 // Reason: linking fails due to the unusual ".ext" staticlib name.
 
diff --git a/tests/run-make/native-link-modifier-verbatim-rustc/rmake.rs b/tests/run-make/native-link-modifier-verbatim-rustc/rmake.rs
index 703b8a80ef3..d885df9e79e 100644
--- a/tests/run-make/native-link-modifier-verbatim-rustc/rmake.rs
+++ b/tests/run-make/native-link-modifier-verbatim-rustc/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // `verbatim` is a native link modifier that forces rustc to only accept libraries with
 // a specified name. This test checks that this modifier works as intended.
 // This test is the same as native-link-modifier-linker, but with rlibs.
diff --git a/tests/run-make/no-builtins-attribute/rmake.rs b/tests/run-make/no-builtins-attribute/rmake.rs
index 7182c65a2c5..038958f19ed 100644
--- a/tests/run-make/no-builtins-attribute/rmake.rs
+++ b/tests/run-make/no-builtins-attribute/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // `no_builtins` is an attribute related to LLVM's optimizations. In order to ensure that it has an
 // effect on link-time optimizations (LTO), it should be added to function declarations in a crate.
 // This test uses the `llvm-filecheck` tool to determine that this attribute is successfully
diff --git a/tests/run-make/no-builtins-lto/rmake.rs b/tests/run-make/no-builtins-lto/rmake.rs
index 56fdfde42f0..a1d9dc43e71 100644
--- a/tests/run-make/no-builtins-lto/rmake.rs
+++ b/tests/run-make/no-builtins-lto/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // The rlib produced by a no_builtins crate should be explicitly linked
 // during compilation, and as a result be present in the linker arguments.
 // See the comments inside this file for more details.
diff --git a/tests/run-make/non-unicode-env/rmake.rs b/tests/run-make/non-unicode-env/rmake.rs
index d708192908c..b7a3c51db5b 100644
--- a/tests/run-make/non-unicode-env/rmake.rs
+++ b/tests/run-make/non-unicode-env/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 use run_make_support::{rfs, rustc};
 
 fn main() {
diff --git a/tests/run-make/non-unicode-in-incremental-dir/rmake.rs b/tests/run-make/non-unicode-in-incremental-dir/rmake.rs
index 42bd4b1b799..5c437a3fe00 100644
--- a/tests/run-make/non-unicode-in-incremental-dir/rmake.rs
+++ b/tests/run-make/non-unicode-in-incremental-dir/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 use run_make_support::{rfs, rustc};
 
 fn main() {
diff --git a/tests/run-make/notify-all-emit-artifacts/rmake.rs b/tests/run-make/notify-all-emit-artifacts/rmake.rs
index 321eda48941..5896cffefcc 100644
--- a/tests/run-make/notify-all-emit-artifacts/rmake.rs
+++ b/tests/run-make/notify-all-emit-artifacts/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // rust should produce artifact notifications about files it was asked to --emit.
 //
 // It should work in incremental mode both on the first pass where files are generated as well
diff --git a/tests/run-make/optimization-remarks-dir/rmake.rs b/tests/run-make/optimization-remarks-dir/rmake.rs
index afcb8c3e3eb..df656302d78 100644
--- a/tests/run-make/optimization-remarks-dir/rmake.rs
+++ b/tests/run-make/optimization-remarks-dir/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // In this test, the function `bar` has #[inline(never)] and the function `foo`
 // does not. This test outputs LLVM optimization remarks twice - first for all
 // functions (including `bar`, and the `inline` mention), and then for only `foo`
diff --git a/tests/run-make/overwrite-input/rmake.rs b/tests/run-make/overwrite-input/rmake.rs
index b87a7c7e0a8..bdf7860caa8 100644
--- a/tests/run-make/overwrite-input/rmake.rs
+++ b/tests/run-make/overwrite-input/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // An attempt to set the output `-o` into a directory or a file we cannot write into should indeed
 // be an error; but not an ICE (Internal Compiler Error). This test attempts both and checks
 // that the standard error matches what is expected.
diff --git a/tests/run-make/parallel-rustc-no-overwrite/rmake.rs b/tests/run-make/parallel-rustc-no-overwrite/rmake.rs
index aa38eb664cf..f7531ab4bf6 100644
--- a/tests/run-make/parallel-rustc-no-overwrite/rmake.rs
+++ b/tests/run-make/parallel-rustc-no-overwrite/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // When two instances of rustc are invoked in parallel, they
 // can conflict on their temporary files and overwrite each others',
 // leading to unsuccessful compilation. The -Z temps-dir flag adds
diff --git a/tests/run-make/pass-linker-flags-from-dep/rmake.rs b/tests/run-make/pass-linker-flags-from-dep/rmake.rs
index 4b8e0486e14..1cd55468737 100644
--- a/tests/run-make/pass-linker-flags-from-dep/rmake.rs
+++ b/tests/run-make/pass-linker-flags-from-dep/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // A similar test to pass-linker-flags, testing that the `-l link-arg` flag
 // respects the order relative to other `-l` flags, but this time, the flags
 // are passed on the compilation of a dependency. This test checks that the
diff --git a/tests/run-make/pass-linker-flags/rmake.rs b/tests/run-make/pass-linker-flags/rmake.rs
index de69567a6e6..a44da7b32ff 100644
--- a/tests/run-make/pass-linker-flags/rmake.rs
+++ b/tests/run-make/pass-linker-flags/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // This test checks the proper function of `-l link-arg=NAME`, which, unlike
 // -C link-arg, is supposed to guarantee that the order relative to other -l
 // options will be respected. In this test, compilation fails (because none of the
diff --git a/tests/run-make/pgo-gen-no-imp-symbols/rmake.rs b/tests/run-make/pgo-gen-no-imp-symbols/rmake.rs
index 85ade7885ce..db25eab104a 100644
--- a/tests/run-make/pgo-gen-no-imp-symbols/rmake.rs
+++ b/tests/run-make/pgo-gen-no-imp-symbols/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // LLVM's profiling instrumentation adds a few symbols that are used by the profiler runtime.
 // Since these show up as globals in the LLVM IR, the compiler generates dllimport-related
 // __imp_ stubs for them. This can lead to linker errors because the instrumentation
diff --git a/tests/run-make/pretty-print-with-dep-file/rmake.rs b/tests/run-make/pretty-print-with-dep-file/rmake.rs
index 24ae6bc2456..e473854a12e 100644
--- a/tests/run-make/pretty-print-with-dep-file/rmake.rs
+++ b/tests/run-make/pretty-print-with-dep-file/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // Passing --emit=dep-info to the Rust compiler should create a .d file...
 // but it failed to do so in Rust 1.69.0 when combined with -Z unpretty=expanded
 // due to a bug. This test checks that -Z unpretty=expanded does not prevent the
diff --git a/tests/run-make/proc-macro-three-crates/rmake.rs b/tests/run-make/proc-macro-three-crates/rmake.rs
index d3735540fdd..e5a3385acbc 100644
--- a/tests/run-make/proc-macro-three-crates/rmake.rs
+++ b/tests/run-make/proc-macro-three-crates/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // A compiler bug caused the following issue:
 // If a crate A depends on crate B, and crate B
 // depends on crate C, and crate C contains a procedural
diff --git a/tests/run-make/raw-dylib-cross-compilation/lib.rs b/tests/run-make/raw-dylib-cross-compilation/lib.rs
index d3b7fd23ca8..8d53ac04485 100644
--- a/tests/run-make/raw-dylib-cross-compilation/lib.rs
+++ b/tests/run-make/raw-dylib-cross-compilation/lib.rs
@@ -4,8 +4,12 @@
 #![crate_type = "lib"]
 
 // This is needed because of #![no_core]:
+#[lang = "pointee_sized"]
+trait PointeeSized {}
+#[lang = "meta_sized"]
+trait MetaSized: PointeeSized {}
 #[lang = "sized"]
-trait Sized {}
+trait Sized: MetaSized {}
 
 #[link(name = "extern_1", kind = "raw-dylib")]
 extern "C" {
diff --git a/tests/run-make/remap-path-prefix-dwarf/rmake.rs b/tests/run-make/remap-path-prefix-dwarf/rmake.rs
index 3d6ca014fc2..3b88fca0bb7 100644
--- a/tests/run-make/remap-path-prefix-dwarf/rmake.rs
+++ b/tests/run-make/remap-path-prefix-dwarf/rmake.rs
@@ -4,6 +4,7 @@
 // It tests several cases, each of them has a detailed description attached to it.
 // See https://github.com/rust-lang/rust/pull/96867
 
+//@ needs-target-std
 //@ ignore-windows
 // Reason: the remap path prefix is not printed in the dwarf dump.
 
diff --git a/tests/run-make/remap-path-prefix/rmake.rs b/tests/run-make/remap-path-prefix/rmake.rs
index b4f7f4769b5..b75ca9e796a 100644
--- a/tests/run-make/remap-path-prefix/rmake.rs
+++ b/tests/run-make/remap-path-prefix/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // Generating metadata alongside remap-path-prefix would fail to actually remap the path
 // in the metadata. After this was fixed in #85344, this test checks that "auxiliary" is being
 // successfully remapped to "/the/aux" in the rmeta files.
diff --git a/tests/run-make/repr128-dwarf/rmake.rs b/tests/run-make/repr128-dwarf/rmake.rs
index 8227c51516f..1372d2bcc46 100644
--- a/tests/run-make/repr128-dwarf/rmake.rs
+++ b/tests/run-make/repr128-dwarf/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 //@ ignore-windows
 // This test should be replaced with one in tests/debuginfo once GDB or LLDB support 128-bit enums.
 
diff --git a/tests/run-make/reproducible-build-2/rmake.rs b/tests/run-make/reproducible-build-2/rmake.rs
index 8b5825cad30..0e1781dbfbe 100644
--- a/tests/run-make/reproducible-build-2/rmake.rs
+++ b/tests/run-make/reproducible-build-2/rmake.rs
@@ -6,6 +6,7 @@
 // Outputs should be identical.
 // See https://github.com/rust-lang/rust/issues/34902
 
+//@ needs-target-std
 //@ ignore-windows
 // Reasons:
 // 1. The object files are reproducible, but their paths are not, which causes
diff --git a/tests/run-make/resolve-rename/rmake.rs b/tests/run-make/resolve-rename/rmake.rs
index 21ec7f85274..8afdaadbfde 100644
--- a/tests/run-make/resolve-rename/rmake.rs
+++ b/tests/run-make/resolve-rename/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // If a library is compiled with -C extra-filename, the rust compiler
 // will take this into account when searching for libraries. However,
 // if that library is then renamed, the rust compiler should fall back
diff --git a/tests/run-make/rlib-format-packed-bundled-libs-2/rmake.rs b/tests/run-make/rlib-format-packed-bundled-libs-2/rmake.rs
index 5a1460963b6..70d1ead85b5 100644
--- a/tests/run-make/rlib-format-packed-bundled-libs-2/rmake.rs
+++ b/tests/run-make/rlib-format-packed-bundled-libs-2/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // `-Z packed_bundled_libs` is an unstable rustc flag that makes the compiler
 // only require a native library and no supplementary object files to compile.
 // This test simply checks that this flag can be passed alongside verbatim syntax
diff --git a/tests/run-make/rustc-macro-dep-files/rmake.rs b/tests/run-make/rustc-macro-dep-files/rmake.rs
index bc02a04c9b8..eb4771fea7a 100644
--- a/tests/run-make/rustc-macro-dep-files/rmake.rs
+++ b/tests/run-make/rustc-macro-dep-files/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // --emit dep-info used to print all macro-generated code it could
 // find as if it was part of a nonexistent file named "proc-macro source",
 // which is not a valid path. After this was fixed in #36776, this test checks
diff --git a/tests/run-make/rustdoc-scrape-examples-invalid-expr/rmake.rs b/tests/run-make/rustdoc-scrape-examples-invalid-expr/rmake.rs
index e9c54fa3922..8996ff184c9 100644
--- a/tests/run-make/rustdoc-scrape-examples-invalid-expr/rmake.rs
+++ b/tests/run-make/rustdoc-scrape-examples-invalid-expr/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 #[path = "../rustdoc-scrape-examples-remap/scrape.rs"]
 mod scrape;
 
diff --git a/tests/run-make/rustdoc-scrape-examples-multiple/rmake.rs b/tests/run-make/rustdoc-scrape-examples-multiple/rmake.rs
index e9c54fa3922..8996ff184c9 100644
--- a/tests/run-make/rustdoc-scrape-examples-multiple/rmake.rs
+++ b/tests/run-make/rustdoc-scrape-examples-multiple/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 #[path = "../rustdoc-scrape-examples-remap/scrape.rs"]
 mod scrape;
 
diff --git a/tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs b/tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs
index e9c54fa3922..8996ff184c9 100644
--- a/tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs
+++ b/tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 #[path = "../rustdoc-scrape-examples-remap/scrape.rs"]
 mod scrape;
 
diff --git a/tests/run-make/rustdoc-scrape-examples-remap/rmake.rs b/tests/run-make/rustdoc-scrape-examples-remap/rmake.rs
index 4e3b895aef0..ead3920c761 100644
--- a/tests/run-make/rustdoc-scrape-examples-remap/rmake.rs
+++ b/tests/run-make/rustdoc-scrape-examples-remap/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 mod scrape;
 
 fn main() {
diff --git a/tests/run-make/rustdoc-scrape-examples-test/rmake.rs b/tests/run-make/rustdoc-scrape-examples-test/rmake.rs
index f96ba113ff7..0868507c4ae 100644
--- a/tests/run-make/rustdoc-scrape-examples-test/rmake.rs
+++ b/tests/run-make/rustdoc-scrape-examples-test/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 #[path = "../rustdoc-scrape-examples-remap/scrape.rs"]
 mod scrape;
 
diff --git a/tests/run-make/rustdoc-scrape-examples-whitespace/rmake.rs b/tests/run-make/rustdoc-scrape-examples-whitespace/rmake.rs
index e9c54fa3922..8996ff184c9 100644
--- a/tests/run-make/rustdoc-scrape-examples-whitespace/rmake.rs
+++ b/tests/run-make/rustdoc-scrape-examples-whitespace/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 #[path = "../rustdoc-scrape-examples-remap/scrape.rs"]
 mod scrape;
 
diff --git a/tests/run-make/rustdoc-with-short-out-dir-option/rmake.rs b/tests/run-make/rustdoc-with-short-out-dir-option/rmake.rs
index 4a8896cc975..49df3bedc84 100644
--- a/tests/run-make/rustdoc-with-short-out-dir-option/rmake.rs
+++ b/tests/run-make/rustdoc-with-short-out-dir-option/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 use run_make_support::{htmldocck, rustdoc};
 
 fn main() {
diff --git a/tests/run-make/share-generics-dylib/rmake.rs b/tests/run-make/share-generics-dylib/rmake.rs
index e0e647fe199..2d52cd43db7 100644
--- a/tests/run-make/share-generics-dylib/rmake.rs
+++ b/tests/run-make/share-generics-dylib/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // This test makes sure all generic instances get re-exported from Rust dylibs for use by
 // `-Zshare-generics`. There are two rlibs (`instance_provider_a` and `instance_provider_b`)
 // which both provide an instance of `Cell<i32>::set`. There is `instance_user_dylib` which is
diff --git a/tests/run-make/short-ice/rmake.rs b/tests/run-make/short-ice/rmake.rs
index 81403931c78..8377954f467 100644
--- a/tests/run-make/short-ice/rmake.rs
+++ b/tests/run-make/short-ice/rmake.rs
@@ -4,6 +4,7 @@
 // was shortened down to an appropriate length.
 // See https://github.com/rust-lang/rust/issues/107910
 
+//@ needs-target-std
 //@ ignore-windows
 // Reason: the assert_eq! on line 32 fails, as error output on Windows is different.
 
diff --git a/tests/run-make/simd-ffi/simd.rs b/tests/run-make/simd-ffi/simd.rs
index 9ea8eb8cf88..1cd961ff87e 100644
--- a/tests/run-make/simd-ffi/simd.rs
+++ b/tests/run-make/simd-ffi/simd.rs
@@ -52,8 +52,14 @@ pub fn bar(a: i32x4, b: i32x4) -> i32x4 {
     unsafe { integer(a, b) }
 }
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-pub trait Sized {}
+pub trait Sized: MetaSized {}
 
 #[lang = "copy"]
 pub trait Copy {}
diff --git a/tests/run-make/stable-symbol-names/rmake.rs b/tests/run-make/stable-symbol-names/rmake.rs
index 402f411c7f5..dacee1a9a3e 100644
--- a/tests/run-make/stable-symbol-names/rmake.rs
+++ b/tests/run-make/stable-symbol-names/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // A typo in rustc caused generic symbol names to be non-deterministic -
 // that is, it was possible to compile the same file twice with no changes
 // and get outputs with different symbol names.
diff --git a/tests/run-make/staticlib-blank-lib/rmake.rs b/tests/run-make/staticlib-blank-lib/rmake.rs
index 11a85d102aa..1ab527b6168 100644
--- a/tests/run-make/staticlib-blank-lib/rmake.rs
+++ b/tests/run-make/staticlib-blank-lib/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // In this test, the static library foo is made blank, which used to cause
 // a compilation error. As the compiler now returns Ok upon encountering a blank
 // staticlib as of #12379, this test checks that compilation is successful despite
diff --git a/tests/run-make/staticlib-broken-bitcode/rmake.rs b/tests/run-make/staticlib-broken-bitcode/rmake.rs
index 17d17c1f0f5..ab406d32176 100644
--- a/tests/run-make/staticlib-broken-bitcode/rmake.rs
+++ b/tests/run-make/staticlib-broken-bitcode/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // Regression test for https://github.com/rust-lang/rust/issues/128955#issuecomment-2657811196
 // which checks that rustc can read an archive containing LLVM bitcode with a
 // newer version from the one rustc links against.
diff --git a/tests/run-make/staticlib-thin-archive/rmake.rs b/tests/run-make/staticlib-thin-archive/rmake.rs
index 955c50da201..1fb56ac0538 100644
--- a/tests/run-make/staticlib-thin-archive/rmake.rs
+++ b/tests/run-make/staticlib-thin-archive/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // Regression test for https://github.com/rust-lang/rust/issues/107407 which
 // checks that rustc can read thin archive. Before the object crate added thin
 // archive support rustc would add emit object files to the staticlib and after
diff --git a/tests/run-make/stdin-rustc/rmake.rs b/tests/run-make/stdin-rustc/rmake.rs
index 2d634dd455e..318d569a760 100644
--- a/tests/run-make/stdin-rustc/rmake.rs
+++ b/tests/run-make/stdin-rustc/rmake.rs
@@ -1,3 +1,4 @@
+//@ needs-target-std
 //! This test checks rustc `-` (stdin) support
 
 use std::path::PathBuf;
diff --git a/tests/run-make/symbol-visibility/rmake.rs b/tests/run-make/symbol-visibility/rmake.rs
index ec936bc3b07..0175158d08b 100644
--- a/tests/run-make/symbol-visibility/rmake.rs
+++ b/tests/run-make/symbol-visibility/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // Dynamic libraries on Rust used to export a very high amount of symbols,
 // going as far as filling the output with mangled names and generic function
 // names. After the rework of #38117, this test checks that no mangled Rust symbols
diff --git a/tests/run-make/symbols-include-type-name/rmake.rs b/tests/run-make/symbols-include-type-name/rmake.rs
index 746c7486bf0..3b46050e662 100644
--- a/tests/run-make/symbols-include-type-name/rmake.rs
+++ b/tests/run-make/symbols-include-type-name/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // Method names used to be obfuscated when exported into symbols,
 // leaving only an obscure `<impl>`. After the fix in #30328,
 // this test checks that method names are successfully saved in the symbol list.
diff --git a/tests/run-make/target-specs/foo.rs b/tests/run-make/target-specs/foo.rs
index 22939e87912..aead76dff87 100644
--- a/tests/run-make/target-specs/foo.rs
+++ b/tests/run-make/target-specs/foo.rs
@@ -4,8 +4,14 @@
 #[lang = "copy"]
 trait Copy {}
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+trait Sized: MetaSized {}
 
 #[lang = "freeze"]
 auto trait Freeze {}
diff --git a/tests/run-make/track-path-dep-info/rmake.rs b/tests/run-make/track-path-dep-info/rmake.rs
index 9b21644c41b..4b98a1b48d5 100644
--- a/tests/run-make/track-path-dep-info/rmake.rs
+++ b/tests/run-make/track-path-dep-info/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // This test checks the functionality of `tracked_path::path`, a procedural macro
 // feature that adds a dependency to another file inside the procmacro. In this case,
 // the text file is added through this method, and the test checks that the compilation
diff --git a/tests/run-make/type-mismatch-same-crate-name/rmake.rs b/tests/run-make/type-mismatch-same-crate-name/rmake.rs
index ecf80d88d51..b095027071f 100644
--- a/tests/run-make/type-mismatch-same-crate-name/rmake.rs
+++ b/tests/run-make/type-mismatch-same-crate-name/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // When a compilation failure deals with seemingly identical types, some helpful
 // errors should be printed.
 // The main use case of this error is when there are two crates
diff --git a/tests/run-make/unknown-mod-stdin/rmake.rs b/tests/run-make/unknown-mod-stdin/rmake.rs
index 6be3119c0fd..101711b0d2c 100644
--- a/tests/run-make/unknown-mod-stdin/rmake.rs
+++ b/tests/run-make/unknown-mod-stdin/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // Rustc displays a compilation error when it finds a `mod` (module)
 // statement referencing a file that does not exist. However, a bug from 2019
 // caused invalid `mod` statements to silently insert empty inline modules
diff --git a/tests/run-make/unstable-feature-usage-metrics-incremental/rmake.rs b/tests/run-make/unstable-feature-usage-metrics-incremental/rmake.rs
index 7e070d80c79..862b2bd5300 100644
--- a/tests/run-make/unstable-feature-usage-metrics-incremental/rmake.rs
+++ b/tests/run-make/unstable-feature-usage-metrics-incremental/rmake.rs
@@ -7,11 +7,11 @@
 //!
 //! # Test history
 //!
-//! - forked from dump-ice-to-disk test, which has flakeyness issues on i686-mingw, I'm assuming
-//! those will be present in this test as well on the same platform
+//! - Forked from `dump-ice-to-disk` test, which previously had backtrace unpredictability on
+//! `i686-pc-windows-gnu`.
 
-//@ ignore-windows
-//FIXME(#128911): still flakey on i686-mingw.
+//@ ignore-cross-compile (exercises metrics incremental on host)
+//@ ignore-i686-pc-windows-gnu (unwind mechanism produces unpredictable backtraces)
 
 use std::path::{Path, PathBuf};
 
@@ -86,9 +86,7 @@ fn test_metrics_errors() {
             .env("RUST_BACKTRACE", "short")
             .arg("-Zmetrics-dir=invaliddirectorythatdefinitelydoesntexist")
             .run_fail()
-            .assert_stderr_contains(
-                "error: cannot dump feature usage metrics: No such file or directory",
-            )
+            .assert_stderr_contains("error: cannot dump feature usage metrics")
             .assert_stdout_not_contains("internal compiler error");
     });
 }
diff --git a/tests/run-make/unstable-feature-usage-metrics/rmake.rs b/tests/run-make/unstable-feature-usage-metrics/rmake.rs
index 2183e28e89a..f987829741c 100644
--- a/tests/run-make/unstable-feature-usage-metrics/rmake.rs
+++ b/tests/run-make/unstable-feature-usage-metrics/rmake.rs
@@ -7,11 +7,10 @@
 //!
 //! # Test history
 //!
-//! - forked from dump-ice-to-disk test, which has flakeyness issues on i686-mingw, I'm assuming
-//! those will be present in this test as well on the same platform
+//! - Forked from `dump-ice-to-disk` test, where `i686-pc-windows-gnu` has unpredictable backtraces.
 
-//@ ignore-windows
-//FIXME(#128911): still flakey on i686-mingw.
+//@ ignore-cross-compile (exercises metrics dump on host)
+//@ ignore-i686-pc-windows-gnu (unwind mechanism produces unpredictable backtraces)
 
 use std::path::{Path, PathBuf};
 
@@ -84,9 +83,7 @@ fn test_metrics_errors() {
             .env("RUST_BACKTRACE", "short")
             .arg("-Zmetrics-dir=invaliddirectorythatdefinitelydoesntexist")
             .run_fail()
-            .assert_stderr_contains(
-                "error: cannot dump feature usage metrics: No such file or directory",
-            )
+            .assert_stderr_contains("error: cannot dump feature usage metrics")
             .assert_stdout_not_contains("internal compiler error");
     });
 }
diff --git a/tests/run-make/use-suggestions-rust-2018/rmake.rs b/tests/run-make/use-suggestions-rust-2018/rmake.rs
index 52c694da75e..4d2163e7cc4 100644
--- a/tests/run-make/use-suggestions-rust-2018/rmake.rs
+++ b/tests/run-make/use-suggestions-rust-2018/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // The compilation error caused by calling on an unimported crate
 // should have a suggestion to write, say, crate::bar::Foo instead
 // of just bar::Foo. However, this suggestion used to only appear for
diff --git a/tests/run-make/used/rmake.rs b/tests/run-make/used/rmake.rs
index 39f36b2eea8..daed69c1b38 100644
--- a/tests/run-make/used/rmake.rs
+++ b/tests/run-make/used/rmake.rs
@@ -1,3 +1,5 @@
+//@ needs-target-std
+//
 // This test ensures that the compiler is keeping static variables, even if not referenced
 // by another part of the program, in the output object file.
 //
diff --git a/tests/rustdoc-gui/globals.goml b/tests/rustdoc-gui/globals.goml
index f8c495ec18a..7a0e2b9eb74 100644
--- a/tests/rustdoc-gui/globals.goml
+++ b/tests/rustdoc-gui/globals.goml
@@ -6,7 +6,6 @@
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html?search=sa'%3Bda'%3Bds"
 wait-for: "#search-tabs"
 assert-window-property-false: {"searchIndex": null}
-assert-window-property: {"srcIndex": null}
 
 // Form input
 go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
@@ -14,11 +13,9 @@ write-into: (".search-input", "Foo")
 press-key: 'Enter'
 wait-for: "#search-tabs"
 assert-window-property-false: {"searchIndex": null}
-assert-window-property: {"srcIndex": null}
 
 // source sidebar
 go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
 click: "#sidebar-button"
 wait-for: "#src-sidebar details"
-assert-window-property-false: {"srcIndex": null}
 assert-window-property: {"searchIndex": null}
diff --git a/tests/rustdoc-json/attrs/inline.rs b/tests/rustdoc-json/attrs/inline.rs
index 74f5f36f03f..b9ea6ab1d10 100644
--- a/tests/rustdoc-json/attrs/inline.rs
+++ b/tests/rustdoc-json/attrs/inline.rs
@@ -1,11 +1,11 @@
-//@ is "$.index[?(@.name=='just_inline')].attrs" '["#[inline]"]'
+//@ is "$.index[?(@.name=='just_inline')].attrs" '["#[attr = Inline(Hint)]"]'
 #[inline]
 pub fn just_inline() {}
 
-//@ is "$.index[?(@.name=='inline_always')].attrs" '["#[inline(always)]"]'
+//@ is "$.index[?(@.name=='inline_always')].attrs" '["#[attr = Inline(Always)]"]'
 #[inline(always)]
 pub fn inline_always() {}
 
-//@ is "$.index[?(@.name=='inline_never')].attrs" '["#[inline(never)]"]'
+//@ is "$.index[?(@.name=='inline_never')].attrs" '["#[attr = Inline(Never)]"]'
 #[inline(never)]
 pub fn inline_never() {}
diff --git a/tests/rustdoc-json/impls/auto.rs b/tests/rustdoc-json/impls/auto.rs
index 5440301f965..104c4891502 100644
--- a/tests/rustdoc-json/impls/auto.rs
+++ b/tests/rustdoc-json/impls/auto.rs
@@ -1,8 +1,14 @@
 #![feature(no_core, auto_traits, lang_items, arbitrary_self_types)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 
 #[lang = "legacy_receiver"]
 pub trait LegacyReceiver {}
@@ -15,8 +21,8 @@ impl Foo {
 }
 
 // Testing spans, so all tests below code
-//@ is "$.index[?(@.docs=='has span')].span.begin" "[13, 1]"
-//@ is "$.index[?(@.docs=='has span')].span.end" "[15, 2]"
+//@ is "$.index[?(@.docs=='has span')].span.begin" "[19, 1]"
+//@ is "$.index[?(@.docs=='has span')].span.end" "[21, 2]"
 //@ is "$.index[?(@.docs=='has span')].inner.impl.is_synthetic" false
 //@ is "$.index[?(@.inner.impl.is_synthetic==true)].span" null
 //@ is "$.index[?(@.inner.impl.is_synthetic==true)].inner.impl.for.resolved_path.path" '"Foo"'
diff --git a/tests/rustdoc-json/primitives/primitive_impls.rs b/tests/rustdoc-json/primitives/primitive_impls.rs
index a1f0ebd11b6..2bdbb868626 100644
--- a/tests/rustdoc-json/primitives/primitive_impls.rs
+++ b/tests/rustdoc-json/primitives/primitive_impls.rs
@@ -6,8 +6,14 @@
 
 //@ set impl_i32 = "$.index[?(@.docs=='Only core can do this')].id"
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 
 /// Only core can do this
 impl i32 {
diff --git a/tests/rustdoc-ui/custom_code_classes_in_docs-warning3.rs b/tests/rustdoc-ui/custom_code_classes_in_docs-warning3.rs
index 18ac37280c0..32ba331527d 100644
--- a/tests/rustdoc-ui/custom_code_classes_in_docs-warning3.rs
+++ b/tests/rustdoc-ui/custom_code_classes_in_docs-warning3.rs
@@ -5,8 +5,14 @@
 #![feature(no_core, lang_items)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 
 /// ```{class="}
 /// main;
diff --git a/tests/rustdoc-ui/custom_code_classes_in_docs-warning3.stderr b/tests/rustdoc-ui/custom_code_classes_in_docs-warning3.stderr
index cc13cc0fe53..fbe3df5d9d3 100644
--- a/tests/rustdoc-ui/custom_code_classes_in_docs-warning3.stderr
+++ b/tests/rustdoc-ui/custom_code_classes_in_docs-warning3.stderr
@@ -1,5 +1,5 @@
 error: unclosed quote string `"`
-  --> $DIR/custom_code_classes_in_docs-warning3.rs:11:1
+  --> $DIR/custom_code_classes_in_docs-warning3.rs:17:1
    |
 LL | / /// ```{class="}
 LL | | /// main;
@@ -17,7 +17,7 @@ LL | #![deny(warnings)]
    = note: `#[deny(rustdoc::invalid_codeblock_attributes)]` implied by `#[deny(warnings)]`
 
 error: unclosed quote string `"`
-  --> $DIR/custom_code_classes_in_docs-warning3.rs:11:1
+  --> $DIR/custom_code_classes_in_docs-warning3.rs:17:1
    |
 LL | / /// ```{class="}
 LL | | /// main;
diff --git a/tests/rustdoc-ui/target-feature-stability.rs b/tests/rustdoc-ui/target-feature-stability.rs
index 17fa3ccfe3e..77512987219 100644
--- a/tests/rustdoc-ui/target-feature-stability.rs
+++ b/tests/rustdoc-ui/target-feature-stability.rs
@@ -14,8 +14,14 @@
 #![feature(arm_target_feature)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-pub trait Sized {}
+pub trait Sized: MetaSized {}
 
 // `fp-armv8` is "forbidden" on aarch64 as we tie it to `neon`.
 #[target_feature(enable = "fp-armv8")]
diff --git a/tests/rustdoc/file-creation-111249.rs b/tests/rustdoc/file-creation-111249.rs
index a6522d682f1..7a075a1583f 100644
--- a/tests/rustdoc/file-creation-111249.rs
+++ b/tests/rustdoc/file-creation-111249.rs
@@ -1,10 +1,20 @@
 // https://github.com/rust-lang/rust/issues/111249
 #![crate_name = "foo"]
 #![feature(no_core)]
+#![feature(lang_items)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
+#[lang = "sized"]
+pub trait Sized: MetaSized {}
+
 //@ files "foo" "['all.html', 'visible', 'index.html', 'sidebar-items.js', 'hidden', \
-//        'struct.Bar.html']"
+//        'struct.Bar.html', 'trait.Sized.html', 'trait.MetaSized.html', 'trait.PointeeSized.html']"
 //@ files "foo/visible" "['trait.Foo.html', 'index.html', 'sidebar-items.js']"
 //@ files "foo/hidden" "['inner']"
 //@ files "foo/hidden/inner" "['trait.Foo.html']"
diff --git a/tests/rustdoc/foreigntype.rs b/tests/rustdoc/foreigntype.rs
index bee3d8e6509..66371e8c827 100644
--- a/tests/rustdoc/foreigntype.rs
+++ b/tests/rustdoc/foreigntype.rs
@@ -10,7 +10,7 @@ impl ExtType {
     pub fn do_something(&self) {}
 }
 
-pub trait Trait {}
+pub trait Trait: std::marker::PointeeSized {}
 
 //@ has foreigntype/trait.Trait.html '//a[@class="foreigntype"]' 'ExtType'
 impl Trait for ExtType {}
diff --git a/tests/rustdoc/intra-doc/auxiliary/my-core.rs b/tests/rustdoc/intra-doc/auxiliary/my-core.rs
index c050929db96..a33b0582b31 100644
--- a/tests/rustdoc/intra-doc/auxiliary/my-core.rs
+++ b/tests/rustdoc/intra-doc/auxiliary/my-core.rs
@@ -13,8 +13,14 @@ impl char {
     }
 }
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-pub trait Sized {}
+pub trait Sized: MetaSized {}
 
 #[lang = "clone"]
 pub trait Clone: Sized {}
diff --git a/tests/rustdoc/intra-doc/extern-type.rs b/tests/rustdoc/intra-doc/extern-type.rs
index 198ac8e43e0..41a678d52cd 100644
--- a/tests/rustdoc/intra-doc/extern-type.rs
+++ b/tests/rustdoc/intra-doc/extern-type.rs
@@ -4,11 +4,11 @@ extern {
     pub type ExternType;
 }
 
-pub trait T {
+pub trait T: std::marker::PointeeSized {
     fn test(&self) {}
 }
 
-pub trait G<N> {
+pub trait G<N>: std::marker::PointeeSized {
     fn g(&self, n: N) {}
 }
 
diff --git a/tests/rustdoc/intra-doc/no-doc-primitive.rs b/tests/rustdoc/intra-doc/no-doc-primitive.rs
index 79825643b98..9ce43e26aa1 100644
--- a/tests/rustdoc/intra-doc/no-doc-primitive.rs
+++ b/tests/rustdoc/intra-doc/no-doc-primitive.rs
@@ -10,8 +10,14 @@
 //@ has no_doc_primitive/index.html
 //! A [`char`] and its [`char::len_utf8`].
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 
 impl char {
     pub fn len_utf8(self) -> usize {
diff --git a/tests/rustdoc/intra-doc/prim-methods-local.rs b/tests/rustdoc/intra-doc/prim-methods-local.rs
index a9e71c58be3..f6aa1ed2156 100644
--- a/tests/rustdoc/intra-doc/prim-methods-local.rs
+++ b/tests/rustdoc/intra-doc/prim-methods-local.rs
@@ -19,8 +19,14 @@ impl char {
     }
 }
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-pub trait Sized {}
+pub trait Sized: MetaSized {}
 
 #[lang = "clone"]
 pub trait Clone: Sized {}
diff --git a/tests/rustdoc/intra-doc/prim-self.rs b/tests/rustdoc/intra-doc/prim-self.rs
index d5bfd570d54..21368fab993 100644
--- a/tests/rustdoc/intra-doc/prim-self.rs
+++ b/tests/rustdoc/intra-doc/prim-self.rs
@@ -37,5 +37,11 @@ impl S {
     pub fn f() {}
 }
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-pub trait Sized {}
+pub trait Sized: MetaSized {}
diff --git a/tests/rustdoc/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs b/tests/rustdoc/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs
index dcdcbfb7ec1..cd4d76baca1 100644
--- a/tests/rustdoc/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs
+++ b/tests/rustdoc/notable-trait/doc-notable_trait_box_is_not_an_iterator.rs
@@ -11,8 +11,14 @@ impl<T> Box<T> {
     }
 }
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 
 #[doc(notable_trait)]
 pub trait FakeIterator {}
diff --git a/tests/rustdoc/primitive/cross-crate-primitive-doc.rs b/tests/rustdoc/primitive/cross-crate-primitive-doc.rs
index 0ffde5b0f2d..3c159d57f13 100644
--- a/tests/rustdoc/primitive/cross-crate-primitive-doc.rs
+++ b/tests/rustdoc/primitive/cross-crate-primitive-doc.rs
@@ -5,8 +5,14 @@
 #![feature(no_core, lang_items)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 
 extern crate primitive_doc;
 
diff --git a/tests/rustdoc/reexport/cfg_doc_reexport.rs b/tests/rustdoc/reexport/cfg_doc_reexport.rs
index 44ec3663284..2c3b3110fb7 100644
--- a/tests/rustdoc/reexport/cfg_doc_reexport.rs
+++ b/tests/rustdoc/reexport/cfg_doc_reexport.rs
@@ -4,8 +4,14 @@
 #![crate_name = "foo"]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 
 //@ has 'foo/index.html'
 //@ has - '//dt/*[@class="stab portability"]' 'foobar'
diff --git a/tests/rustdoc/reexport/reexport-trait-from-hidden-111064-2.rs b/tests/rustdoc/reexport/reexport-trait-from-hidden-111064-2.rs
index 61060b3ff7c..8f0a5806b09 100644
--- a/tests/rustdoc/reexport/reexport-trait-from-hidden-111064-2.rs
+++ b/tests/rustdoc/reexport/reexport-trait-from-hidden-111064-2.rs
@@ -3,11 +3,17 @@
 #![no_core]
 #![crate_name = "foo"]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 
 //@ files "foo" "['sidebar-items.js', 'all.html', 'hidden', 'index.html', 'struct.Bar.html', \
-//        'visible']"
+//        'visible', 'trait.Sized.html', 'trait.MetaSized.html', 'trait.PointeeSized.html']"
 //@ files "foo/hidden" "['inner']"
 //@ files "foo/hidden/inner" "['trait.Foo.html']"
 //@ files "foo/visible" "['index.html', 'sidebar-items.js', 'trait.Foo.html']"
diff --git a/tests/rustdoc/safe-intrinsic.rs b/tests/rustdoc/safe-intrinsic.rs
index 0d2ee89415d..a40116894a8 100644
--- a/tests/rustdoc/safe-intrinsic.rs
+++ b/tests/rustdoc/safe-intrinsic.rs
@@ -5,8 +5,14 @@
 #![no_core]
 #![crate_name = "foo"]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 
 //@ has 'foo/fn.abort.html'
 //@ has - '//pre[@class="rust item-decl"]' 'pub fn abort() -> !'
diff --git a/tests/ui-fulldeps/pprust-expr-roundtrip.rs b/tests/ui-fulldeps/pprust-expr-roundtrip.rs
index f5cfa9e0bcc..8bca20852ad 100644
--- a/tests/ui-fulldeps/pprust-expr-roundtrip.rs
+++ b/tests/ui-fulldeps/pprust-expr-roundtrip.rs
@@ -187,9 +187,9 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) {
 struct RemoveParens;
 
 impl MutVisitor for RemoveParens {
-    fn visit_expr(&mut self, e: &mut P<Expr>) {
+    fn visit_expr(&mut self, e: &mut Expr) {
         match e.kind.clone() {
-            ExprKind::Paren(inner) => *e = inner,
+            ExprKind::Paren(inner) => *e = *inner,
             _ => {}
         };
         mut_visit::walk_expr(self, e);
@@ -200,11 +200,11 @@ impl MutVisitor for RemoveParens {
 struct AddParens;
 
 impl MutVisitor for AddParens {
-    fn visit_expr(&mut self, e: &mut P<Expr>) {
+    fn visit_expr(&mut self, e: &mut Expr) {
         mut_visit::walk_expr(self, e);
         let expr = std::mem::replace(e, Expr::dummy());
 
-        e.kind = ExprKind::Paren(expr);
+        e.kind = ExprKind::Paren(P(expr));
     }
 }
 
diff --git a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs
index 08bed40abe8..90e07bed40e 100644
--- a/tests/ui-fulldeps/pprust-parenthesis-insertion.rs
+++ b/tests/ui-fulldeps/pprust-parenthesis-insertion.rs
@@ -43,7 +43,6 @@ use std::process::ExitCode;
 use parser::parse_expr;
 use rustc_ast::ast::{Expr, ExprKind};
 use rustc_ast::mut_visit::{self, MutVisitor};
-use rustc_ast::ptr::P;
 use rustc_ast_pretty::pprust;
 use rustc_session::parse::ParseSess;
 
@@ -157,7 +156,7 @@ static EXPRS: &[&str] = &[
 struct Unparenthesize;
 
 impl MutVisitor for Unparenthesize {
-    fn visit_expr(&mut self, e: &mut P<Expr>) {
+    fn visit_expr(&mut self, e: &mut Expr) {
         while let ExprKind::Paren(paren) = &mut e.kind {
             *e = mem::replace(paren, Expr::dummy());
         }
diff --git a/tests/ui-fulldeps/stable-mir/check_variant.rs b/tests/ui-fulldeps/stable-mir/check_variant.rs
new file mode 100644
index 00000000000..b0de3369830
--- /dev/null
+++ b/tests/ui-fulldeps/stable-mir/check_variant.rs
@@ -0,0 +1,183 @@
+//@ run-pass
+//! Test that users are able to use stable mir APIs to retrieve
+//! discriminant value and type for AdtDef and Coroutine variants
+
+//@ ignore-stage1
+//@ ignore-cross-compile
+//@ ignore-remote
+//@ edition: 2024
+
+#![feature(rustc_private)]
+#![feature(assert_matches)]
+
+extern crate rustc_middle;
+#[macro_use]
+extern crate rustc_smir;
+extern crate rustc_driver;
+extern crate rustc_interface;
+extern crate stable_mir;
+
+use std::io::Write;
+use std::ops::ControlFlow;
+
+use stable_mir::CrateItem;
+use stable_mir::crate_def::CrateDef;
+use stable_mir::mir::{AggregateKind, Rvalue, Statement, StatementKind};
+use stable_mir::ty::{IntTy, RigidTy, Ty};
+
+const CRATE_NAME: &str = "crate_variant_ty";
+
+/// Test if we can retrieve discriminant info for different types.
+fn test_def_tys() -> ControlFlow<()> {
+    check_adt_mono();
+    check_adt_poly();
+    check_adt_poly2();
+
+    ControlFlow::Continue(())
+}
+
+fn check_adt_mono() {
+    let mono = get_fn("mono").expect_body();
+
+    check_statement_is_aggregate_assign(
+        &mono.blocks[0].statements[0],
+        0,
+        RigidTy::Int(IntTy::Isize),
+    );
+    check_statement_is_aggregate_assign(
+        &mono.blocks[1].statements[0],
+        1,
+        RigidTy::Int(IntTy::Isize),
+    );
+    check_statement_is_aggregate_assign(
+        &mono.blocks[2].statements[0],
+        2,
+        RigidTy::Int(IntTy::Isize),
+    );
+}
+
+fn check_adt_poly() {
+    let poly = get_fn("poly").expect_body();
+
+    check_statement_is_aggregate_assign(
+        &poly.blocks[0].statements[0],
+        0,
+        RigidTy::Int(IntTy::Isize),
+    );
+    check_statement_is_aggregate_assign(
+        &poly.blocks[1].statements[0],
+        1,
+        RigidTy::Int(IntTy::Isize),
+    );
+    check_statement_is_aggregate_assign(
+        &poly.blocks[2].statements[0],
+        2,
+        RigidTy::Int(IntTy::Isize),
+    );
+}
+
+fn check_adt_poly2() {
+    let poly = get_fn("poly2").expect_body();
+
+    check_statement_is_aggregate_assign(
+        &poly.blocks[0].statements[0],
+        0,
+        RigidTy::Int(IntTy::Isize),
+    );
+    check_statement_is_aggregate_assign(
+        &poly.blocks[1].statements[0],
+        1,
+        RigidTy::Int(IntTy::Isize),
+    );
+    check_statement_is_aggregate_assign(
+        &poly.blocks[2].statements[0],
+        2,
+        RigidTy::Int(IntTy::Isize),
+    );
+}
+
+fn get_fn(name: &str) -> CrateItem {
+    stable_mir::all_local_items().into_iter().find(|it| it.name().eq(name)).unwrap()
+}
+
+fn check_statement_is_aggregate_assign(
+    statement: &Statement,
+    expected_discr_val: u128,
+    expected_discr_ty: RigidTy,
+) {
+    if let Statement { kind: StatementKind::Assign(_, rvalue), .. } = statement
+        && let Rvalue::Aggregate(aggregate, _) = rvalue
+        && let AggregateKind::Adt(adt_def, variant_idx, ..) = aggregate
+    {
+        let discr = adt_def.discriminant_for_variant(*variant_idx);
+
+        assert_eq!(discr.val, expected_discr_val);
+        assert_eq!(discr.ty, Ty::from_rigid_kind(expected_discr_ty));
+    } else {
+        unreachable!("Unexpected statement");
+    }
+}
+
+/// This test will generate and analyze a dummy crate using the stable mir.
+/// For that, it will first write the dummy crate into a file.
+/// Then it will create a `StableMir` using custom arguments and then
+/// it will run the compiler.
+fn main() {
+    let path = "defs_ty_input.rs";
+    generate_input(&path).unwrap();
+    let args = &[
+        "rustc".to_string(),
+        "-Cpanic=abort".to_string(),
+        "--crate-name".to_string(),
+        CRATE_NAME.to_string(),
+        path.to_string(),
+    ];
+    run!(args, test_def_tys).unwrap();
+}
+
+fn generate_input(path: &str) -> std::io::Result<()> {
+    let mut file = std::fs::File::create(path)?;
+    write!(
+        file,
+        r#"
+        use std::hint::black_box;
+
+        enum Mono {{
+            A,
+            B(i32),
+            C {{ a: i32, b: u32 }},
+        }}
+
+        enum Poly<T> {{
+            A,
+            B(T),
+            C {{ t: T }},
+        }}
+
+        pub fn main() {{
+            mono();
+            poly();
+            poly2::<i32>(1);
+        }}
+
+        fn mono() {{
+            black_box(Mono::A);
+            black_box(Mono::B(6));
+            black_box(Mono::C {{a: 1, b: 10 }});
+        }}
+
+        fn poly() {{
+            black_box(Poly::<i32>::A);
+            black_box(Poly::B(1i32));
+            black_box(Poly::C {{ t: 1i32 }});
+        }}
+
+        fn poly2<T: Copy>(t: T) {{
+            black_box(Poly::<T>::A);
+            black_box(Poly::B(t));
+            black_box(Poly::C {{ t: t }});
+        }}
+    "#
+    )?;
+    Ok(())
+}
diff --git a/tests/ui/abi/fixed_x18.rs b/tests/ui/abi/fixed_x18.rs
index d64b845e5bd..09d16303033 100644
--- a/tests/ui/abi/fixed_x18.rs
+++ b/tests/ui/abi/fixed_x18.rs
@@ -20,7 +20,11 @@
 #![feature(no_core, lang_items)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+trait PointeeSized {}
+#[lang = "meta_sized"]
+trait MetaSized: PointeeSized {}
 #[lang = "sized"]
-trait Sized {}
+trait Sized: MetaSized {}
 
 //~? ERROR the `-Zfixed-x18` flag is not supported on the `
diff --git a/tests/ui/abi/numbers-arithmetic/float-struct.rs b/tests/ui/abi/numbers-arithmetic/float-struct.rs
new file mode 100644
index 00000000000..a958dc27272
--- /dev/null
+++ b/tests/ui/abi/numbers-arithmetic/float-struct.rs
@@ -0,0 +1,44 @@
+//@ run-pass
+
+use std::fmt::Debug;
+use std::hint::black_box;
+
+#[repr(C)]
+#[derive(Copy, Clone, PartialEq, Debug, Default)]
+struct Regular(f32, f64);
+
+#[repr(C, packed)]
+#[derive(Copy, Clone, PartialEq, Debug, Default)]
+struct Packed(f32, f64);
+
+#[repr(C, align(64))]
+#[derive(Copy, Clone, PartialEq, Debug, Default)]
+struct AlignedF32(f32);
+
+#[repr(C)]
+#[derive(Copy, Clone, PartialEq, Debug, Default)]
+struct Aligned(f64, AlignedF32);
+
+#[inline(never)]
+extern "C" fn read<T: Copy>(x: &T) -> T {
+    *black_box(x)
+}
+
+#[inline(never)]
+extern "C" fn write<T: Copy>(x: T, dest: &mut T) {
+    *dest = black_box(x)
+}
+
+#[track_caller]
+fn check<T: Copy + PartialEq + Debug + Default>(x: T) {
+    assert_eq!(read(&x), x);
+    let mut out = T::default();
+    write(x, &mut out);
+    assert_eq!(out, x);
+}
+
+fn main() {
+    check(Regular(1.0, 2.0));
+    check(Packed(3.0, 4.0));
+    check(Aligned(5.0, AlignedF32(6.0)));
+}
diff --git a/tests/ui/abi/shadow-call-stack-without-fixed-x18.rs b/tests/ui/abi/shadow-call-stack-without-fixed-x18.rs
index 74882fb5c55..b3bd0666ab2 100644
--- a/tests/ui/abi/shadow-call-stack-without-fixed-x18.rs
+++ b/tests/ui/abi/shadow-call-stack-without-fixed-x18.rs
@@ -7,8 +7,14 @@
 #![feature(no_core, lang_items)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+trait PointeeSized {}
+
+#[lang = "meta_sized"]
+trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+trait Sized: MetaSized {}
 
 #[no_mangle]
 pub fn foo() {}
diff --git a/tests/ui/attributes/dump-preds.stderr b/tests/ui/attributes/dump-preds.stderr
index bdfcbed71e9..99139761d7c 100644
--- a/tests/ui/attributes/dump-preds.stderr
+++ b/tests/ui/attributes/dump-preds.stderr
@@ -4,6 +4,7 @@ error: rustc_dump_predicates
 LL | trait Trait<T>: Iterator<Item: Copy>
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: Binder { value: TraitPredicate(<Self as std::marker::MetaSized>, polarity:Positive), bound_vars: [] }
    = note: Binder { value: TraitPredicate(<Self as std::iter::Iterator>, polarity:Positive), bound_vars: [] }
    = note: Binder { value: TraitPredicate(<<Self as std::iter::Iterator>::Item as std::marker::Copy>, polarity:Positive), bound_vars: [] }
    = note: Binder { value: TraitPredicate(<T as std::marker::Sized>, polarity:Positive), bound_vars: [] }
@@ -16,6 +17,7 @@ error: rustc_dump_predicates
 LL |     type Assoc<P: Eq>: std::ops::Deref<Target = ()>
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = note: Binder { value: TraitPredicate(<Self as std::marker::MetaSized>, polarity:Positive), bound_vars: [] }
    = note: Binder { value: TraitPredicate(<Self as std::iter::Iterator>, polarity:Positive), bound_vars: [] }
    = note: Binder { value: TraitPredicate(<<Self as std::iter::Iterator>::Item as std::marker::Copy>, polarity:Positive), bound_vars: [] }
    = note: Binder { value: TraitPredicate(<T as std::marker::Sized>, polarity:Positive), bound_vars: [] }
diff --git a/tests/ui/attributes/export/lang-item.rs b/tests/ui/attributes/export/lang-item.rs
index b923b41a957..92ca1d742e1 100644
--- a/tests/ui/attributes/export/lang-item.rs
+++ b/tests/ui/attributes/export/lang-item.rs
@@ -3,6 +3,14 @@
 #![crate_type = "sdylib"]
 #![no_core]
 
+#[lang = "pointee_sized"]
+//~^ ERROR lang items are not allowed in stable dylibs
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+//~^ ERROR lang items are not allowed in stable dylibs
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
 //~^ ERROR lang items are not allowed in stable dylibs
 trait Sized {}
diff --git a/tests/ui/attributes/export/lang-item.stderr b/tests/ui/attributes/export/lang-item.stderr
index 8c0741bdb6f..211c0b9b07b 100644
--- a/tests/ui/attributes/export/lang-item.stderr
+++ b/tests/ui/attributes/export/lang-item.stderr
@@ -1,8 +1,20 @@
 error: lang items are not allowed in stable dylibs
   --> $DIR/lang-item.rs:6:1
    |
+LL | #[lang = "pointee_sized"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: lang items are not allowed in stable dylibs
+  --> $DIR/lang-item.rs:10:1
+   |
+LL | #[lang = "meta_sized"]
+   | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: lang items are not allowed in stable dylibs
+  --> $DIR/lang-item.rs:14:1
+   |
 LL | #[lang = "sized"]
    | ^^^^^^^^^^^^^^^^^
 
-error: aborting due to 1 previous error
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/attributes/multiple-invalid.stderr b/tests/ui/attributes/multiple-invalid.stderr
index a8dba0ba37d..f4f7dd7c4f1 100644
--- a/tests/ui/attributes/multiple-invalid.stderr
+++ b/tests/ui/attributes/multiple-invalid.stderr
@@ -1,12 +1,3 @@
-error[E0518]: attribute should be applied to function or closure
-  --> $DIR/multiple-invalid.rs:4:1
-   |
-LL | #[inline]
-   | ^^^^^^^^^
-...
-LL | const FOO: u8 = 0;
-   | ------------------ not a function or closure
-
 error: attribute should be applied to a function definition
   --> $DIR/multiple-invalid.rs:6:1
    |
@@ -16,6 +7,15 @@ LL |
 LL | const FOO: u8 = 0;
    | ------------------ not a function definition
 
+error[E0518]: attribute should be applied to function or closure
+  --> $DIR/multiple-invalid.rs:4:1
+   |
+LL | #[inline]
+   | ^^^^^^^^^
+...
+LL | const FOO: u8 = 0;
+   | ------------------ not a function or closure
+
 error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0518`.
diff --git a/tests/ui/attributes/rustc_confusables.rs b/tests/ui/attributes/rustc_confusables.rs
index 93d9a7d572c..a8095936cff 100644
--- a/tests/ui/attributes/rustc_confusables.rs
+++ b/tests/ui/attributes/rustc_confusables.rs
@@ -37,8 +37,8 @@ impl Bar {
     fn qux() {}
 
     #[rustc_confusables(invalid_meta_item)]
-    //~^ ERROR expected a quoted string literal
-    //~| HELP consider surrounding this with quotes
+    //~^ ERROR malformed `rustc_confusables` attribute input [E0539]
+    //~| HELP must be of the form
     fn quux() {}
 }
 
diff --git a/tests/ui/attributes/rustc_confusables.stderr b/tests/ui/attributes/rustc_confusables.stderr
index aba384ff8ac..3ed4efeb4db 100644
--- a/tests/ui/attributes/rustc_confusables.stderr
+++ b/tests/ui/attributes/rustc_confusables.stderr
@@ -1,25 +1,26 @@
-error: malformed `rustc_confusables` attribute input
-  --> $DIR/rustc_confusables.rs:34:5
-   |
-LL |     #[rustc_confusables]
-   |     ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]`
-
 error: expected at least one confusable name
   --> $DIR/rustc_confusables.rs:30:5
    |
 LL |     #[rustc_confusables()]
    |     ^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0539]: expected a quoted string literal
-  --> $DIR/rustc_confusables.rs:39:25
-   |
-LL |     #[rustc_confusables(invalid_meta_item)]
-   |                         ^^^^^^^^^^^^^^^^^
+error[E0539]: malformed `rustc_confusables` attribute input
+  --> $DIR/rustc_confusables.rs:34:5
    |
-help: consider surrounding this with quotes
+LL |     #[rustc_confusables]
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |     |
+   |     expected this to be a list
+   |     help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]`
+
+error[E0539]: malformed `rustc_confusables` attribute input
+  --> $DIR/rustc_confusables.rs:39:5
    |
-LL |     #[rustc_confusables("invalid_meta_item")]
-   |                         +                 +
+LL |     #[rustc_confusables(invalid_meta_item)]
+   |     ^^^^^^^^^^^^^^^^^^^^-----------------^^
+   |     |                   |
+   |     |                   expected a string literal here
+   |     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
diff --git a/tests/ui/borrowck/span-semicolon-issue-139049.fixed b/tests/ui/borrowck/span-semicolon-issue-139049.fixed
index 0b263b22296..c01d1242dd7 100644
--- a/tests/ui/borrowck/span-semicolon-issue-139049.fixed
+++ b/tests/ui/borrowck/span-semicolon-issue-139049.fixed
@@ -1,52 +1,25 @@
-// Make sure the generated suggestion suggest editing the user
-// code instead of the std macro implementation
+// Make sure the generated suggestion suggest editing the user code instead of
+// the macro implementation (which might come from an external crate).
+// issue: <https://github.com/rust-lang/rust/issues/139049>
 
 //@ run-rustfix
 
 #![allow(dead_code)]
 
-use std::fmt::{self, Display};
-
-struct Mutex;
-
-impl Mutex {
-    fn lock(&self) -> MutexGuard<'_> {
-        MutexGuard(self)
-    }
-}
-
-struct MutexGuard<'a>(&'a Mutex);
-
-impl<'a> Drop for MutexGuard<'a> {
-    fn drop(&mut self) {}
-}
-
-struct Out;
-
-impl Out {
-    fn write_fmt(&self, _args: fmt::Arguments) {}
-}
-
-impl<'a> Display for MutexGuard<'a> {
-    fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
-        Ok(())
-    }
-}
+// You could assume that this comes from an extern crate (it doesn't
+// because an aux crate would be overkill for this test).
+macro_rules! perform { ($e:expr) => { D(&$e).end() } }
+//~^ ERROR does not live long enough
+//~| ERROR does not live long enough
 
 fn main() {
-    let _write = {
-        let mutex = Mutex;
-        write!(Out, "{}", mutex.lock());
-        //~^ ERROR `mutex` does not live long enough
-        //~| SUGGESTION ;
-    };
-
-    let _write = {
-        use std::io::Write as _;
+    { let l = (); perform!(l); };
+    //~^ SUGGESTION ;
 
-        let mutex = Mutex;
-        let x = write!(std::io::stdout(), "{}", mutex.lock()); x
-        //~^ ERROR `mutex` does not live long enough
-        //~| SUGGESTION let x
-    };
+    let _x = { let l = (); let x = perform!(l); x };
+    //~^ SUGGESTION let x
 }
+
+struct D<T>(T);
+impl<T> Drop for D<T> { fn drop(&mut self) {} }
+impl<T> D<T> { fn end(&self) -> String { String::new() } }
diff --git a/tests/ui/borrowck/span-semicolon-issue-139049.rs b/tests/ui/borrowck/span-semicolon-issue-139049.rs
index a92742ac94b..43558756c71 100644
--- a/tests/ui/borrowck/span-semicolon-issue-139049.rs
+++ b/tests/ui/borrowck/span-semicolon-issue-139049.rs
@@ -1,52 +1,25 @@
-// Make sure the generated suggestion suggest editing the user
-// code instead of the std macro implementation
+// Make sure the generated suggestion suggest editing the user code instead of
+// the macro implementation (which might come from an external crate).
+// issue: <https://github.com/rust-lang/rust/issues/139049>
 
 //@ run-rustfix
 
 #![allow(dead_code)]
 
-use std::fmt::{self, Display};
-
-struct Mutex;
-
-impl Mutex {
-    fn lock(&self) -> MutexGuard<'_> {
-        MutexGuard(self)
-    }
-}
-
-struct MutexGuard<'a>(&'a Mutex);
-
-impl<'a> Drop for MutexGuard<'a> {
-    fn drop(&mut self) {}
-}
-
-struct Out;
-
-impl Out {
-    fn write_fmt(&self, _args: fmt::Arguments) {}
-}
-
-impl<'a> Display for MutexGuard<'a> {
-    fn fmt(&self, _formatter: &mut fmt::Formatter) -> fmt::Result {
-        Ok(())
-    }
-}
+// You could assume that this comes from an extern crate (it doesn't
+// because an aux crate would be overkill for this test).
+macro_rules! perform { ($e:expr) => { D(&$e).end() } }
+//~^ ERROR does not live long enough
+//~| ERROR does not live long enough
 
 fn main() {
-    let _write = {
-        let mutex = Mutex;
-        write!(Out, "{}", mutex.lock())
-        //~^ ERROR `mutex` does not live long enough
-        //~| SUGGESTION ;
-    };
-
-    let _write = {
-        use std::io::Write as _;
+    { let l = (); perform!(l) };
+    //~^ SUGGESTION ;
 
-        let mutex = Mutex;
-        write!(std::io::stdout(), "{}", mutex.lock())
-        //~^ ERROR `mutex` does not live long enough
-        //~| SUGGESTION let x
-    };
+    let _x = { let l = (); perform!(l) };
+    //~^ SUGGESTION let x
 }
+
+struct D<T>(T);
+impl<T> Drop for D<T> { fn drop(&mut self) {} }
+impl<T> D<T> { fn end(&self) -> String { String::new() } }
diff --git a/tests/ui/borrowck/span-semicolon-issue-139049.stderr b/tests/ui/borrowck/span-semicolon-issue-139049.stderr
index 123bdf4bc67..8d2de67382b 100644
--- a/tests/ui/borrowck/span-semicolon-issue-139049.stderr
+++ b/tests/ui/borrowck/span-semicolon-issue-139049.stderr
@@ -1,46 +1,48 @@
-error[E0597]: `mutex` does not live long enough
-  --> $DIR/span-semicolon-issue-139049.rs:39:27
+error[E0597]: `l` does not live long enough
+  --> $DIR/span-semicolon-issue-139049.rs:11:41
    |
-LL |         let mutex = Mutex;
-   |             ----- binding `mutex` declared here
-LL |         write!(Out, "{}", mutex.lock())
-   |                           ^^^^^-------
-   |                           |
-   |                           borrowed value does not live long enough
-   |                           a temporary with access to the borrow is created here ...
+LL | macro_rules! perform { ($e:expr) => { D(&$e).end() } }
+   |                                       --^^^-
+   |                                       | |
+   |                                       | borrowed value does not live long enough
+   |                                       a temporary with access to the borrow is created here ...
 ...
-LL |     };
-   |     -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MutexGuard`
-   |     |
-   |     `mutex` dropped here while still borrowed
+LL |     { let l = (); perform!(l) };
+   |           -       ----------- -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+   |           |       |           |
+   |           |       |           `l` dropped here while still borrowed
+   |           |       in this macro invocation
+   |           binding `l` declared here
    |
+   = note: this error originates in the macro `perform` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
    |
-LL |         write!(Out, "{}", mutex.lock());
-   |                                        +
+LL |     { let l = (); perform!(l); };
+   |                              +
 
-error[E0597]: `mutex` does not live long enough
-  --> $DIR/span-semicolon-issue-139049.rs:48:41
+error[E0597]: `l` does not live long enough
+  --> $DIR/span-semicolon-issue-139049.rs:11:41
    |
-LL |         let mutex = Mutex;
-   |             ----- binding `mutex` declared here
-LL |         write!(std::io::stdout(), "{}", mutex.lock())
-   |                                         ^^^^^-------
-   |                                         |
-   |                                         borrowed value does not live long enough
-   |                                         a temporary with access to the borrow is created here ...
+LL | macro_rules! perform { ($e:expr) => { D(&$e).end() } }
+   |                                       --^^^-
+   |                                       | |
+   |                                       | borrowed value does not live long enough
+   |                                       a temporary with access to the borrow is created here ...
 ...
-LL |     };
-   |     -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `MutexGuard`
-   |     |
-   |     `mutex` dropped here while still borrowed
+LL |     let _x = { let l = (); perform!(l) };
+   |                    -       ----------- -- ... and the borrow might be used here, when that temporary is dropped and runs the `Drop` code for type `D`
+   |                    |       |           |
+   |                    |       |           `l` dropped here while still borrowed
+   |                    |       in this macro invocation
+   |                    binding `l` declared here
    |
    = note: the temporary is part of an expression at the end of a block;
            consider forcing this temporary to be dropped sooner, before the block's local variables are dropped
+   = note: this error originates in the macro `perform` (in Nightly builds, run with -Z macro-backtrace for more info)
 help: for example, you could save the expression's value in a new local variable `x` and then make `x` be the expression at the end of the block
    |
-LL |         let x = write!(std::io::stdout(), "{}", mutex.lock()); x
-   |         +++++++                                              +++
+LL |     let _x = { let l = (); let x = perform!(l); x };
+   |                            +++++++            +++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/codegen/mismatched-data-layouts.rs b/tests/ui/codegen/mismatched-data-layouts.rs
index 194bcaa307f..6428b8c5247 100644
--- a/tests/ui/codegen/mismatched-data-layouts.rs
+++ b/tests/ui/codegen/mismatched-data-layouts.rs
@@ -9,7 +9,13 @@
 #![feature(lang_items, no_core, auto_traits)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 
 //~? ERROR differs from LLVM target's
diff --git a/tests/ui/const-generics/unused-type-param-suggestion.rs b/tests/ui/const-generics/unused-type-param-suggestion.rs
index fb0ccb4fdcd..b8ae4f6b56b 100644
--- a/tests/ui/const-generics/unused-type-param-suggestion.rs
+++ b/tests/ui/const-generics/unused-type-param-suggestion.rs
@@ -25,3 +25,4 @@ type C<N: Sized> = ();
 type D<N: ?Sized> = ();
 //~^ ERROR type parameter `N` is never used
 //~| HELP consider removing `N`
+//~| HELP if you intended `N` to be a const parameter
diff --git a/tests/ui/const-generics/unused-type-param-suggestion.stderr b/tests/ui/const-generics/unused-type-param-suggestion.stderr
index 67b704d8bc7..a7aa477ab31 100644
--- a/tests/ui/const-generics/unused-type-param-suggestion.stderr
+++ b/tests/ui/const-generics/unused-type-param-suggestion.stderr
@@ -47,6 +47,7 @@ LL | type D<N: ?Sized> = ();
    |        ^ unused type parameter
    |
    = help: consider removing `N` or referring to it in the body of the type alias
+   = help: if you intended `N` to be a const parameter, use `const N: /* Type */` instead
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs
index 423ff37baef..2372d1c3e3d 100644
--- a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs
+++ b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.rs
@@ -7,7 +7,9 @@ extern "C" {
     type Opaque;
 }
 
-const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) }; //~ ERROR layout
-const _ALIGN: usize = unsafe { align_of_val(&4 as *const i32 as *const Opaque) }; //~ ERROR layout
+const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) };
+//~^ ERROR the size for values of type `Opaque` cannot be known
+const _ALIGN: usize = unsafe { align_of_val(&4 as *const i32 as *const Opaque) };
+//~^ ERROR the size for values of type `Opaque` cannot be known
 
 fn main() {}
diff --git a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr
index c78626bdefc..6d6bc157771 100644
--- a/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr
+++ b/tests/ui/consts/const-size_of_val-align_of_val-extern-type.stderr
@@ -1,15 +1,27 @@
-error[E0080]: `extern type` does not have known layout
-  --> $DIR/const-size_of_val-align_of_val-extern-type.rs:10:31
+error[E0277]: the size for values of type `Opaque` cannot be known
+  --> $DIR/const-size_of_val-align_of_val-extern-type.rs:10:43
    |
 LL | const _SIZE: usize = unsafe { size_of_val(&4 as *const i32 as *const Opaque) };
-   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_SIZE` failed here
+   |                               ----------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a known size
+   |                               |
+   |                               required by a bound introduced by this call
+   |
+   = help: the trait `MetaSized` is not implemented for `Opaque`
+note: required by a bound in `std::intrinsics::size_of_val`
+  --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL
 
-error[E0080]: `extern type` does not have known layout
-  --> $DIR/const-size_of_val-align_of_val-extern-type.rs:11:32
+error[E0277]: the size for values of type `Opaque` cannot be known
+  --> $DIR/const-size_of_val-align_of_val-extern-type.rs:12:45
    |
 LL | const _ALIGN: usize = unsafe { align_of_val(&4 as *const i32 as *const Opaque) };
-   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `_ALIGN` failed here
+   |                                ------------ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a known size
+   |                                |
+   |                                required by a bound introduced by this call
+   |
+   = help: the trait `MetaSized` is not implemented for `Opaque`
+note: required by a bound in `std::intrinsics::align_of_val`
+  --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0080`.
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/debuginfo/dwarf-versions.rs b/tests/ui/debuginfo/dwarf-versions.rs
index 8f731f10ead..ccf33542960 100644
--- a/tests/ui/debuginfo/dwarf-versions.rs
+++ b/tests/ui/debuginfo/dwarf-versions.rs
@@ -29,8 +29,14 @@
 #![no_core]
 #![no_std]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-pub trait Sized {}
+pub trait Sized: MetaSized {}
 
 pub fn foo() {}
 
diff --git a/tests/ui/deprecation/deprecation-sanity.rs b/tests/ui/deprecation/deprecation-sanity.rs
index d5b149b18ed..80198ab8196 100644
--- a/tests/ui/deprecation/deprecation-sanity.rs
+++ b/tests/ui/deprecation/deprecation-sanity.rs
@@ -4,22 +4,22 @@ mod bogus_attribute_types_1 {
     #[deprecated(since = "a", note = "a", reason)] //~ ERROR unknown meta item 'reason'
     fn f1() { }
 
-    #[deprecated(since = "a", note)] //~ ERROR expected a quoted string literal
+    #[deprecated(since = "a", note)] //~ ERROR malformed `deprecated` attribute input [E0539]
     fn f2() { }
 
-    #[deprecated(since, note = "a")] //~ ERROR expected a quoted string literal
+    #[deprecated(since, note = "a")] //~ ERROR malformed `deprecated` attribute input [E0539]
     fn f3() { }
 
-    #[deprecated(since = "a", note(b))] //~ ERROR expected a quoted string literal
+    #[deprecated(since = "a", note(b))] //~ ERROR malformed `deprecated` attribute input [E0539]
     fn f5() { }
 
-    #[deprecated(since(b), note = "a")] //~ ERROR expected a quoted string literal
+    #[deprecated(since(b), note = "a")] //~ ERROR malformed `deprecated` attribute input [E0539]
     fn f6() { }
 
-    #[deprecated(note = b"test")] //~ ERROR literal in `deprecated` value must be a string
+    #[deprecated(note = b"test")] //~ ERROR malformed `deprecated` attribute input [E0539]
     fn f7() { }
 
-    #[deprecated("test")] //~ ERROR item in `deprecated` must be a key/value pair
+    #[deprecated("test")] //~ ERROR malformed `deprecated` attribute input [E0565]
     fn f8() { }
 }
 
@@ -27,7 +27,7 @@ mod bogus_attribute_types_1 {
 #[deprecated(since = "a", note = "b")] //~ ERROR multiple `deprecated` attributes
 fn multiple1() { }
 
-#[deprecated(since = "a", since = "b", note = "c")] //~ ERROR multiple 'since' items
+#[deprecated(since = "a", since = "b", note = "c")] //~ ERROR malformed `deprecated` attribute input [E0538]
 fn f1() { }
 
 struct X;
diff --git a/tests/ui/deprecation/deprecation-sanity.stderr b/tests/ui/deprecation/deprecation-sanity.stderr
index 53047d40cb2..f1b4697485c 100644
--- a/tests/ui/deprecation/deprecation-sanity.stderr
+++ b/tests/ui/deprecation/deprecation-sanity.stderr
@@ -4,43 +4,115 @@ error[E0541]: unknown meta item 'reason'
 LL |     #[deprecated(since = "a", note = "a", reason)]
    |                                           ^^^^^^ expected one of `since`, `note`
 
-error[E0539]: expected a quoted string literal
-  --> $DIR/deprecation-sanity.rs:7:31
+error[E0539]: malformed `deprecated` attribute input
+  --> $DIR/deprecation-sanity.rs:7:5
    |
 LL |     #[deprecated(since = "a", note)]
-   |                               ^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^----^^
+   |                               |
+   |                               expected this to be of the form `note = "..."`
+   |
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL -     #[deprecated(since = "a", note)]
+LL +     #[deprecated = "reason"]
+   |
+LL -     #[deprecated(since = "a", note)]
+LL +     #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")]
+   |
+LL -     #[deprecated(since = "a", note)]
+LL +     #[deprecated]
+   |
 
-error[E0539]: expected a quoted string literal
-  --> $DIR/deprecation-sanity.rs:10:18
+error[E0539]: malformed `deprecated` attribute input
+  --> $DIR/deprecation-sanity.rs:10:5
    |
 LL |     #[deprecated(since, note = "a")]
-   |                  ^^^^^
+   |     ^^^^^^^^^^^^^-----^^^^^^^^^^^^^^
+   |                  |
+   |                  expected this to be of the form `since = "..."`
+   |
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL -     #[deprecated(since, note = "a")]
+LL +     #[deprecated = "reason"]
+   |
+LL -     #[deprecated(since, note = "a")]
+LL +     #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")]
+   |
+LL -     #[deprecated(since, note = "a")]
+LL +     #[deprecated]
+   |
 
-error[E0539]: expected a quoted string literal
-  --> $DIR/deprecation-sanity.rs:13:31
+error[E0539]: malformed `deprecated` attribute input
+  --> $DIR/deprecation-sanity.rs:13:5
    |
 LL |     #[deprecated(since = "a", note(b))]
-   |                               ^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^-------^^
+   |                               |
+   |                               expected this to be of the form `note = "..."`
+   |
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL -     #[deprecated(since = "a", note(b))]
+LL +     #[deprecated = "reason"]
+   |
+LL -     #[deprecated(since = "a", note(b))]
+LL +     #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")]
+   |
+LL -     #[deprecated(since = "a", note(b))]
+LL +     #[deprecated]
+   |
 
-error[E0539]: expected a quoted string literal
-  --> $DIR/deprecation-sanity.rs:16:18
+error[E0539]: malformed `deprecated` attribute input
+  --> $DIR/deprecation-sanity.rs:16:5
    |
 LL |     #[deprecated(since(b), note = "a")]
-   |                  ^^^^^^^^
+   |     ^^^^^^^^^^^^^--------^^^^^^^^^^^^^^
+   |                  |
+   |                  expected this to be of the form `since = "..."`
+   |
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL -     #[deprecated(since(b), note = "a")]
+LL +     #[deprecated = "reason"]
+   |
+LL -     #[deprecated(since(b), note = "a")]
+LL +     #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")]
+   |
+LL -     #[deprecated(since(b), note = "a")]
+LL +     #[deprecated]
+   |
 
-error[E0565]: literal in `deprecated` value must be a string
-  --> $DIR/deprecation-sanity.rs:19:25
+error[E0539]: malformed `deprecated` attribute input
+  --> $DIR/deprecation-sanity.rs:19:5
    |
 LL |     #[deprecated(note = b"test")]
-   |                         -^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^-^^^^^^^^
    |                         |
    |                         help: consider removing the prefix
+   |
+   = note: expected a normal string literal, not a byte string literal
 
-error[E0565]: item in `deprecated` must be a key/value pair
-  --> $DIR/deprecation-sanity.rs:22:18
+error[E0565]: malformed `deprecated` attribute input
+  --> $DIR/deprecation-sanity.rs:22:5
    |
 LL |     #[deprecated("test")]
-   |                  ^^^^^^
+   |     ^^^^^^^^^^^^^------^^
+   |                  |
+   |                  didn't expect a literal here
+   |
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL -     #[deprecated("test")]
+LL +     #[deprecated = "reason"]
+   |
+LL -     #[deprecated("test")]
+LL +     #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")]
+   |
+LL -     #[deprecated("test")]
+LL +     #[deprecated]
+   |
 
 error: multiple `deprecated` attributes
   --> $DIR/deprecation-sanity.rs:27:1
@@ -54,11 +126,25 @@ note: attribute also specified here
 LL | #[deprecated(since = "a", note = "b")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error[E0538]: multiple 'since' items
-  --> $DIR/deprecation-sanity.rs:30:27
+error[E0538]: malformed `deprecated` attribute input
+  --> $DIR/deprecation-sanity.rs:30:1
    |
 LL | #[deprecated(since = "a", since = "b", note = "c")]
-   |                           ^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^-----------^^^^^^^^^^^^^^
+   |                           |
+   |                           found `since` used as a key more than once
+   |
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[deprecated(since = "a", since = "b", note = "c")]
+LL + #[deprecated = "reason"]
+   |
+LL - #[deprecated(since = "a", since = "b", note = "c")]
+LL + #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")]
+   |
+LL - #[deprecated(since = "a", since = "b", note = "c")]
+LL + #[deprecated]
+   |
 
 error: this `#[deprecated]` annotation has no effect
   --> $DIR/deprecation-sanity.rs:35:1
diff --git a/tests/ui/deprecation/invalid-literal.stderr b/tests/ui/deprecation/invalid-literal.stderr
index cbe1fcca023..6f25aebc315 100644
--- a/tests/ui/deprecation/invalid-literal.stderr
+++ b/tests/ui/deprecation/invalid-literal.stderr
@@ -1,20 +1,13 @@
-error: malformed `deprecated` attribute input
+error[E0539]: malformed `deprecated` attribute input
   --> $DIR/invalid-literal.rs:1:1
    |
 LL | #[deprecated = b"test"]
-   | ^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: the following are the possible correct uses
-   |
-LL - #[deprecated = b"test"]
-LL + #[deprecated = "reason"]
-   |
-LL - #[deprecated = b"test"]
-LL + #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")]
-   |
-LL - #[deprecated = b"test"]
-LL + #[deprecated]
+   | ^^^^^^^^^^^^^^^-^^^^^^^
+   |                |
+   |                help: consider removing the prefix
    |
+   = note: expected a normal string literal, not a byte string literal
 
 error: aborting due to 1 previous error
 
+For more information about this error, try `rustc --explain E0539`.
diff --git a/tests/ui/error-codes/E0534.rs b/tests/ui/error-codes/E0534.rs
deleted file mode 100644
index a4242499419..00000000000
--- a/tests/ui/error-codes/E0534.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-#[inline()] //~ ERROR E0534
-pub fn something() {}
-
-fn main() {
-    something();
-}
diff --git a/tests/ui/error-codes/E0534.stderr b/tests/ui/error-codes/E0534.stderr
deleted file mode 100644
index 6983de7ab69..00000000000
--- a/tests/ui/error-codes/E0534.stderr
+++ /dev/null
@@ -1,9 +0,0 @@
-error[E0534]: expected one argument
-  --> $DIR/E0534.rs:1:1
-   |
-LL | #[inline()]
-   | ^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0534`.
diff --git a/tests/ui/error-codes/E0565-2.rs b/tests/ui/error-codes/E0539.rs
index 0319ecb11f9..0e2c537f473 100644
--- a/tests/ui/error-codes/E0565-2.rs
+++ b/tests/ui/error-codes/E0539.rs
@@ -1,5 +1,5 @@
 // repr currently doesn't support literals
-#[deprecated(since = b"1.29", note = "hi")] //~ ERROR E0565
+#[deprecated(since = b"1.29", note = "hi")] //~ ERROR E0539
 struct A {  }
 
 fn main() {  }
diff --git a/tests/ui/error-codes/E0539.stderr b/tests/ui/error-codes/E0539.stderr
new file mode 100644
index 00000000000..18ed1c23b40
--- /dev/null
+++ b/tests/ui/error-codes/E0539.stderr
@@ -0,0 +1,13 @@
+error[E0539]: malformed `deprecated` attribute input
+  --> $DIR/E0539.rs:2:1
+   |
+LL | #[deprecated(since = b"1.29", note = "hi")]
+   | ^^^^^^^^^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^^
+   |                      |
+   |                      help: consider removing the prefix
+   |
+   = note: expected a normal string literal, not a byte string literal
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0539`.
diff --git a/tests/ui/error-codes/E0540.rs b/tests/ui/error-codes/E0540.rs
new file mode 100644
index 00000000000..db29e6801f5
--- /dev/null
+++ b/tests/ui/error-codes/E0540.rs
@@ -0,0 +1,6 @@
+#[inline()] //~ ERROR malformed `inline` attribute input
+pub fn something() {}
+
+fn main() {
+    something();
+}
diff --git a/tests/ui/error-codes/E0540.stderr b/tests/ui/error-codes/E0540.stderr
new file mode 100644
index 00000000000..3e5f408feb5
--- /dev/null
+++ b/tests/ui/error-codes/E0540.stderr
@@ -0,0 +1,19 @@
+error[E0805]: malformed `inline` attribute input
+  --> $DIR/E0540.rs:1:1
+   |
+LL | #[inline()]
+   | ^^^^^^^^--^
+   |         |
+   |         expected a single argument here
+   |
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL | #[inline(always|never)]
+   |          ++++++++++++
+LL - #[inline()]
+LL + #[inline]
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0805`.
diff --git a/tests/ui/error-codes/E0565-1.stderr b/tests/ui/error-codes/E0565-1.stderr
index 806eed2a632..6277e6400d7 100644
--- a/tests/ui/error-codes/E0565-1.stderr
+++ b/tests/ui/error-codes/E0565-1.stderr
@@ -1,8 +1,22 @@
-error[E0565]: item in `deprecated` must be a key/value pair
-  --> $DIR/E0565-1.rs:2:14
+error[E0565]: malformed `deprecated` attribute input
+  --> $DIR/E0565-1.rs:2:1
    |
 LL | #[deprecated("since")]
-   |              ^^^^^^^
+   | ^^^^^^^^^^^^^-------^^
+   |              |
+   |              didn't expect a literal here
+   |
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[deprecated("since")]
+LL + #[deprecated = "reason"]
+   |
+LL - #[deprecated("since")]
+LL + #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")]
+   |
+LL - #[deprecated("since")]
+LL + #[deprecated]
+   |
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/error-codes/E0565-2.stderr b/tests/ui/error-codes/E0565-2.stderr
deleted file mode 100644
index 42199351c3d..00000000000
--- a/tests/ui/error-codes/E0565-2.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0565]: literal in `deprecated` value must be a string
-  --> $DIR/E0565-2.rs:2:22
-   |
-LL | #[deprecated(since = b"1.29", note = "hi")]
-   |                      -^^^^^^
-   |                      |
-   |                      help: consider removing the prefix
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0565`.
diff --git a/tests/ui/extern/extern-type-diag-not-similar.rs b/tests/ui/extern/extern-type-diag-not-similar.rs
index cd3eec9f1f7..21a2a20a644 100644
--- a/tests/ui/extern/extern-type-diag-not-similar.rs
+++ b/tests/ui/extern/extern-type-diag-not-similar.rs
@@ -3,7 +3,10 @@
 // Two extern types shouldn't really be considered similar just
 // because they are both extern types.
 
-#![feature(extern_types)]
+#![feature(extern_types, sized_hierarchy)]
+
+use std::marker::PointeeSized;
+
 extern "C" {
     type ShouldNotBeMentioned;
 }
@@ -14,7 +17,7 @@ extern "C" {
 
 unsafe impl Send for ShouldNotBeMentioned {}
 
-fn assert_send<T: Send + ?Sized>() {}
+fn assert_send<T: Send + PointeeSized>() {}
 
 fn main() {
     assert_send::<Foo>()
diff --git a/tests/ui/extern/extern-type-diag-not-similar.stderr b/tests/ui/extern/extern-type-diag-not-similar.stderr
index 3547f9b3ff6..f85ff1eead6 100644
--- a/tests/ui/extern/extern-type-diag-not-similar.stderr
+++ b/tests/ui/extern/extern-type-diag-not-similar.stderr
@@ -1,14 +1,14 @@
 error[E0277]: `Foo` cannot be sent between threads safely
-  --> $DIR/extern-type-diag-not-similar.rs:20:19
+  --> $DIR/extern-type-diag-not-similar.rs:23:19
    |
 LL |     assert_send::<Foo>()
    |                   ^^^ `Foo` cannot be sent between threads safely
    |
    = help: the trait `Send` is not implemented for `Foo`
 note: required by a bound in `assert_send`
-  --> $DIR/extern-type-diag-not-similar.rs:17:19
+  --> $DIR/extern-type-diag-not-similar.rs:20:19
    |
-LL | fn assert_send<T: Send + ?Sized>() {}
+LL | fn assert_send<T: Send + PointeeSized>() {}
    |                   ^^^^ required by this bound in `assert_send`
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/extern/extern-types-manual-sync-send.rs b/tests/ui/extern/extern-types-manual-sync-send.rs
index 2df0cd4c923..b273dcea722 100644
--- a/tests/ui/extern/extern-types-manual-sync-send.rs
+++ b/tests/ui/extern/extern-types-manual-sync-send.rs
@@ -1,7 +1,9 @@
 //@ run-pass
 // Test that unsafe impl for Sync/Send can be provided for extern types.
 
-#![feature(extern_types)]
+#![feature(extern_types, sized_hierarchy)]
+
+use std::marker::PointeeSized;
 
 extern "C" {
     type A;
@@ -10,8 +12,8 @@ extern "C" {
 unsafe impl Sync for A {}
 unsafe impl Send for A {}
 
-fn assert_sync<T: ?Sized + Sync>() {}
-fn assert_send<T: ?Sized + Send>() {}
+fn assert_sync<T: PointeeSized + Sync>() {}
+fn assert_send<T: PointeeSized + Send>() {}
 
 fn main() {
     assert_sync::<A>();
diff --git a/tests/ui/extern/extern-types-not-sync-send.rs b/tests/ui/extern/extern-types-not-sync-send.rs
index ba82caced7a..3cac1aabea9 100644
--- a/tests/ui/extern/extern-types-not-sync-send.rs
+++ b/tests/ui/extern/extern-types-not-sync-send.rs
@@ -1,13 +1,15 @@
 // Make sure extern types are !Sync and !Send.
 
-#![feature(extern_types)]
+#![feature(extern_types, sized_hierarchy)]
+
+use std::marker::PointeeSized;
 
 extern "C" {
     type A;
 }
 
-fn assert_sync<T: ?Sized + Sync>() {}
-fn assert_send<T: ?Sized + Send>() {}
+fn assert_sync<T: PointeeSized + Sync>() {}
+fn assert_send<T: PointeeSized + Send>() {}
 
 fn main() {
     assert_sync::<A>();
diff --git a/tests/ui/extern/extern-types-not-sync-send.stderr b/tests/ui/extern/extern-types-not-sync-send.stderr
index 7865ddeda34..56bdd5be7cf 100644
--- a/tests/ui/extern/extern-types-not-sync-send.stderr
+++ b/tests/ui/extern/extern-types-not-sync-send.stderr
@@ -1,28 +1,28 @@
 error[E0277]: `A` cannot be shared between threads safely
-  --> $DIR/extern-types-not-sync-send.rs:13:19
+  --> $DIR/extern-types-not-sync-send.rs:15:19
    |
 LL |     assert_sync::<A>();
    |                   ^ `A` cannot be shared between threads safely
    |
    = help: the trait `Sync` is not implemented for `A`
 note: required by a bound in `assert_sync`
-  --> $DIR/extern-types-not-sync-send.rs:9:28
+  --> $DIR/extern-types-not-sync-send.rs:11:34
    |
-LL | fn assert_sync<T: ?Sized + Sync>() {}
-   |                            ^^^^ required by this bound in `assert_sync`
+LL | fn assert_sync<T: PointeeSized + Sync>() {}
+   |                                  ^^^^ required by this bound in `assert_sync`
 
 error[E0277]: `A` cannot be sent between threads safely
-  --> $DIR/extern-types-not-sync-send.rs:16:19
+  --> $DIR/extern-types-not-sync-send.rs:18:19
    |
 LL |     assert_send::<A>();
    |                   ^ `A` cannot be sent between threads safely
    |
    = help: the trait `Send` is not implemented for `A`
 note: required by a bound in `assert_send`
-  --> $DIR/extern-types-not-sync-send.rs:10:28
+  --> $DIR/extern-types-not-sync-send.rs:12:34
    |
-LL | fn assert_send<T: ?Sized + Send>() {}
-   |                            ^^^^ required by this bound in `assert_send`
+LL | fn assert_send<T: PointeeSized + Send>() {}
+   |                                  ^^^^ required by this bound in `assert_send`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/extern/extern-types-pointer-cast.rs b/tests/ui/extern/extern-types-pointer-cast.rs
index 78dbee77b9c..080ed91a632 100644
--- a/tests/ui/extern/extern-types-pointer-cast.rs
+++ b/tests/ui/extern/extern-types-pointer-cast.rs
@@ -2,7 +2,8 @@
 #![allow(dead_code)]
 // Test that pointers to extern types can be cast from/to usize,
 // despite being !Sized.
-#![feature(extern_types)]
+#![feature(extern_types, sized_hierarchy)]
+use std::marker::PointeeSized;
 
 extern "C" {
     type A;
@@ -13,7 +14,7 @@ struct Foo {
     tail: A,
 }
 
-struct Bar<T: ?Sized> {
+struct Bar<T: PointeeSized> {
     x: u8,
     tail: T,
 }
diff --git a/tests/ui/extern/extern-types-size_of_val.rs b/tests/ui/extern/extern-types-size_of_val.rs
index 399a5828ff3..3ff51b9b6b0 100644
--- a/tests/ui/extern/extern-types-size_of_val.rs
+++ b/tests/ui/extern/extern-types-size_of_val.rs
@@ -1,8 +1,4 @@
-//@ run-fail
-//@ check-run-results
-//@ exec-env:RUST_BACKTRACE=0
-//@ normalize-stderr: "(core/src/panicking\.rs):[0-9]+:[0-9]+" -> "$1:$$LINE:$$COL"
-//@ revisions: size align
+//@ check-fail
 #![feature(extern_types)]
 
 use std::mem::{align_of_val, size_of_val};
@@ -14,10 +10,8 @@ extern "C" {
 fn main() {
     let x: &A = unsafe { &*(1usize as *const A) };
 
-    // These don't have a dynamic size, so this should panic.
-    if cfg!(size) {
-        assert_eq!(size_of_val(x), 0);
-    } else {
-        assert_eq!(align_of_val(x), 1);
-    }
+    size_of_val(x);
+    //~^ ERROR the size for values of type `A` cannot be known
+    align_of_val(x);
+    //~^ ERROR the size for values of type `A` cannot be known
 }
diff --git a/tests/ui/extern/extern-types-size_of_val.stderr b/tests/ui/extern/extern-types-size_of_val.stderr
new file mode 100644
index 00000000000..8678c6c3d60
--- /dev/null
+++ b/tests/ui/extern/extern-types-size_of_val.stderr
@@ -0,0 +1,39 @@
+error[E0277]: the size for values of type `A` cannot be known
+  --> $DIR/extern-types-size_of_val.rs:13:17
+   |
+LL |     size_of_val(x);
+   |     ----------- ^ the trait `MetaSized` is not implemented for `A`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = note: the trait bound `A: MetaSized` is not satisfied
+note: required by a bound in `std::mem::size_of_val`
+  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
+help: consider borrowing here
+   |
+LL |     size_of_val(&x);
+   |                 +
+LL |     size_of_val(&mut x);
+   |                 ++++
+
+error[E0277]: the size for values of type `A` cannot be known
+  --> $DIR/extern-types-size_of_val.rs:15:18
+   |
+LL |     align_of_val(x);
+   |     ------------ ^ the trait `MetaSized` is not implemented for `A`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = note: the trait bound `A: MetaSized` is not satisfied
+note: required by a bound in `std::mem::align_of_val`
+  --> $SRC_DIR/core/src/mem/mod.rs:LL:COL
+help: consider borrowing here
+   |
+LL |     align_of_val(&x);
+   |                  +
+LL |     align_of_val(&mut x);
+   |                  ++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/extern/extern-types-thin-pointer.rs b/tests/ui/extern/extern-types-thin-pointer.rs
index 8e5911228b2..15777d456c2 100644
--- a/tests/ui/extern/extern-types-thin-pointer.rs
+++ b/tests/ui/extern/extern-types-thin-pointer.rs
@@ -2,8 +2,9 @@
 #![allow(dead_code)]
 // Test that pointers and references to extern types are thin, ie they have the same size and
 // alignment as a pointer to ().
-#![feature(extern_types)]
+#![feature(extern_types, sized_hierarchy)]
 
+use std::marker::PointeeSized;
 use std::mem::{align_of, size_of};
 
 extern "C" {
@@ -15,12 +16,12 @@ struct Foo {
     tail: A,
 }
 
-struct Bar<T: ?Sized> {
+struct Bar<T: PointeeSized> {
     x: u8,
     tail: T,
 }
 
-fn assert_thin<T: ?Sized>() {
+fn assert_thin<T: PointeeSized>() {
     assert_eq!(size_of::<*const T>(), size_of::<*const ()>());
     assert_eq!(align_of::<*const T>(), align_of::<*const ()>());
 
diff --git a/tests/ui/extern/extern-types-trait-impl.rs b/tests/ui/extern/extern-types-trait-impl.rs
index 44300b10514..07cb1efa801 100644
--- a/tests/ui/extern/extern-types-trait-impl.rs
+++ b/tests/ui/extern/extern-types-trait-impl.rs
@@ -1,13 +1,14 @@
 //@ run-pass
 #![allow(dead_code)]
 // Test that traits can be implemented for extern types.
-#![feature(extern_types)]
+#![feature(extern_types, sized_hierarchy)]
+use std::marker::PointeeSized;
 
 extern "C" {
     type A;
 }
 
-trait Foo {
+trait Foo: PointeeSized {
     fn foo(&self) {}
 }
 
@@ -15,9 +16,9 @@ impl Foo for A {
     fn foo(&self) {}
 }
 
-fn assert_foo<T: ?Sized + Foo>() {}
+fn assert_foo<T: PointeeSized + Foo>() {}
 
-fn use_foo<T: ?Sized + Foo>(x: &dyn Foo) {
+fn use_foo<T: PointeeSized + Foo>(x: &dyn Foo) {
     x.foo();
 }
 
diff --git a/tests/ui/extern/extern-types-unsized.rs b/tests/ui/extern/extern-types-unsized.rs
index 94a222a7e7e..46cdc24e083 100644
--- a/tests/ui/extern/extern-types-unsized.rs
+++ b/tests/ui/extern/extern-types-unsized.rs
@@ -27,7 +27,9 @@ fn main() {
 
     assert_sized::<Bar<A>>();
     //~^ ERROR the size for values of type
+    //~| ERROR the size for values of type
 
     assert_sized::<Bar<Bar<A>>>();
     //~^ ERROR the size for values of type
+    //~| ERROR the size for values of type
 }
diff --git a/tests/ui/extern/extern-types-unsized.stderr b/tests/ui/extern/extern-types-unsized.stderr
index a587d4dda55..43dd9800d6d 100644
--- a/tests/ui/extern/extern-types-unsized.stderr
+++ b/tests/ui/extern/extern-types-unsized.stderr
@@ -59,8 +59,21 @@ help: consider relaxing the implicit `Sized` restriction
 LL | fn assert_sized<T: ?Sized>() {}
    |                  ++++++++
 
+error[E0277]: the size for values of type `A` cannot be known
+  --> $DIR/extern-types-unsized.rs:28:20
+   |
+LL |     assert_sized::<Bar<A>>();
+   |                    ^^^^^^ doesn't have a known size
+   |
+   = help: the trait `MetaSized` is not implemented for `A`
+note: required by a bound in `Bar`
+  --> $DIR/extern-types-unsized.rs:14:12
+   |
+LL | struct Bar<T: ?Sized> {
+   |            ^ required by this bound in `Bar`
+
 error[E0277]: the size for values of type `A` cannot be known at compilation time
-  --> $DIR/extern-types-unsized.rs:31:20
+  --> $DIR/extern-types-unsized.rs:32:20
    |
 LL |     assert_sized::<Bar<Bar<A>>>();
    |                    ^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -81,6 +94,19 @@ help: consider relaxing the implicit `Sized` restriction
 LL | fn assert_sized<T: ?Sized>() {}
    |                  ++++++++
 
-error: aborting due to 4 previous errors
+error[E0277]: the size for values of type `A` cannot be known
+  --> $DIR/extern-types-unsized.rs:32:20
+   |
+LL |     assert_sized::<Bar<Bar<A>>>();
+   |                    ^^^^^^^^^^^ doesn't have a known size
+   |
+   = help: the trait `MetaSized` is not implemented for `A`
+note: required by a bound in `Bar`
+  --> $DIR/extern-types-unsized.rs:14:12
+   |
+LL | struct Bar<T: ?Sized> {
+   |            ^ required by this bound in `Bar`
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/extern/unsized-extern-derefmove.rs b/tests/ui/extern/unsized-extern-derefmove.rs
index 4ec9e53f49d..c02375266ab 100644
--- a/tests/ui/extern/unsized-extern-derefmove.rs
+++ b/tests/ui/extern/unsized-extern-derefmove.rs
@@ -1,15 +1,20 @@
-//! Regression test for #79409
-
 #![feature(extern_types)]
 
-unsafe extern "C" {
+// Regression test for #79409
+
+extern "C" {
     type Device;
 }
 
 unsafe fn make_device() -> Box<Device> {
+//~^ ERROR the size for values of type `Device` cannot be known
     Box::from_raw(0 as *mut _)
+//~^ ERROR the size for values of type `Device` cannot be known
+//~| ERROR the size for values of type `Device` cannot be known
 }
 
 fn main() {
-    let d: Device = unsafe { *make_device() }; //~ERROR the size for values of type `Device` cannot be known at compilation time
+    let d: Device = unsafe { *make_device() };
+//~^ ERROR the size for values of type `Device` cannot be known
+//~| ERROR the size for values of type `Device` cannot be known
 }
diff --git a/tests/ui/extern/unsized-extern-derefmove.stderr b/tests/ui/extern/unsized-extern-derefmove.stderr
index c43184d94e1..d6be76a9d62 100644
--- a/tests/ui/extern/unsized-extern-derefmove.stderr
+++ b/tests/ui/extern/unsized-extern-derefmove.stderr
@@ -1,5 +1,43 @@
+error[E0277]: the size for values of type `Device` cannot be known
+  --> $DIR/unsized-extern-derefmove.rs:9:28
+   |
+LL | unsafe fn make_device() -> Box<Device> {
+   |                            ^^^^^^^^^^^ doesn't have a known size
+   |
+   = help: the trait `MetaSized` is not implemented for `Device`
+note: required by a bound in `Box`
+  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+
+error[E0277]: the size for values of type `Device` cannot be known
+  --> $DIR/unsized-extern-derefmove.rs:11:19
+   |
+LL |     Box::from_raw(0 as *mut _)
+   |     ------------- ^^^^^^^^^^^ the trait `MetaSized` is not implemented for `Device`
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = note: the trait bound `Device: MetaSized` is not satisfied
+note: required by a bound in `Box::<T>::from_raw`
+  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+help: consider borrowing here
+   |
+LL |     Box::from_raw(&0 as *mut _)
+   |                   +
+LL |     Box::from_raw(&mut 0 as *mut _)
+   |                   ++++
+
+error[E0277]: the size for values of type `Device` cannot be known
+  --> $DIR/unsized-extern-derefmove.rs:11:5
+   |
+LL |     Box::from_raw(0 as *mut _)
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a known size
+   |
+   = help: the trait `MetaSized` is not implemented for `Device`
+note: required by a bound in `Box`
+  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+
 error[E0277]: the size for values of type `Device` cannot be known at compilation time
-  --> $DIR/unsized-extern-derefmove.rs:14:9
+  --> $DIR/unsized-extern-derefmove.rs:17:9
    |
 LL |     let d: Device = unsafe { *make_device() };
    |         ^ doesn't have a size known at compile-time
@@ -11,6 +49,16 @@ help: consider borrowing here
 LL |     let d: &Device = unsafe { *make_device() };
    |            +
 
-error: aborting due to 1 previous error
+error[E0277]: the size for values of type `Device` cannot be known
+  --> $DIR/unsized-extern-derefmove.rs:17:31
+   |
+LL |     let d: Device = unsafe { *make_device() };
+   |                               ^^^^^^^^^^^^^ doesn't have a known size
+   |
+   = help: the trait `MetaSized` is not implemented for `Device`
+note: required by a bound in `Box`
+  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+
+error: aborting due to 5 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/feature-gates/feature-gate-default-field-values.rs b/tests/ui/feature-gates/feature-gate-default-field-values.rs
index d2e41a71602..4631f51b9d8 100644
--- a/tests/ui/feature-gates/feature-gate-default-field-values.rs
+++ b/tests/ui/feature-gates/feature-gate-default-field-values.rs
@@ -58,6 +58,16 @@ pub enum OptEnum {
     }
 }
 
+// Default field values may not be used on `union`s (at least, this is not described in the accepted
+// RFC, and it's not currently clear how to extend the design to do so). We emit a feature gate
+// error when the feature is not enabled, but syntactically reject default field values when used
+// with unions when the feature is enabled. This can be adjusted if there's an acceptable design
+// extension, or just unconditionally reject always.
+union U {
+    x: i32 = 0,   //~ ERROR default values on fields are experimental
+    y: f32 = 0.0, //~ ERROR default values on fields are experimental
+}
+
 fn main () {
     let x = Foo { .. }; //~ ERROR base expression required after `..`
     let y = Foo::default();
diff --git a/tests/ui/feature-gates/feature-gate-default-field-values.stderr b/tests/ui/feature-gates/feature-gate-default-field-values.stderr
index 104d72a3986..292c3899072 100644
--- a/tests/ui/feature-gates/feature-gate-default-field-values.stderr
+++ b/tests/ui/feature-gates/feature-gate-default-field-values.stderr
@@ -124,8 +124,28 @@ LL |         optional: () = (),
    = help: add `#![feature(default_field_values)]` 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]: default values on fields are experimental
+  --> $DIR/feature-gate-default-field-values.rs:67:11
+   |
+LL |     x: i32 = 0,
+   |           ^^^^
+   |
+   = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information
+   = help: add `#![feature(default_field_values)]` 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]: default values on fields are experimental
+  --> $DIR/feature-gate-default-field-values.rs:68:11
+   |
+LL |     y: f32 = 0.0,
+   |           ^^^^^^
+   |
+   = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information
+   = help: add `#![feature(default_field_values)]` 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[E0797]: base expression required after `..`
-  --> $DIR/feature-gate-default-field-values.rs:62:21
+  --> $DIR/feature-gate-default-field-values.rs:72:21
    |
 LL |     let x = Foo { .. };
    |                     ^
@@ -140,7 +160,7 @@ LL |     let x = Foo { ../* expr */ };
    |                     ++++++++++
 
 error[E0797]: base expression required after `..`
-  --> $DIR/feature-gate-default-field-values.rs:64:29
+  --> $DIR/feature-gate-default-field-values.rs:74:29
    |
 LL |     let z = Foo { baz: 1, .. };
    |                             ^
@@ -155,7 +175,7 @@ LL |     let z = Foo { baz: 1, ../* expr */ };
    |                             ++++++++++
 
 error[E0797]: base expression required after `..`
-  --> $DIR/feature-gate-default-field-values.rs:70:26
+  --> $DIR/feature-gate-default-field-values.rs:80:26
    |
 LL |     let x = Bar::Foo { .. };
    |                          ^
@@ -170,7 +190,7 @@ LL |     let x = Bar::Foo { ../* expr */ };
    |                          ++++++++++
 
 error[E0797]: base expression required after `..`
-  --> $DIR/feature-gate-default-field-values.rs:72:34
+  --> $DIR/feature-gate-default-field-values.rs:82:34
    |
 LL |     let z = Bar::Foo { baz: 1, .. };
    |                                  ^
@@ -185,7 +205,7 @@ LL |     let z = Bar::Foo { baz: 1, ../* expr */ };
    |                                  ++++++++++
 
 error[E0797]: base expression required after `..`
-  --> $DIR/feature-gate-default-field-values.rs:78:31
+  --> $DIR/feature-gate-default-field-values.rs:88:31
    |
 LL |     let x = Qux::<i32, 4> { .. };
    |                               ^
@@ -200,7 +220,7 @@ LL |     let x = Qux::<i32, 4> { ../* expr */ };
    |                               ++++++++++
 
 error[E0797]: base expression required after `..`
-  --> $DIR/feature-gate-default-field-values.rs:79:73
+  --> $DIR/feature-gate-default-field-values.rs:89:73
    |
 LL |     assert!(matches!(Qux::<i32, 4> { bar: S, baz: 42, bat: 2, bay: 4, .. }, x));
    |                                                                         ^
@@ -215,7 +235,7 @@ LL |     assert!(matches!(Qux::<i32, 4> { bar: S, baz: 42, bat: 2, bay: 4, ../*
    |                                                                         ++++++++++
 
 error[E0797]: base expression required after `..`
-  --> $DIR/feature-gate-default-field-values.rs:82:38
+  --> $DIR/feature-gate-default-field-values.rs:92:38
    |
 LL |     let y = Opt { mandatory: None, .. };
    |                                      ^
@@ -230,7 +250,7 @@ LL |     let y = Opt { mandatory: None, ../* expr */ };
    |                                      ++++++++++
 
 error[E0797]: base expression required after `..`
-  --> $DIR/feature-gate-default-field-values.rs:86:47
+  --> $DIR/feature-gate-default-field-values.rs:96:47
    |
 LL |     assert!(matches!(Opt { mandatory: None, .. }, z));
    |                                               ^
@@ -245,7 +265,7 @@ LL |     assert!(matches!(Opt { mandatory: None, ../* expr */ }, z));
    |                                               ++++++++++
 
 error[E0797]: base expression required after `..`
-  --> $DIR/feature-gate-default-field-values.rs:88:30
+  --> $DIR/feature-gate-default-field-values.rs:98:30
    |
 LL |     assert!(matches!(Opt { .. }, z));
    |                              ^
@@ -256,7 +276,7 @@ LL |     assert!(matches!(Opt { ../* expr */ }, z));
    |                              ++++++++++
 
 error[E0797]: base expression required after `..`
-  --> $DIR/feature-gate-default-field-values.rs:90:44
+  --> $DIR/feature-gate-default-field-values.rs:100:44
    |
 LL |     assert!(matches!(Opt { optional: (), .. }, z));
    |                                            ^
@@ -267,7 +287,7 @@ LL |     assert!(matches!(Opt { optional: (), ../* expr */ }, z));
    |                                            ++++++++++
 
 error[E0797]: base expression required after `..`
-  --> $DIR/feature-gate-default-field-values.rs:92:61
+  --> $DIR/feature-gate-default-field-values.rs:102:61
    |
 LL |     assert!(matches!(Opt { optional: (), mandatory: None, .. }, z));
    |                                                             ^
@@ -279,7 +299,7 @@ LL +     assert!(matches!(Opt { optional: (), mandatory: None,  }, z));
    |
 
 error[E0797]: base expression required after `..`
-  --> $DIR/feature-gate-default-field-values.rs:94:51
+  --> $DIR/feature-gate-default-field-values.rs:104:51
    |
 LL |     let y = OptEnum::Variant { mandatory: None, .. };
    |                                                   ^
@@ -294,7 +314,7 @@ LL |     let y = OptEnum::Variant { mandatory: None, ../* expr */ };
    |                                                   ++++++++++
 
 error[E0797]: base expression required after `..`
-  --> $DIR/feature-gate-default-field-values.rs:98:60
+  --> $DIR/feature-gate-default-field-values.rs:108:60
    |
 LL |     assert!(matches!(OptEnum::Variant { mandatory: None, .. }, z));
    |                                                            ^
@@ -309,7 +329,7 @@ LL |     assert!(matches!(OptEnum::Variant { mandatory: None, ../* expr */ }, z)
    |                                                            ++++++++++
 
 error[E0797]: base expression required after `..`
-  --> $DIR/feature-gate-default-field-values.rs:100:43
+  --> $DIR/feature-gate-default-field-values.rs:110:43
    |
 LL |     assert!(matches!(OptEnum::Variant { .. }, z));
    |                                           ^
@@ -320,7 +340,7 @@ LL |     assert!(matches!(OptEnum::Variant { ../* expr */ }, z));
    |                                           ++++++++++
 
 error[E0797]: base expression required after `..`
-  --> $DIR/feature-gate-default-field-values.rs:102:57
+  --> $DIR/feature-gate-default-field-values.rs:112:57
    |
 LL |     assert!(matches!(OptEnum::Variant { optional: (), .. }, z));
    |                                                         ^
@@ -331,7 +351,7 @@ LL |     assert!(matches!(OptEnum::Variant { optional: (), ../* expr */ }, z));
    |                                                         ++++++++++
 
 error[E0797]: base expression required after `..`
-  --> $DIR/feature-gate-default-field-values.rs:104:74
+  --> $DIR/feature-gate-default-field-values.rs:114:74
    |
 LL |     assert!(matches!(OptEnum::Variant { optional: (), mandatory: None, .. }, z));
    |                                                                          ^
@@ -342,7 +362,7 @@ LL -     assert!(matches!(OptEnum::Variant { optional: (), mandatory: None, .. }
 LL +     assert!(matches!(OptEnum::Variant { optional: (), mandatory: None,  }, z));
    |
 
-error: aborting due to 29 previous errors
+error: aborting due to 31 previous errors
 
 Some errors have detailed explanations: E0658, E0797.
 For more information about an error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-sized-hierarchy.rs b/tests/ui/feature-gates/feature-gate-sized-hierarchy.rs
new file mode 100644
index 00000000000..33688c2e2ce
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-sized-hierarchy.rs
@@ -0,0 +1,29 @@
+#![feature(extern_types)]
+#![feature(sized_hierarchy)]
+
+use std::marker::{MetaSized, PointeeSized};
+
+fn needs_pointeesized<T: PointeeSized>() {}
+fn needs_metasized<T: MetaSized>() {}
+fn needs_sized<T: Sized>() {}
+
+fn main() {
+    needs_pointeesized::<u8>();
+    needs_metasized::<u8>();
+    needs_sized::<u8>();
+
+    needs_pointeesized::<str>();
+    needs_metasized::<str>();
+    needs_sized::<str>();
+//~^ ERROR the size for values of type `str` cannot be known at compilation time
+
+    extern "C" {
+        type Foo;
+    }
+
+    needs_pointeesized::<Foo>();
+    needs_metasized::<Foo>();
+//~^ ERROR the size for values of type `main::Foo` cannot be known
+    needs_sized::<Foo>();
+//~^ ERROR the size for values of type `main::Foo` cannot be known at compilation time
+}
diff --git a/tests/ui/feature-gates/feature-gate-sized-hierarchy.stderr b/tests/ui/feature-gates/feature-gate-sized-hierarchy.stderr
new file mode 100644
index 00000000000..6a35fcfb0e8
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-sized-hierarchy.stderr
@@ -0,0 +1,42 @@
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/feature-gate-sized-hierarchy.rs:17:19
+   |
+LL |     needs_sized::<str>();
+   |                   ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+note: required by a bound in `needs_sized`
+  --> $DIR/feature-gate-sized-hierarchy.rs:8:19
+   |
+LL | fn needs_sized<T: Sized>() {}
+   |                   ^^^^^ required by this bound in `needs_sized`
+
+error[E0277]: the size for values of type `main::Foo` cannot be known
+  --> $DIR/feature-gate-sized-hierarchy.rs:25:23
+   |
+LL |     needs_metasized::<Foo>();
+   |                       ^^^ doesn't have a known size
+   |
+   = help: the trait `MetaSized` is not implemented for `main::Foo`
+note: required by a bound in `needs_metasized`
+  --> $DIR/feature-gate-sized-hierarchy.rs:7:23
+   |
+LL | fn needs_metasized<T: MetaSized>() {}
+   |                       ^^^^^^^^^ required by this bound in `needs_metasized`
+
+error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
+  --> $DIR/feature-gate-sized-hierarchy.rs:27:19
+   |
+LL |     needs_sized::<Foo>();
+   |                   ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `main::Foo`
+note: required by a bound in `needs_sized`
+  --> $DIR/feature-gate-sized-hierarchy.rs:8:19
+   |
+LL | fn needs_sized<T: Sized>() {}
+   |                   ^^^^^ required by this bound in `needs_sized`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
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 bdca6163473..1620bf72922 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
@@ -8,16 +8,6 @@ LL | #![rustc_main]
    = note: the `#[rustc_main]` attribute is an internal implementation detail that will never be stable
    = note: the `#[rustc_main]` attribute is used internally to specify test entry point function
 
-error: valid forms for the attribute are `#[inline]` and `#[inline(always|never)]`
-  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:5
-   |
-LL |     #[inline = "2100"] fn f() { }
-   |     ^^^^^^^^^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
-   = note: `#[deny(ill_formed_attribute_input)]` on by default
-
 error[E0518]: attribute should be applied to function or closure
   --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:32:1
    |
@@ -314,6 +304,16 @@ error[E0517]: attribute should be applied to a struct, enum, or union
 LL |     #[repr(Rust)] impl S { }
    |            ^^^^   ---------- not a struct, enum, or union
 
+error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]`
+  --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:5
+   |
+LL |     #[inline = "2100"] fn f() { }
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
+   = note: `#[deny(ill_formed_attribute_input)]` on by default
+
 error: aborting due to 38 previous errors
 
 Some errors have detailed explanations: E0517, E0518, E0658.
diff --git a/tests/ui/force-inlining/invalid.rs b/tests/ui/force-inlining/invalid.rs
index 7574078b245..e9f5712413e 100644
--- a/tests/ui/force-inlining/invalid.rs
+++ b/tests/ui/force-inlining/invalid.rs
@@ -9,7 +9,6 @@
 // Test that invalid force inlining attributes error as expected.
 
 #[rustc_force_inline("foo")]
-//~^ ERROR malformed `rustc_force_inline` attribute input
 pub fn forced1() {
 }
 
diff --git a/tests/ui/force-inlining/invalid.stderr b/tests/ui/force-inlining/invalid.stderr
index 92b3c314bad..3b3da00ae88 100644
--- a/tests/ui/force-inlining/invalid.stderr
+++ b/tests/ui/force-inlining/invalid.stderr
@@ -1,71 +1,71 @@
-error: malformed `rustc_force_inline` attribute input
-  --> $DIR/invalid.rs:11:1
-   |
-LL | #[rustc_force_inline("foo")]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-help: the following are the possible correct uses
-   |
-LL - #[rustc_force_inline("foo")]
-LL + #[rustc_force_inline = "reason"]
-   |
-LL - #[rustc_force_inline("foo")]
-LL + #[rustc_force_inline]
+error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
+  --> $DIR/invalid.rs:132:11
    |
+LL | fn barqux(#[rustc_force_inline] _x: u32) {}
+   |           ^^^^^^^^^^^^^^^^^^^^^
 
-error: malformed `rustc_force_inline` attribute input
-  --> $DIR/invalid.rs:16:1
+error[E0805]: malformed `rustc_force_inline` attribute input
+  --> $DIR/invalid.rs:15:1
    |
 LL | #[rustc_force_inline(bar, baz)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^----------^
+   |                     |
+   |                     expected a single argument here
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[rustc_force_inline(bar, baz)]
 LL + #[rustc_force_inline = "reason"]
    |
 LL - #[rustc_force_inline(bar, baz)]
+LL + #[rustc_force_inline(reason)]
+   |
+LL - #[rustc_force_inline(bar, baz)]
 LL + #[rustc_force_inline]
    |
 
-error: malformed `rustc_force_inline` attribute input
-  --> $DIR/invalid.rs:21:1
+error[E0539]: malformed `rustc_force_inline` attribute input
+  --> $DIR/invalid.rs:20:1
    |
 LL | #[rustc_force_inline(2)]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^-^^
+   |                      |
+   |                      expected a string literal here
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[rustc_force_inline(2)]
 LL + #[rustc_force_inline = "reason"]
    |
 LL - #[rustc_force_inline(2)]
+LL + #[rustc_force_inline(reason)]
+   |
+LL - #[rustc_force_inline(2)]
 LL + #[rustc_force_inline]
    |
 
-error: malformed `rustc_force_inline` attribute input
-  --> $DIR/invalid.rs:26:1
+error[E0539]: malformed `rustc_force_inline` attribute input
+  --> $DIR/invalid.rs:25:1
    |
 LL | #[rustc_force_inline = 2]
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^-^
+   |                        |
+   |                        expected a string literal here
    |
-help: the following are the possible correct uses
+help: try changing it to one of the following valid forms of the attribute
    |
 LL - #[rustc_force_inline = 2]
 LL + #[rustc_force_inline = "reason"]
    |
 LL - #[rustc_force_inline = 2]
-LL + #[rustc_force_inline]
+LL + #[rustc_force_inline(reason)]
    |
-
-error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
-  --> $DIR/invalid.rs:133:11
+LL - #[rustc_force_inline = 2]
+LL + #[rustc_force_inline]
    |
-LL | fn barqux(#[rustc_force_inline] _x: u32) {}
-   |           ^^^^^^^^^^^^^^^^^^^^^
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:31:1
+  --> $DIR/invalid.rs:30:1
    |
 LL | #[rustc_force_inline]
    | ^^^^^^^^^^^^^^^^^^^^^
@@ -74,7 +74,7 @@ LL | extern crate std as other_std;
    | ------------------------------ not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:35:1
+  --> $DIR/invalid.rs:34:1
    |
 LL | #[rustc_force_inline]
    | ^^^^^^^^^^^^^^^^^^^^^
@@ -83,7 +83,7 @@ LL | use std::collections::HashMap;
    | ------------------------------ not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:39:1
+  --> $DIR/invalid.rs:38:1
    |
 LL | #[rustc_force_inline]
    | ^^^^^^^^^^^^^^^^^^^^^
@@ -92,7 +92,7 @@ LL | static _FOO: &'static str = "FOO";
    | ---------------------------------- not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:43:1
+  --> $DIR/invalid.rs:42:1
    |
 LL | #[rustc_force_inline]
    | ^^^^^^^^^^^^^^^^^^^^^
@@ -101,7 +101,7 @@ LL | const _BAR: u32 = 3;
    | -------------------- not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:47:1
+  --> $DIR/invalid.rs:46:1
    |
 LL | #[rustc_force_inline]
    | ^^^^^^^^^^^^^^^^^^^^^
@@ -110,7 +110,7 @@ LL | mod foo { }
    | ----------- not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:51:1
+  --> $DIR/invalid.rs:50:1
    |
 LL |   #[rustc_force_inline]
    |   ^^^^^^^^^^^^^^^^^^^^^
@@ -125,7 +125,7 @@ LL | | }
    | |_- not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:67:1
+  --> $DIR/invalid.rs:66:1
    |
 LL | #[rustc_force_inline]
    | ^^^^^^^^^^^^^^^^^^^^^
@@ -134,7 +134,7 @@ LL | type Foo = u32;
    | --------------- not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:71:1
+  --> $DIR/invalid.rs:70:1
    |
 LL |   #[rustc_force_inline]
    |   ^^^^^^^^^^^^^^^^^^^^^
@@ -147,13 +147,13 @@ LL | | }
    | |_- not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:73:10
+  --> $DIR/invalid.rs:72:10
    |
 LL | enum Bar<#[rustc_force_inline] T> {
    |          ^^^^^^^^^^^^^^^^^^^^^ - not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:75:5
+  --> $DIR/invalid.rs:74:5
    |
 LL |     #[rustc_force_inline]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -162,7 +162,7 @@ LL |     Baz(std::marker::PhantomData<T>),
    |     -------------------------------- not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:80:1
+  --> $DIR/invalid.rs:79:1
    |
 LL |   #[rustc_force_inline]
    |   ^^^^^^^^^^^^^^^^^^^^^
@@ -175,7 +175,7 @@ LL | | }
    | |_- not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:83:5
+  --> $DIR/invalid.rs:82:5
    |
 LL |     #[rustc_force_inline]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -184,7 +184,7 @@ LL |     field: u32,
    |     ---------- not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:88:1
+  --> $DIR/invalid.rs:87:1
    |
 LL |   #[rustc_force_inline]
    |   ^^^^^^^^^^^^^^^^^^^^^
@@ -196,7 +196,7 @@ LL | | }
    | |_- not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:95:1
+  --> $DIR/invalid.rs:94:1
    |
 LL |   #[rustc_force_inline]
    |   ^^^^^^^^^^^^^^^^^^^^^
@@ -211,7 +211,7 @@ LL | | }
    | |_- not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:110:1
+  --> $DIR/invalid.rs:109:1
    |
 LL | #[rustc_force_inline]
    | ^^^^^^^^^^^^^^^^^^^^^
@@ -220,7 +220,7 @@ LL | trait FooQux = FooBaz;
    | ---------------------- not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:114:1
+  --> $DIR/invalid.rs:113:1
    |
 LL |   #[rustc_force_inline]
    |   ^^^^^^^^^^^^^^^^^^^^^
@@ -233,7 +233,7 @@ LL | | }
    | |_- not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:122:1
+  --> $DIR/invalid.rs:121:1
    |
 LL |   #[rustc_force_inline]
    |   ^^^^^^^^^^^^^^^^^^^^^
@@ -245,7 +245,7 @@ LL | | }
    | |_- not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:129:1
+  --> $DIR/invalid.rs:128:1
    |
 LL | #[rustc_force_inline]
    | ^^^^^^^^^^^^^^^^^^^^^
@@ -254,7 +254,7 @@ LL | macro_rules! barqux { ($foo:tt) => { $foo }; }
    | ---------------------------------------------- not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:133:11
+  --> $DIR/invalid.rs:132:11
    |
 LL | fn barqux(#[rustc_force_inline] _x: u32) {}
    |           ^^^^^^^^^^^^^^^^^^^^^--------
@@ -262,7 +262,7 @@ LL | fn barqux(#[rustc_force_inline] _x: u32) {}
    |           not a function definition
 
 error: attribute cannot be applied to a `async`, `gen` or `async gen` function
-  --> $DIR/invalid.rs:137:1
+  --> $DIR/invalid.rs:136:1
    |
 LL | #[rustc_force_inline]
    | ^^^^^^^^^^^^^^^^^^^^^
@@ -271,7 +271,7 @@ LL | async fn async_foo() {}
    | -------------------- `async`, `gen` or `async gen` function
 
 error: attribute cannot be applied to a `async`, `gen` or `async gen` function
-  --> $DIR/invalid.rs:141:1
+  --> $DIR/invalid.rs:140:1
    |
 LL | #[rustc_force_inline]
    | ^^^^^^^^^^^^^^^^^^^^^
@@ -280,7 +280,7 @@ LL | gen fn gen_foo() {}
    | ---------------- `async`, `gen` or `async gen` function
 
 error: attribute cannot be applied to a `async`, `gen` or `async gen` function
-  --> $DIR/invalid.rs:145:1
+  --> $DIR/invalid.rs:144:1
    |
 LL | #[rustc_force_inline]
    | ^^^^^^^^^^^^^^^^^^^^^
@@ -289,19 +289,19 @@ LL | async gen fn async_gen_foo() {}
    | ---------------------------- `async`, `gen` or `async gen` function
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:150:14
+  --> $DIR/invalid.rs:149:14
    |
 LL |     let _x = #[rustc_force_inline] || { };
    |              ^^^^^^^^^^^^^^^^^^^^^ ------ not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:152:14
+  --> $DIR/invalid.rs:151:14
    |
 LL |     let _y = #[rustc_force_inline] 3 + 4;
    |              ^^^^^^^^^^^^^^^^^^^^^ - not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:154:5
+  --> $DIR/invalid.rs:153:5
    |
 LL |     #[rustc_force_inline]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -310,7 +310,7 @@ LL |     let _z = 3;
    |     ----------- not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:159:9
+  --> $DIR/invalid.rs:158:9
    |
 LL |         #[rustc_force_inline]
    |         ^^^^^^^^^^^^^^^^^^^^^
@@ -319,7 +319,7 @@ LL |         1 => (),
    |         ------- not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:98:5
+  --> $DIR/invalid.rs:97:5
    |
 LL |     #[rustc_force_inline]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -328,7 +328,7 @@ LL |     type Foo;
    |     --------- not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:101:5
+  --> $DIR/invalid.rs:100:5
    |
 LL |     #[rustc_force_inline]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -337,7 +337,7 @@ LL |     const Bar: i32;
    |     --------------- not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:105:5
+  --> $DIR/invalid.rs:104:5
    |
 LL |     #[rustc_force_inline]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -346,7 +346,7 @@ LL |     fn foo() {}
    |     ----------- not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:117:5
+  --> $DIR/invalid.rs:116:5
    |
 LL |     #[rustc_force_inline]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -355,7 +355,7 @@ LL |     fn foo() {}
    |     ----------- not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:54:5
+  --> $DIR/invalid.rs:53:5
    |
 LL |     #[rustc_force_inline]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -364,7 +364,7 @@ LL |     static X: &'static u32;
    |     ----------------------- not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:58:5
+  --> $DIR/invalid.rs:57:5
    |
 LL |     #[rustc_force_inline]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -373,7 +373,7 @@ LL |     type Y;
    |     ------- not a function definition
 
 error: attribute should be applied to a function
-  --> $DIR/invalid.rs:62:5
+  --> $DIR/invalid.rs:61:5
    |
 LL |     #[rustc_force_inline]
    |     ^^^^^^^^^^^^^^^^^^^^^
@@ -381,5 +381,7 @@ LL |
 LL |     fn foo();
    |     --------- not a function definition
 
-error: aborting due to 38 previous errors
+error: aborting due to 37 previous errors
 
+Some errors have detailed explanations: E0539, E0805.
+For more information about an error, try `rustc --explain E0539`.
diff --git a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.rs b/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.rs
index 2a39d579c51..bb23f9fe5c6 100644
--- a/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.rs
+++ b/tests/ui/invalid-compile-flags/branch-protection-missing-pac-ret.rs
@@ -13,8 +13,14 @@
 #![feature(no_core, lang_items)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+pub trait Sized: MetaSized {}
 
 //[BADFLAGS]~? ERROR incorrect value `leaf` for unstable option `branch-protection`
 //[BADFLAGSPC]~? ERROR incorrect value `pc` for unstable option `branch-protection`
diff --git a/tests/ui/invalid/invalid-inline.rs b/tests/ui/invalid/invalid-inline.rs
index 2501b1e23f2..6735e1d814d 100644
--- a/tests/ui/invalid/invalid-inline.rs
+++ b/tests/ui/invalid/invalid-inline.rs
@@ -1,10 +1,10 @@
 #![allow(dead_code)]
 
-#[inline(please,no)] //~ ERROR expected one argument
+#[inline(please,no)] //~ ERROR malformed `inline` attribute
 fn a() {
 }
 
-#[inline()] //~ ERROR expected one argument
+#[inline()] //~ ERROR malformed `inline` attribute
 fn b() {
 }
 
diff --git a/tests/ui/invalid/invalid-inline.stderr b/tests/ui/invalid/invalid-inline.stderr
index 7edbf936b1b..54e6b2b5408 100644
--- a/tests/ui/invalid/invalid-inline.stderr
+++ b/tests/ui/invalid/invalid-inline.stderr
@@ -1,15 +1,36 @@
-error[E0534]: expected one argument
+error[E0805]: malformed `inline` attribute input
   --> $DIR/invalid-inline.rs:3:1
    |
 LL | #[inline(please,no)]
-   | ^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^-----------^
+   |         |
+   |         expected a single argument here
+   |
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[inline(please,no)]
+LL + #[inline(always|never)]
+   |
+LL - #[inline(please,no)]
+LL + #[inline]
+   |
 
-error[E0534]: expected one argument
+error[E0805]: malformed `inline` attribute input
   --> $DIR/invalid-inline.rs:7:1
    |
 LL | #[inline()]
-   | ^^^^^^^^^^^
+   | ^^^^^^^^--^
+   |         |
+   |         expected a single argument here
+   |
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL | #[inline(always|never)]
+   |          ++++++++++++
+LL - #[inline()]
+LL + #[inline]
+   |
 
 error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0534`.
+For more information about this error, try `rustc --explain E0805`.
diff --git a/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.rs b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.rs
index f3a15a58f26..70e3ef9814d 100644
--- a/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.rs
+++ b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.rs
@@ -28,4 +28,11 @@ fn main() {
 
     std::arch::x86_64::_mm_inserti_si64(loop {}, loop {}, || (), 1 + || ());
     //~^ ERROR invalid argument to a legacy const generic
+
+    // A regression test for <https://github.com/rust-lang/rust/issues/142525>.
+    struct Struct<T> {
+        field: T,
+    }
+    std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, Struct { field: || () });
+    //~^ ERROR invalid argument to a legacy const generic
 }
diff --git a/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr
index 8d120ae98d9..6f5d719006d 100644
--- a/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr
+++ b/tests/ui/invalid/invalid-rustc_legacy_const_generics-issue-123077.stderr
@@ -84,5 +84,17 @@ LL -     std::arch::x86_64::_mm_inserti_si64(loop {}, loop {}, || (), 1 + || ())
 LL +     std::arch::x86_64::_mm_inserti_si64::<{ || () }, { 1 + || () }>(loop {}, loop {});
    |
 
-error: aborting due to 7 previous errors
+error: invalid argument to a legacy const generic: cannot have const blocks, closures, async blocks or items
+  --> $DIR/invalid-rustc_legacy_const_generics-issue-123077.rs:36:71
+   |
+LL |     std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, Struct { field: || () });
+   |                                                                       ^^^^^
+   |
+help: try using a const generic argument instead
+   |
+LL -     std::arch::x86_64::_mm_blend_ps(loop {}, loop {}, Struct { field: || () });
+LL +     std::arch::x86_64::_mm_blend_ps::<{ Struct { field: || () } }>(loop {}, loop {});
+   |
+
+error: aborting due to 8 previous errors
 
diff --git a/tests/ui/issues/issue-43988.rs b/tests/ui/issues/issue-43988.rs
index b114e8e0333..5fea5576b7f 100644
--- a/tests/ui/issues/issue-43988.rs
+++ b/tests/ui/issues/issue-43988.rs
@@ -9,7 +9,7 @@ fn main() {
 
     #[inline(XYZ)]
     let _b = 4;
-    //~^^ ERROR attribute should be applied to function or closure
+    //~^^ ERROR malformed `inline` attribute
 
     #[repr(nothing)]
     let _x = 0;
@@ -29,7 +29,7 @@ fn main() {
 
     #[inline(ABC)]
     foo();
-    //~^^ ERROR attribute should be applied to function or closure
+    //~^^ ERROR malformed `inline` attribute
 
     let _z = #[repr] 1;
     //~^ ERROR malformed `repr` attribute
diff --git a/tests/ui/issues/issue-43988.stderr b/tests/ui/issues/issue-43988.stderr
index d629f199b22..bd4eb8bbed3 100644
--- a/tests/ui/issues/issue-43988.stderr
+++ b/tests/ui/issues/issue-43988.stderr
@@ -1,14 +1,19 @@
-error: malformed `repr` attribute input
-  --> $DIR/issue-43988.rs:24:5
+error[E0539]: malformed `inline` attribute input
+  --> $DIR/issue-43988.rs:10:5
    |
-LL |     #[repr]
-   |     ^^^^^^^ help: must be of the form: `#[repr(C)]`
-
-error: malformed `repr` attribute input
-  --> $DIR/issue-43988.rs:34:14
+LL |     #[inline(XYZ)]
+   |     ^^^^^^^^^---^^
+   |              |
+   |              valid arguments are `always` or `never`
+   |
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL -     #[inline(XYZ)]
+LL +     #[inline(always|never)]
+   |
+LL -     #[inline(XYZ)]
+LL +     #[inline]
    |
-LL |     let _z = #[repr] 1;
-   |              ^^^^^^^ help: must be of the form: `#[repr(C)]`
 
 error[E0552]: unrecognized representation hint
   --> $DIR/issue-43988.rs:14:12
@@ -26,6 +31,41 @@ 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[E0539]: malformed `repr` attribute input
+  --> $DIR/issue-43988.rs:24:5
+   |
+LL |     #[repr]
+   |     ^^^^^^^
+   |     |
+   |     expected this to be a list
+   |     help: must be of the form: `#[repr(C)]`
+
+error[E0539]: malformed `inline` attribute input
+  --> $DIR/issue-43988.rs:30:5
+   |
+LL |     #[inline(ABC)]
+   |     ^^^^^^^^^---^^
+   |              |
+   |              valid arguments are `always` or `never`
+   |
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL -     #[inline(ABC)]
+LL +     #[inline(always|never)]
+   |
+LL -     #[inline(ABC)]
+LL +     #[inline]
+   |
+
+error[E0539]: malformed `repr` attribute input
+  --> $DIR/issue-43988.rs:34:14
+   |
+LL |     let _z = #[repr] 1;
+   |              ^^^^^^^
+   |              |
+   |              expected this to be a list
+   |              help: must be of the form: `#[repr(C)]`
+
 error[E0518]: attribute should be applied to function or closure
   --> $DIR/issue-43988.rs:5:5
    |
@@ -34,23 +74,7 @@ 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)]
-   |     ^^^^^^^^^^^^^^
-LL |     foo();
-   |     ----- not a function or closure
-
 error: aborting due to 7 previous errors
 
-Some errors have detailed explanations: E0518, E0552.
+Some errors have detailed explanations: E0518, E0539, E0552.
 For more information about an error, try `rustc --explain E0518`.
diff --git a/tests/ui/lang-items/issue-83471.rs b/tests/ui/lang-items/issue-83471.rs
index 6be345ac507..f3ce9f25c13 100644
--- a/tests/ui/lang-items/issue-83471.rs
+++ b/tests/ui/lang-items/issue-83471.rs
@@ -4,9 +4,17 @@
 #![feature(no_core)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+//~^ ERROR: lang items are subject to change [E0658]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+//~^ ERROR: lang items are subject to change [E0658]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
 //~^ ERROR: lang items are subject to change [E0658]
-trait Sized {}
+trait Sized: MetaSized {}
 
 #[lang = "fn"]
 //~^ ERROR: lang items are subject to change [E0658]
diff --git a/tests/ui/lang-items/issue-83471.stderr b/tests/ui/lang-items/issue-83471.stderr
index 244b2efeaf1..e913c0bf10f 100644
--- a/tests/ui/lang-items/issue-83471.stderr
+++ b/tests/ui/lang-items/issue-83471.stderr
@@ -1,5 +1,5 @@
 error[E0573]: expected type, found built-in attribute `export_name`
-  --> $DIR/issue-83471.rs:15:13
+  --> $DIR/issue-83471.rs:23:13
    |
 LL |     fn call(export_name);
    |             ^^^^^^^^^^^ not a type
@@ -7,6 +7,24 @@ LL |     fn call(export_name);
 error[E0658]: lang items are subject to change
   --> $DIR/issue-83471.rs:7:1
    |
+LL | #[lang = "pointee_sized"]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(lang_items)]` 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]: lang items are subject to change
+  --> $DIR/issue-83471.rs:11:1
+   |
+LL | #[lang = "meta_sized"]
+   | ^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(lang_items)]` 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]: lang items are subject to change
+  --> $DIR/issue-83471.rs:15:1
+   |
 LL | #[lang = "sized"]
    | ^^^^^^^^^^^^^^^^^
    |
@@ -14,7 +32,7 @@ LL | #[lang = "sized"]
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: lang items are subject to change
-  --> $DIR/issue-83471.rs:11:1
+  --> $DIR/issue-83471.rs:19:1
    |
 LL | #[lang = "fn"]
    | ^^^^^^^^^^^^^^
@@ -23,7 +41,7 @@ LL | #[lang = "fn"]
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 warning: anonymous parameters are deprecated and will be removed in the next edition
-  --> $DIR/issue-83471.rs:15:13
+  --> $DIR/issue-83471.rs:23:13
    |
 LL |     fn call(export_name);
    |             ^^^^^^^^^^^ help: try naming the parameter or explicitly ignoring it: `_: export_name`
@@ -33,7 +51,7 @@ LL |     fn call(export_name);
    = note: `#[warn(anonymous_parameters)]` on by default
 
 error[E0718]: `fn` lang item must be applied to a trait with 1 generic argument
-  --> $DIR/issue-83471.rs:11:1
+  --> $DIR/issue-83471.rs:19:1
    |
 LL | #[lang = "fn"]
    | ^^^^^^^^^^^^^^
@@ -42,12 +60,12 @@ LL | trait Fn {
    |         - this trait has 0 generic arguments
 
 error[E0425]: cannot find function `a` in this scope
-  --> $DIR/issue-83471.rs:21:5
+  --> $DIR/issue-83471.rs:29:5
    |
 LL |     a()
    |     ^ not found in this scope
 
-error: aborting due to 5 previous errors; 1 warning emitted
+error: aborting due to 7 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0425, E0573, E0658, E0718.
 For more information about an error, try `rustc --explain E0425`.
diff --git a/tests/ui/lang-items/issue-87573.rs b/tests/ui/lang-items/issue-87573.rs
index 7b805e8b0cd..97146df0ba7 100644
--- a/tests/ui/lang-items/issue-87573.rs
+++ b/tests/ui/lang-items/issue-87573.rs
@@ -7,8 +7,14 @@
 
 pub static STATIC_BOOL: bool = true;
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+trait Sized: MetaSized {}
 
 #[lang = "copy"]
 trait Copy {}
diff --git a/tests/ui/lang-items/issue-87573.stderr b/tests/ui/lang-items/issue-87573.stderr
index 7085bb8c339..07f4f5d8ac8 100644
--- a/tests/ui/lang-items/issue-87573.stderr
+++ b/tests/ui/lang-items/issue-87573.stderr
@@ -1,5 +1,5 @@
 error[E0718]: `drop_in_place` lang item must be applied to a function with at least 1 generic argument
-  --> $DIR/issue-87573.rs:20:1
+  --> $DIR/issue-87573.rs:26:1
    |
 LL | #[lang = "drop_in_place"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@ LL | fn drop_fn() {
    |           - this function has 0 generic arguments
 
 error[E0718]: `start` lang item must be applied to a function with 1 generic argument
-  --> $DIR/issue-87573.rs:26:1
+  --> $DIR/issue-87573.rs:32:1
    |
 LL | #[lang = "start"]
    | ^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/lang-items/lang-item-generic-requirements.rs b/tests/ui/lang-items/lang-item-generic-requirements.rs
index 25a4ff283ba..168e22ad7db 100644
--- a/tests/ui/lang-items/lang-item-generic-requirements.rs
+++ b/tests/ui/lang-items/lang-item-generic-requirements.rs
@@ -4,8 +4,14 @@
 #![feature(lang_items, no_core)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait MyPointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MyMetaSized: MyPointeeSized {}
+
 #[lang = "sized"]
-trait MySized {}
+trait MySized: MyMetaSized {}
 
 #[lang = "add"]
 trait MyAdd<'a, T> {}
diff --git a/tests/ui/lang-items/lang-item-generic-requirements.stderr b/tests/ui/lang-items/lang-item-generic-requirements.stderr
index c82bdb00fd1..0b3088add61 100644
--- a/tests/ui/lang-items/lang-item-generic-requirements.stderr
+++ b/tests/ui/lang-items/lang-item-generic-requirements.stderr
@@ -1,5 +1,5 @@
 error[E0718]: `add` lang item must be applied to a trait with 1 generic argument
-  --> $DIR/lang-item-generic-requirements.rs:10:1
+  --> $DIR/lang-item-generic-requirements.rs:16:1
    |
 LL | #[lang = "add"]
    | ^^^^^^^^^^^^^^^
@@ -7,7 +7,7 @@ LL | trait MyAdd<'a, T> {}
    |            ------- this trait has 2 generic arguments
 
 error[E0718]: `drop_in_place` lang item must be applied to a function with at least 1 generic argument
-  --> $DIR/lang-item-generic-requirements.rs:14:1
+  --> $DIR/lang-item-generic-requirements.rs:20:1
    |
 LL | #[lang = "drop_in_place"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@ LL | fn my_ptr_drop() {}
    |               - this function has 0 generic arguments
 
 error[E0718]: `index` lang item must be applied to a trait with 1 generic argument
-  --> $DIR/lang-item-generic-requirements.rs:18:1
+  --> $DIR/lang-item-generic-requirements.rs:24:1
    |
 LL | #[lang = "index"]
    | ^^^^^^^^^^^^^^^^^
@@ -24,7 +24,7 @@ LL | trait MyIndex<'a, T> {}
    |              ------- this trait has 2 generic arguments
 
 error[E0718]: `phantom_data` lang item must be applied to a struct with 1 generic argument
-  --> $DIR/lang-item-generic-requirements.rs:22:1
+  --> $DIR/lang-item-generic-requirements.rs:28:1
    |
 LL | #[lang = "phantom_data"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -33,7 +33,7 @@ LL | struct MyPhantomData<T, U>;
    |                     ------ this struct has 2 generic arguments
 
 error[E0718]: `owned_box` lang item must be applied to a struct with at least 1 generic argument
-  --> $DIR/lang-item-generic-requirements.rs:28:1
+  --> $DIR/lang-item-generic-requirements.rs:34:1
    |
 LL | #[lang = "owned_box"]
    | ^^^^^^^^^^^^^^^^^^^^^
@@ -42,7 +42,7 @@ LL | struct Foo;
    |           - this struct has 0 generic arguments
 
 error[E0718]: `start` lang item must be applied to a function with 1 generic argument
-  --> $DIR/lang-item-generic-requirements.rs:34:1
+  --> $DIR/lang-item-generic-requirements.rs:40:1
    |
 LL | #[lang = "start"]
    | ^^^^^^^^^^^^^^^^^
@@ -51,7 +51,7 @@ LL | fn start(_: *const u8, _: isize, _: *const *const u8) -> isize {
    |         - this function has 0 generic arguments
 
 error[E0392]: type parameter `T` is never used
-  --> $DIR/lang-item-generic-requirements.rs:24:22
+  --> $DIR/lang-item-generic-requirements.rs:30:22
    |
 LL | struct MyPhantomData<T, U>;
    |                      ^ unused type parameter
@@ -60,7 +60,7 @@ LL | struct MyPhantomData<T, U>;
    = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
 
 error[E0392]: type parameter `U` is never used
-  --> $DIR/lang-item-generic-requirements.rs:24:25
+  --> $DIR/lang-item-generic-requirements.rs:30:25
    |
 LL | struct MyPhantomData<T, U>;
    |                         ^ unused type parameter
@@ -69,7 +69,7 @@ LL | struct MyPhantomData<T, U>;
    = help: if you intended `U` to be a const parameter, use `const U: /* Type */` instead
 
 error[E0369]: cannot add `{integer}` to `{integer}`
-  --> $DIR/lang-item-generic-requirements.rs:44:7
+  --> $DIR/lang-item-generic-requirements.rs:50:7
    |
 LL |     r + a;
    |     - ^ - {integer}
@@ -77,13 +77,13 @@ LL |     r + a;
    |     {integer}
 
 error[E0608]: cannot index into a value of type `[{integer}; 5]`
-  --> $DIR/lang-item-generic-requirements.rs:52:16
+  --> $DIR/lang-item-generic-requirements.rs:58:16
    |
 LL |     let _ = arr[2];
    |                ^^^
 
 error[E0308]: mismatched types
-  --> $DIR/lang-item-generic-requirements.rs:59:17
+  --> $DIR/lang-item-generic-requirements.rs:65:17
    |
 LL |     let _: () = Foo;
    |            --   ^^^ expected `()`, found `Foo`
@@ -91,7 +91,7 @@ LL |     let _: () = Foo;
    |            expected due to this
 
 error: requires `copy` lang_item
-  --> $DIR/lang-item-generic-requirements.rs:50:16
+  --> $DIR/lang-item-generic-requirements.rs:56:16
    |
 LL |     let arr = [0; 5];
    |                ^
diff --git a/tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs b/tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs
index f92a00e602c..35d5d079c68 100644
--- a/tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs
+++ b/tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs
@@ -2,8 +2,14 @@
 #![no_core]
 #![no_main]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized { }
+trait Sized: MetaSized { }
 
 struct S;
 
diff --git a/tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr b/tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr
index 9b25b1db292..7b9541f734f 100644
--- a/tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr
+++ b/tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr
@@ -1,5 +1,5 @@
 error: requires `copy` lang_item
-  --> $DIR/missing-copy-lang-item-issue-19660.rs:12:5
+  --> $DIR/missing-copy-lang-item-issue-19660.rs:18:5
    |
 LL |     argc
    |     ^^^^
diff --git a/tests/ui/lang-items/start_lang_item_args.argc.stderr b/tests/ui/lang-items/start_lang_item_args.argc.stderr
index cd7361255eb..82fd374a1c5 100644
--- a/tests/ui/lang-items/start_lang_item_args.argc.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.argc.stderr
@@ -1,5 +1,5 @@
 error[E0308]: lang item `start` function has wrong type
-  --> $DIR/start_lang_item_args.rs:75:38
+  --> $DIR/start_lang_item_args.rs:79:38
    |
 LL | fn start<T>(_main: fn() -> T, _argc: i8, _argv: *const *const u8, _sigpipe: u8) -> isize {
    |                                      ^^ expected `isize`, found `i8`
diff --git a/tests/ui/lang-items/start_lang_item_args.argv.stderr b/tests/ui/lang-items/start_lang_item_args.argv.stderr
index 1a5905ab8e6..6095f8fa532 100644
--- a/tests/ui/lang-items/start_lang_item_args.argv.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.argv.stderr
@@ -1,5 +1,5 @@
 error[E0308]: lang item `start` function has wrong type
-  --> $DIR/start_lang_item_args.rs:89:52
+  --> $DIR/start_lang_item_args.rs:93:52
    |
 LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: u8, _sigpipe: u8) -> isize {
    |                                                    ^^ expected `*const *const u8`, found `u8`
diff --git a/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr b/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr
index c61ace3cd62..2a295c8990b 100644
--- a/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.argv_inner_ptr.stderr
@@ -1,5 +1,5 @@
 error[E0308]: lang item `start` function has wrong type
-  --> $DIR/start_lang_item_args.rs:82:52
+  --> $DIR/start_lang_item_args.rs:86:52
    |
 LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const usize, _sigpipe: u8) -> isize {
    |                                                    ^^^^^^^^^^^^^^^^^^^ expected `u8`, found `usize`
diff --git a/tests/ui/lang-items/start_lang_item_args.main_args.stderr b/tests/ui/lang-items/start_lang_item_args.main_args.stderr
index ef943d6b3db..027fd16d410 100644
--- a/tests/ui/lang-items/start_lang_item_args.main_args.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.main_args.stderr
@@ -1,5 +1,5 @@
 error[E0308]: lang item `start` function has wrong type
-  --> $DIR/start_lang_item_args.rs:61:1
+  --> $DIR/start_lang_item_args.rs:65:1
    |
 LL | fn start<T>(_main: fn(i32) -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
diff --git a/tests/ui/lang-items/start_lang_item_args.main_ret.stderr b/tests/ui/lang-items/start_lang_item_args.main_ret.stderr
index 00395a05d33..0f295d350d1 100644
--- a/tests/ui/lang-items/start_lang_item_args.main_ret.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.main_ret.stderr
@@ -1,5 +1,5 @@
 error[E0308]: lang item `start` function has wrong type
-  --> $DIR/start_lang_item_args.rs:68:20
+  --> $DIR/start_lang_item_args.rs:72:20
    |
 LL | fn start<T>(_main: fn() -> u16, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
    |          -         ^^^^^^^^^^^ expected type parameter `T`, found `u16`
diff --git a/tests/ui/lang-items/start_lang_item_args.main_ty.stderr b/tests/ui/lang-items/start_lang_item_args.main_ty.stderr
index 193f25bab05..6e462c8b1a7 100644
--- a/tests/ui/lang-items/start_lang_item_args.main_ty.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.main_ty.stderr
@@ -1,5 +1,5 @@
 error[E0308]: lang item `start` function has wrong type
-  --> $DIR/start_lang_item_args.rs:54:20
+  --> $DIR/start_lang_item_args.rs:58:20
    |
 LL | fn start<T>(_main: u64, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
    |                    ^^^ expected fn pointer, found `u64`
diff --git a/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr b/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr
index 56b787d2ae3..90fa5e0d575 100644
--- a/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.missing_all_args.stderr
@@ -1,5 +1,5 @@
 error[E0308]: lang item `start` function has wrong type
-  --> $DIR/start_lang_item_args.rs:15:1
+  --> $DIR/start_lang_item_args.rs:19:1
    |
 LL | fn start<T>() -> isize {
    | ^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
diff --git a/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr b/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr
index 2672efe51c9..879917cc800 100644
--- a/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.missing_ret.stderr
@@ -1,5 +1,5 @@
 error[E0308]: lang item `start` function has wrong type
-  --> $DIR/start_lang_item_args.rs:29:83
+  --> $DIR/start_lang_item_args.rs:33:83
    |
 LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
    |                                                                                   ^ expected `isize`, found `()`
diff --git a/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr b/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr
index 98814dcd24a..d756909d735 100644
--- a/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.missing_sigpipe_arg.stderr
@@ -1,5 +1,5 @@
 error[E0308]: lang item `start` function has wrong type
-  --> $DIR/start_lang_item_args.rs:22:1
+  --> $DIR/start_lang_item_args.rs:26:1
    |
 LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize {
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters
diff --git a/tests/ui/lang-items/start_lang_item_args.rs b/tests/ui/lang-items/start_lang_item_args.rs
index 5bb99e2adc8..1da761545a8 100644
--- a/tests/ui/lang-items/start_lang_item_args.rs
+++ b/tests/ui/lang-items/start_lang_item_args.rs
@@ -8,7 +8,11 @@
 #[lang = "copy"]
 pub trait Copy {}
 #[lang = "sized"]
-pub trait Sized {}
+pub trait Sized: MetaSized {}
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
 
 #[cfg(missing_all_args)]
 #[lang = "start"]
diff --git a/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr b/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr
index e0a8496dba9..ba1dd4b4f79 100644
--- a/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.sigpipe.stderr
@@ -1,5 +1,5 @@
 error[E0308]: lang item `start` function has wrong type
-  --> $DIR/start_lang_item_args.rs:96:80
+  --> $DIR/start_lang_item_args.rs:100:80
    |
 LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: i64) -> isize {
    |                                                                                ^^^ expected `u8`, found `i64`
diff --git a/tests/ui/lang-items/start_lang_item_args.start_ret.stderr b/tests/ui/lang-items/start_lang_item_args.start_ret.stderr
index 4437b0fdcfb..a11867997d3 100644
--- a/tests/ui/lang-items/start_lang_item_args.start_ret.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.start_ret.stderr
@@ -1,5 +1,5 @@
 error[E0308]: lang item `start` function has wrong type
-  --> $DIR/start_lang_item_args.rs:34:87
+  --> $DIR/start_lang_item_args.rs:38:87
    |
 LL | fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> u8 {
    |                                                                                       ^^ expected `isize`, found `u8`
diff --git a/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr b/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr
index 8570d96fc62..ecccf8c74bc 100644
--- a/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr
+++ b/tests/ui/lang-items/start_lang_item_args.too_many_args.stderr
@@ -1,5 +1,5 @@
 error[E0308]: lang item `start` function has wrong type
-  --> $DIR/start_lang_item_args.rs:41:1
+  --> $DIR/start_lang_item_args.rs:45:1
    |
 LL | / fn start<T>(
 LL | |
diff --git a/tests/ui/lang-items/start_lang_item_with_target_feature.rs b/tests/ui/lang-items/start_lang_item_with_target_feature.rs
index 18cd4c97040..19036819d3d 100644
--- a/tests/ui/lang-items/start_lang_item_with_target_feature.rs
+++ b/tests/ui/lang-items/start_lang_item_with_target_feature.rs
@@ -6,8 +6,15 @@
 
 #[lang = "copy"]
 pub trait Copy {}
+
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-pub trait Sized {}
+pub trait Sized: MetaSized {}
 
 #[lang = "start"]
 #[target_feature(enable = "avx2")]
diff --git a/tests/ui/lang-items/start_lang_item_with_target_feature.stderr b/tests/ui/lang-items/start_lang_item_with_target_feature.stderr
index 6214e3f8bc7..ce0b1d75574 100644
--- a/tests/ui/lang-items/start_lang_item_with_target_feature.stderr
+++ b/tests/ui/lang-items/start_lang_item_with_target_feature.stderr
@@ -1,5 +1,5 @@
 error: `start` lang item function is not allowed to have `#[target_feature]`
-  --> $DIR/start_lang_item_with_target_feature.rs:13:1
+  --> $DIR/start_lang_item_with_target_feature.rs:20:1
    |
 LL | #[target_feature(enable = "avx2")]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/layout/unconstrained-param-ice-137308.rs b/tests/ui/layout/unconstrained-param-ice-137308.rs
index c9b1e0a4b9e..03b7e759960 100644
--- a/tests/ui/layout/unconstrained-param-ice-137308.rs
+++ b/tests/ui/layout/unconstrained-param-ice-137308.rs
@@ -15,4 +15,6 @@ impl<C: ?Sized> A for u8 { //~ ERROR: the type parameter `C` is not constrained
 }
 
 #[rustc_layout(debug)]
-struct S([u8; <u8 as A>::B]); //~ ERROR: the type has an unknown layout
+struct S([u8; <u8 as A>::B]);
+//~^ ERROR: the type has an unknown layout
+//~| ERROR: type annotations needed
diff --git a/tests/ui/layout/unconstrained-param-ice-137308.stderr b/tests/ui/layout/unconstrained-param-ice-137308.stderr
index 615c131eb90..82cd1217c49 100644
--- a/tests/ui/layout/unconstrained-param-ice-137308.stderr
+++ b/tests/ui/layout/unconstrained-param-ice-137308.stderr
@@ -4,12 +4,19 @@ error[E0207]: the type parameter `C` is not constrained by the impl trait, self
 LL | impl<C: ?Sized> A for u8 {
    |      ^ unconstrained type parameter
 
+error[E0282]: type annotations needed
+  --> $DIR/unconstrained-param-ice-137308.rs:18:16
+   |
+LL | struct S([u8; <u8 as A>::B]);
+   |                ^^ cannot infer type for type parameter `C`
+
 error: the type has an unknown layout
   --> $DIR/unconstrained-param-ice-137308.rs:18:1
    |
 LL | struct S([u8; <u8 as A>::B]);
    | ^^^^^^^^
 
-error: aborting due to 2 previous errors
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0207`.
+Some errors have detailed explanations: E0207, E0282.
+For more information about an error, try `rustc --explain E0207`.
diff --git a/tests/ui/lint/redundant-semicolon/suggest-remove-semi-in-macro-expansion-issue-142143.rs b/tests/ui/lint/redundant-semicolon/suggest-remove-semi-in-macro-expansion-issue-142143.rs
new file mode 100644
index 00000000000..4360eb964a4
--- /dev/null
+++ b/tests/ui/lint/redundant-semicolon/suggest-remove-semi-in-macro-expansion-issue-142143.rs
@@ -0,0 +1,11 @@
+// Make sure we don't suggest remove redundant semicolon inside macro expansion.(issue #142143)
+
+#![deny(redundant_semicolons)]
+
+macro_rules! m {
+    ($stmt:stmt) => { #[allow(bad_style)] $stmt } //~ ERROR unnecessary trailing semicolon [redundant_semicolons]
+}
+
+fn main() {
+    m!(;);
+}
diff --git a/tests/ui/lint/redundant-semicolon/suggest-remove-semi-in-macro-expansion-issue-142143.stderr b/tests/ui/lint/redundant-semicolon/suggest-remove-semi-in-macro-expansion-issue-142143.stderr
new file mode 100644
index 00000000000..7a38ec318ab
--- /dev/null
+++ b/tests/ui/lint/redundant-semicolon/suggest-remove-semi-in-macro-expansion-issue-142143.stderr
@@ -0,0 +1,18 @@
+error: unnecessary trailing semicolon
+  --> $DIR/suggest-remove-semi-in-macro-expansion-issue-142143.rs:6:43
+   |
+LL |     ($stmt:stmt) => { #[allow(bad_style)] $stmt }
+   |                                           ^^^^^
+...
+LL |     m!(;);
+   |     ----- in this macro invocation
+   |
+note: the lint level is defined here
+  --> $DIR/suggest-remove-semi-in-macro-expansion-issue-142143.rs:3:9
+   |
+LL | #![deny(redundant_semicolons)]
+   |         ^^^^^^^^^^^^^^^^^^^^
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr
index 769b174874b..e1c45e832af 100644
--- a/tests/ui/lint/unused/unused-attr-duplicate.stderr
+++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr
@@ -103,19 +103,6 @@ LL | #[automatically_derived]
    | ^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: unused attribute
-  --> $DIR/unused-attr-duplicate.rs:74:1
-   |
-LL | #[inline(never)]
-   | ^^^^^^^^^^^^^^^^ help: remove this attribute
-   |
-note: attribute also specified here
-  --> $DIR/unused-attr-duplicate.rs:73:1
-   |
-LL | #[inline(always)]
-   | ^^^^^^^^^^^^^^^^^
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-
-error: unused attribute
   --> $DIR/unused-attr-duplicate.rs:77:1
    |
 LL | #[cold]
@@ -289,5 +276,18 @@ note: attribute also specified here
 LL |     #[macro_export]
    |     ^^^^^^^^^^^^^^^
 
+error: unused attribute
+  --> $DIR/unused-attr-duplicate.rs:74:1
+   |
+LL | #[inline(never)]
+   | ^^^^^^^^^^^^^^^^ help: remove this attribute
+   |
+note: attribute also specified here
+  --> $DIR/unused-attr-duplicate.rs:73:1
+   |
+LL | #[inline(always)]
+   | ^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
 error: aborting due to 23 previous errors
 
diff --git a/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout b/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout
index 6b41eb530db..7c41225f95e 100644
--- a/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout
+++ b/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout
@@ -8,7 +8,7 @@ extern crate std;
 // issue#97006
 
 macro_rules! m { ($attr_path: path) => { #[$attr_path] fn f() {} } }
-#[inline]
+#[attr = Inline(Hint)]
 fn f() { }
 
 fn main() { }
diff --git a/tests/ui/malformed/malformed-regressions.stderr b/tests/ui/malformed/malformed-regressions.stderr
index e1dbdb9ab3c..535db55a13d 100644
--- a/tests/ui/malformed/malformed-regressions.stderr
+++ b/tests/ui/malformed/malformed-regressions.stderr
@@ -17,15 +17,6 @@ LL | #[ignore()]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
 
-error: valid forms for the attribute are `#[inline]` and `#[inline(always|never)]`
-  --> $DIR/malformed-regressions.rs:5:1
-   |
-LL | #[inline = ""]
-   | ^^^^^^^^^^^^^^
-   |
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
-
 error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]`
   --> $DIR/malformed-regressions.rs:7:1
    |
@@ -44,5 +35,14 @@ LL | #[link = ""]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
 
+error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]`
+  --> $DIR/malformed-regressions.rs:5:1
+   |
+LL | #[inline = ""]
+   | ^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
+
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/nll/issue-50716.rs b/tests/ui/nll/issue-50716.rs
index c2fc345fa2b..76c6fc5e7b9 100644
--- a/tests/ui/nll/issue-50716.rs
+++ b/tests/ui/nll/issue-50716.rs
@@ -1,4 +1,3 @@
-//
 // Regression test for the issue #50716: NLL ignores lifetimes bounds
 // derived from `Sized` requirements
 
@@ -6,7 +5,7 @@ trait A {
     type X: ?Sized;
 }
 
-fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>)
+fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>) //~ ERROR
 where
     for<'b> &'b T: A,
     <&'static T as A>::X: Sized
diff --git a/tests/ui/nll/issue-50716.stderr b/tests/ui/nll/issue-50716.stderr
index a09e7670515..edd7fd765da 100644
--- a/tests/ui/nll/issue-50716.stderr
+++ b/tests/ui/nll/issue-50716.stderr
@@ -1,5 +1,20 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-50716.rs:8:27
+   |
+LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>)
+   |                           ^^^^^^^^^^^^^^^^^^^^ lifetime mismatch
+   |
+   = note: expected trait `<<&'a T as A>::X as MetaSized>`
+              found trait `<<&'static T as A>::X as MetaSized>`
+note: the lifetime `'a` as defined here...
+  --> $DIR/issue-50716.rs:8:8
+   |
+LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>)
+   |        ^^
+   = note: ...does not necessarily outlive the static lifetime
+
 error: lifetime may not live long enough
-  --> $DIR/issue-50716.rs:14:14
+  --> $DIR/issue-50716.rs:13:14
    |
 LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>)
    |        -- lifetime `'a` defined here
@@ -7,5 +22,6 @@ LL | fn foo<'a, T: 'static>(s: Box<<&'a T as A>::X>)
 LL |     let _x = *s;
    |              ^^ proving this value is `Sized` requires that `'a` must outlive `'static`
 
-error: aborting due to 1 previous error
+error: aborting due to 2 previous errors
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/offset-of/offset-of-dst-field.rs b/tests/ui/offset-of/offset-of-dst-field.rs
index 2e0bdb151e1..575a66fe302 100644
--- a/tests/ui/offset-of/offset-of-dst-field.rs
+++ b/tests/ui/offset-of/offset-of-dst-field.rs
@@ -1,5 +1,6 @@
-#![feature(extern_types)]
+#![feature(extern_types, sized_hierarchy)]
 
+use std::marker::PointeeSized;
 use std::mem::offset_of;
 
 struct Alpha {
@@ -26,7 +27,7 @@ struct Gamma {
     z: Extern,
 }
 
-struct Delta<T: ?Sized> {
+struct Delta<T: PointeeSized> {
     x: u8,
     y: u16,
     z: T,
diff --git a/tests/ui/offset-of/offset-of-dst-field.stderr b/tests/ui/offset-of/offset-of-dst-field.stderr
index 714bf7a0266..0953e86e222 100644
--- a/tests/ui/offset-of/offset-of-dst-field.stderr
+++ b/tests/ui/offset-of/offset-of-dst-field.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
-  --> $DIR/offset-of-dst-field.rs:36:5
+  --> $DIR/offset-of-dst-field.rs:37:5
    |
 LL |     offset_of!(Alpha, z);
    |     ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -8,7 +8,7 @@ LL |     offset_of!(Alpha, z);
    = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time
-  --> $DIR/offset-of-dst-field.rs:37:5
+  --> $DIR/offset-of-dst-field.rs:38:5
    |
 LL |     offset_of!(Beta, z);
    |     ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -17,7 +17,7 @@ LL |     offset_of!(Beta, z);
    = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the size for values of type `Extern` cannot be known at compilation time
-  --> $DIR/offset-of-dst-field.rs:38:5
+  --> $DIR/offset-of-dst-field.rs:39:5
    |
 LL |     offset_of!(Gamma, z);
    |     ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -26,7 +26,7 @@ LL |     offset_of!(Gamma, z);
    = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time
-  --> $DIR/offset-of-dst-field.rs:40:5
+  --> $DIR/offset-of-dst-field.rs:41:5
    |
 LL |     offset_of!((u8, dyn Trait), 1);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -35,7 +35,7 @@ LL |     offset_of!((u8, dyn Trait), 1);
    = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the size for values of type `Extern` cannot be known at compilation time
-  --> $DIR/offset-of-dst-field.rs:45:5
+  --> $DIR/offset-of-dst-field.rs:46:5
    |
 LL |     offset_of!(Delta<Extern>, z);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -44,7 +44,7 @@ LL |     offset_of!(Delta<Extern>, z);
    = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time
-  --> $DIR/offset-of-dst-field.rs:46:5
+  --> $DIR/offset-of-dst-field.rs:47:5
    |
 LL |     offset_of!(Delta<dyn Trait>, z);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
@@ -53,21 +53,21 @@ LL |     offset_of!(Delta<dyn Trait>, z);
    = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
-  --> $DIR/offset-of-dst-field.rs:44:5
+  --> $DIR/offset-of-dst-field.rs:45:5
    |
 LL |     offset_of!(Delta<Alpha>, z);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
    = help: within `Alpha`, the trait `Sized` is not implemented for `[u8]`
 note: required because it appears within the type `Alpha`
-  --> $DIR/offset-of-dst-field.rs:5:8
+  --> $DIR/offset-of-dst-field.rs:6:8
    |
 LL | struct Alpha {
    |        ^^^^^
    = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0277]: the size for values of type `T` cannot be known at compilation time
-  --> $DIR/offset-of-dst-field.rs:50:5
+  --> $DIR/offset-of-dst-field.rs:51:5
    |
 LL | fn generic_with_maybe_sized<T: ?Sized>() -> usize {
    |                             - this type parameter needs to be `Sized`
@@ -82,7 +82,7 @@ LL + fn generic_with_maybe_sized<T>() -> usize {
    |
 
 error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
-  --> $DIR/offset-of-dst-field.rs:54:16
+  --> $DIR/offset-of-dst-field.rs:55:16
    |
 LL |     offset_of!(([u8], u8), 1);
    |                ^^^^^^^^^^ doesn't have a size known at compile-time
diff --git a/tests/ui/panic-handler/panic-handler-requires-panic-info.rs b/tests/ui/panic-handler/panic-handler-requires-panic-info.rs
index 0b8308ba753..618ac7d88dd 100644
--- a/tests/ui/panic-handler/panic-handler-requires-panic-info.rs
+++ b/tests/ui/panic-handler/panic-handler-requires-panic-info.rs
@@ -11,5 +11,11 @@ fn panic() -> ! {
     loop {}
 }
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+trait Sized: MetaSized {}
diff --git a/tests/ui/parser/doc-comment-after-missing-comma-issue-142311.rs b/tests/ui/parser/doc-comment-after-missing-comma-issue-142311.rs
new file mode 100644
index 00000000000..7ac6fa127f4
--- /dev/null
+++ b/tests/ui/parser/doc-comment-after-missing-comma-issue-142311.rs
@@ -0,0 +1,34 @@
+//! Check that if the parser suggests converting `///` to a regular comment
+//! when it appears after a missing comma in an list (e.g. `enum` variants).
+//!
+//! Related issue
+//! - https://github.com/rust-lang/rust/issues/142311
+
+enum Foo {
+    /// Like the noise a sheep makes
+    Bar
+    /// Like where people drink
+    //~^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found doc comment `/// Like where people drink`
+    Baa///xxxxxx
+    //~^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found doc comment `///xxxxxx`
+    Baz///xxxxxx
+    //~^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found doc comment `///xxxxxx`
+}
+
+fn foo() {
+    let a = [
+        1///xxxxxx
+        //~^ ERROR expected one of `,`, `.`, `;`, `?`, `]`, or an operator, found doc comment `///xxxxxx`
+        2
+    ];
+}
+
+fn bar() {
+    let a = [
+        1,
+        2///xxxxxx
+        //~^ ERROR expected one of `,`, `.`, `?`, `]`, or an operator, found doc comment `///xxxxxx`
+    ];
+}
+
+fn main() {}
diff --git a/tests/ui/parser/doc-comment-after-missing-comma-issue-142311.stderr b/tests/ui/parser/doc-comment-after-missing-comma-issue-142311.stderr
new file mode 100644
index 00000000000..d95cecfc560
--- /dev/null
+++ b/tests/ui/parser/doc-comment-after-missing-comma-issue-142311.stderr
@@ -0,0 +1,43 @@
+error: expected one of `(`, `,`, `=`, `{`, or `}`, found doc comment `/// Like where people drink`
+  --> $DIR/doc-comment-after-missing-comma-issue-142311.rs:10:5
+   |
+LL |     Bar
+   |        -
+   |        |
+   |        expected one of `(`, `,`, `=`, `{`, or `}`
+   |        help: missing `,`
+LL |     /// Like where people drink
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ unexpected token
+
+error: expected one of `(`, `,`, `=`, `{`, or `}`, found doc comment `///xxxxxx`
+  --> $DIR/doc-comment-after-missing-comma-issue-142311.rs:12:8
+   |
+LL |     Baa///xxxxxx
+   |        -^^^^^^^^
+   |        |
+   |        expected one of `(`, `,`, `=`, `{`, or `}`
+   |        help: missing `,`
+
+error: expected one of `(`, `,`, `=`, `{`, or `}`, found doc comment `///xxxxxx`
+  --> $DIR/doc-comment-after-missing-comma-issue-142311.rs:14:8
+   |
+LL |     Baz///xxxxxx
+   |        ^^^^^^^^^ expected one of `(`, `,`, `=`, `{`, or `}`
+   |
+   = help: doc comments must come before what they document, if a comment was intended use `//`
+   = help: enum variants can be `Variant`, `Variant = <integer>`, `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`
+
+error: expected one of `,`, `.`, `;`, `?`, `]`, or an operator, found doc comment `///xxxxxx`
+  --> $DIR/doc-comment-after-missing-comma-issue-142311.rs:20:10
+   |
+LL |         1///xxxxxx
+   |          ^^^^^^^^^ expected one of `,`, `.`, `;`, `?`, `]`, or an operator
+
+error: expected one of `,`, `.`, `?`, `]`, or an operator, found doc comment `///xxxxxx`
+  --> $DIR/doc-comment-after-missing-comma-issue-142311.rs:29:10
+   |
+LL |         2///xxxxxx
+   |          ^^^^^^^^^ expected one of `,`, `.`, `?`, `]`, or an operator
+
+error: aborting due to 5 previous errors
+
diff --git a/tests/ui/print-request/emit-warning-print-link-info-without-staticlib.rs b/tests/ui/print-request/emit-warning-print-link-info-without-staticlib.rs
deleted file mode 100644
index b100c062bba..00000000000
--- a/tests/ui/print-request/emit-warning-print-link-info-without-staticlib.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-//@ compile-flags: --print native-static-libs
-//@ check-pass
-//~? WARN cannot output linkage information without staticlib crate-type
-
-fn main() {}
diff --git a/tests/ui/print-request/emit-warning-print-link-info-without-staticlib.stderr b/tests/ui/print-request/emit-warning-print-link-info-without-staticlib.stderr
deleted file mode 100644
index ceff08baa13..00000000000
--- a/tests/ui/print-request/emit-warning-print-link-info-without-staticlib.stderr
+++ /dev/null
@@ -1,6 +0,0 @@
-warning: cannot output linkage information without staticlib crate-type
-
-note: consider `--crate-type staticlib` to print linkage information
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/print-request/emit-warning-while-exe-and-print-link-info.rs b/tests/ui/print-request/emit-warning-while-exe-and-print-link-info.rs
deleted file mode 100644
index 3e9ca457a9c..00000000000
--- a/tests/ui/print-request/emit-warning-while-exe-and-print-link-info.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-//@ compile-flags: --print native-static-libs --crate-type staticlib  --emit metadata
-//@ check-pass
-//~? WARN cannot output linkage information when --emit link is not passed
diff --git a/tests/ui/print-request/emit-warning-while-exe-and-print-link-info.stderr b/tests/ui/print-request/emit-warning-while-exe-and-print-link-info.stderr
deleted file mode 100644
index b32e1437d6b..00000000000
--- a/tests/ui/print-request/emit-warning-while-exe-and-print-link-info.stderr
+++ /dev/null
@@ -1,4 +0,0 @@
-warning: cannot output linkage information when --emit link is not passed
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/print-request/stability.rs b/tests/ui/print-request/stability.rs
index fbcdf916cc7..54142ce78ce 100644
--- a/tests/ui/print-request/stability.rs
+++ b/tests/ui/print-request/stability.rs
@@ -110,4 +110,3 @@ fn main() {}
 //[check_cfg]~? ERROR the `-Z unstable-options` flag must also be passed to enable the `check-cfg` print option
 //[supported_crate_types]~? ERROR the `-Z unstable-options` flag must also be passed to enable the `supported-crate-types` print option
 //[target_spec_json]~? ERROR the `-Z unstable-options` flag must also be passed to enable the `target-spec-json` print option
-//[native_static_libs]~? WARNING cannot output linkage information without staticlib crate-type
diff --git a/tests/ui/privacy/privacy1.rs b/tests/ui/privacy/privacy1.rs
index 6cd12b80782..16aacd81289 100644
--- a/tests/ui/privacy/privacy1.rs
+++ b/tests/ui/privacy/privacy1.rs
@@ -1,8 +1,14 @@
 #![feature(lang_items, no_core)]
 #![no_core] // makes debugging this test *a lot* easier (during resolve)
 
-#[lang="sized"]
-pub trait Sized {}
+#[lang = "sized"]
+pub trait Sized: MetaSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
 
 #[lang="copy"]
 pub trait Copy {}
diff --git a/tests/ui/privacy/privacy1.stderr b/tests/ui/privacy/privacy1.stderr
index 1f2f4a92c48..98750cee610 100644
--- a/tests/ui/privacy/privacy1.stderr
+++ b/tests/ui/privacy/privacy1.stderr
@@ -1,54 +1,54 @@
 error[E0603]: module `baz` is private
-  --> $DIR/privacy1.rs:132:18
+  --> $DIR/privacy1.rs:138:18
    |
 LL |         use bar::baz::{foo, bar};
    |                  ^^^ private module
    |
 note: the module `baz` is defined here
-  --> $DIR/privacy1.rs:50:5
+  --> $DIR/privacy1.rs:56:5
    |
 LL |     mod baz {
    |     ^^^^^^^
 
 error[E0603]: module `baz` is private
-  --> $DIR/privacy1.rs:132:18
+  --> $DIR/privacy1.rs:138:18
    |
 LL |         use bar::baz::{foo, bar};
    |                  ^^^ private module
    |
 note: the module `baz` is defined here
-  --> $DIR/privacy1.rs:50:5
+  --> $DIR/privacy1.rs:56:5
    |
 LL |     mod baz {
    |     ^^^^^^^
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error[E0603]: module `baz` is private
-  --> $DIR/privacy1.rs:141:18
+  --> $DIR/privacy1.rs:147:18
    |
 LL |         use bar::baz;
    |                  ^^^ private module
    |
 note: the module `baz` is defined here
-  --> $DIR/privacy1.rs:50:5
+  --> $DIR/privacy1.rs:56:5
    |
 LL |     mod baz {
    |     ^^^^^^^
 
 error[E0603]: module `i` is private
-  --> $DIR/privacy1.rs:165:20
+  --> $DIR/privacy1.rs:171:20
    |
 LL |     use self::foo::i::A;
    |                    ^ private module
    |
 note: the module `i` is defined here
-  --> $DIR/privacy1.rs:170:9
+  --> $DIR/privacy1.rs:176:9
    |
 LL |         mod i {
    |         ^^^^^
 
 error[E0603]: module `baz` is private
-  --> $DIR/privacy1.rs:104:21
+  --> $DIR/privacy1.rs:110:21
    |
 LL |         crate::bar::baz::A::foo();
    |                     ^^^  - struct `A` is not publicly re-exported
@@ -56,13 +56,13 @@ LL |         crate::bar::baz::A::foo();
    |                     private module
    |
 note: the module `baz` is defined here
-  --> $DIR/privacy1.rs:50:5
+  --> $DIR/privacy1.rs:56:5
    |
 LL |     mod baz {
    |     ^^^^^^^
 
 error[E0603]: module `baz` is private
-  --> $DIR/privacy1.rs:105:21
+  --> $DIR/privacy1.rs:111:21
    |
 LL |         crate::bar::baz::A::bar();
    |                     ^^^  - struct `A` is not publicly re-exported
@@ -70,13 +70,13 @@ LL |         crate::bar::baz::A::bar();
    |                     private module
    |
 note: the module `baz` is defined here
-  --> $DIR/privacy1.rs:50:5
+  --> $DIR/privacy1.rs:56:5
    |
 LL |     mod baz {
    |     ^^^^^^^
 
 error[E0603]: module `baz` is private
-  --> $DIR/privacy1.rs:107:21
+  --> $DIR/privacy1.rs:113:21
    |
 LL |         crate::bar::baz::A.foo2();
    |                     ^^^  - unit struct `A` is not publicly re-exported
@@ -84,13 +84,13 @@ LL |         crate::bar::baz::A.foo2();
    |                     private module
    |
 note: the module `baz` is defined here
-  --> $DIR/privacy1.rs:50:5
+  --> $DIR/privacy1.rs:56:5
    |
 LL |     mod baz {
    |     ^^^^^^^
 
 error[E0603]: module `baz` is private
-  --> $DIR/privacy1.rs:108:21
+  --> $DIR/privacy1.rs:114:21
    |
 LL |         crate::bar::baz::A.bar2();
    |                     ^^^  - unit struct `A` is not publicly re-exported
@@ -98,13 +98,13 @@ LL |         crate::bar::baz::A.bar2();
    |                     private module
    |
 note: the module `baz` is defined here
-  --> $DIR/privacy1.rs:50:5
+  --> $DIR/privacy1.rs:56:5
    |
 LL |     mod baz {
    |     ^^^^^^^
 
 error[E0603]: trait `B` is private
-  --> $DIR/privacy1.rs:112:21
+  --> $DIR/privacy1.rs:118:21
    |
 LL |         crate::bar::B::foo();
    |                     ^  --- associated function `foo` is not publicly re-exported
@@ -112,31 +112,31 @@ LL |         crate::bar::B::foo();
    |                     private trait
    |
 note: the trait `B` is defined here
-  --> $DIR/privacy1.rs:40:5
+  --> $DIR/privacy1.rs:46:5
    |
 LL |     trait B {
    |     ^^^^^^^
 
 error[E0603]: function `epriv` is private
-  --> $DIR/privacy1.rs:118:25
+  --> $DIR/privacy1.rs:124:25
    |
 LL |             crate::bar::epriv();
    |                         ^^^^^ private function
    |
 note: the function `epriv` is defined here
-  --> $DIR/privacy1.rs:65:9
+  --> $DIR/privacy1.rs:71:9
    |
 LL |         fn epriv();
    |         ^^^^^^^^^^^
 
 error[E0603]: module `baz` is private
-  --> $DIR/privacy1.rs:127:21
+  --> $DIR/privacy1.rs:133:21
    |
 LL |         crate::bar::baz::foo();
    |                     ^^^ private module
    |
 note: the module `baz` is defined here
-  --> $DIR/privacy1.rs:50:5
+  --> $DIR/privacy1.rs:56:5
    |
 LL |     mod baz {
    |     ^^^^^^^
@@ -147,13 +147,13 @@ LL +         bar::foo();
    |
 
 error[E0603]: module `baz` is private
-  --> $DIR/privacy1.rs:128:21
+  --> $DIR/privacy1.rs:134:21
    |
 LL |         crate::bar::baz::bar();
    |                     ^^^ private module
    |
 note: the module `baz` is defined here
-  --> $DIR/privacy1.rs:50:5
+  --> $DIR/privacy1.rs:56:5
    |
 LL |     mod baz {
    |     ^^^^^^^
@@ -164,19 +164,19 @@ LL +         bar::bar();
    |
 
 error[E0603]: trait `B` is private
-  --> $DIR/privacy1.rs:157:22
+  --> $DIR/privacy1.rs:163:22
    |
 LL |     impl crate::bar::B for f32 { fn foo() -> f32 { 1.0 } }
    |                      ^ private trait
    |
 note: the trait `B` is defined here
-  --> $DIR/privacy1.rs:40:5
+  --> $DIR/privacy1.rs:46:5
    |
 LL |     trait B {
    |     ^^^^^^^
 
 error[E0624]: associated function `bar` is private
-  --> $DIR/privacy1.rs:77:23
+  --> $DIR/privacy1.rs:83:23
    |
 LL |             fn bar() {}
    |             -------- private associated function defined here
@@ -185,7 +185,7 @@ LL |         self::baz::A::bar();
    |                       ^^^ private associated function
 
 error[E0624]: associated function `bar` is private
-  --> $DIR/privacy1.rs:95:13
+  --> $DIR/privacy1.rs:101:13
    |
 LL |         fn bar() {}
    |         -------- private associated function defined here
@@ -194,7 +194,7 @@ LL |     bar::A::bar();
    |             ^^^ private associated function
 
 error[E0624]: associated function `bar` is private
-  --> $DIR/privacy1.rs:102:24
+  --> $DIR/privacy1.rs:108:24
    |
 LL |         fn bar() {}
    |         -------- private associated function defined here
@@ -203,7 +203,7 @@ LL |         crate::bar::A::bar();
    |                        ^^^ private associated function
 
 error[E0624]: associated function `bar` is private
-  --> $DIR/privacy1.rs:105:29
+  --> $DIR/privacy1.rs:111:29
    |
 LL |             fn bar() {}
    |             -------- private associated function defined here
@@ -212,7 +212,7 @@ LL |         crate::bar::baz::A::bar();
    |                             ^^^ private associated function
 
 error[E0624]: method `bar2` is private
-  --> $DIR/privacy1.rs:108:28
+  --> $DIR/privacy1.rs:114:28
    |
 LL |             fn bar2(&self) {}
    |             -------------- private method defined here
diff --git a/tests/ui/privacy/privacy4.rs b/tests/ui/privacy/privacy4.rs
index 7341c7752bb..6091613271f 100644
--- a/tests/ui/privacy/privacy4.rs
+++ b/tests/ui/privacy/privacy4.rs
@@ -1,7 +1,9 @@
 #![feature(lang_items, no_core)]
 #![no_core] // makes debugging this test *a lot* easier (during resolve)
 
-#[lang = "sized"] pub trait Sized {}
+#[lang = "sized"] pub trait Sized: MetaSized {}
+#[lang = "meta_sized"] pub trait MetaSized: PointeeSized {}
+#[lang = "pointee_sized"] pub trait PointeeSized {}
 #[lang="copy"] pub trait Copy {}
 
 // Test to make sure that private items imported through globs remain private
diff --git a/tests/ui/privacy/privacy4.stderr b/tests/ui/privacy/privacy4.stderr
index 4aa3ae964c0..eeefd85645c 100644
--- a/tests/ui/privacy/privacy4.stderr
+++ b/tests/ui/privacy/privacy4.stderr
@@ -1,11 +1,11 @@
 error[E0603]: module `glob` is private
-  --> $DIR/privacy4.rs:21:14
+  --> $DIR/privacy4.rs:23:14
    |
 LL |     use bar::glob::gpriv;
    |              ^^^^ private module
    |
 note: the module `glob` is defined here
-  --> $DIR/privacy4.rs:13:5
+  --> $DIR/privacy4.rs:15:5
    |
 LL |     mod glob {
    |     ^^^^^^^^
diff --git a/tests/ui/proc-macro/quote/auxiliary/basic.rs b/tests/ui/proc-macro/quote/auxiliary/basic.rs
index ef726bbfbe3..c50bb964eab 100644
--- a/tests/ui/proc-macro/quote/auxiliary/basic.rs
+++ b/tests/ui/proc-macro/quote/auxiliary/basic.rs
@@ -4,6 +4,7 @@
 extern crate proc_macro;
 
 use std::borrow::Cow;
+use std::collections::BTreeSet;
 use std::ffi::{CStr, CString};
 
 use proc_macro::*;
@@ -12,6 +13,8 @@ use proc_macro::*;
 pub fn run_tests(_: TokenStream) -> TokenStream {
     test_quote_impl();
     test_substitution();
+    test_iter();
+    test_array();
     test_advanced();
     test_integer();
     test_floating();
@@ -24,6 +27,13 @@ pub fn run_tests(_: TokenStream) -> TokenStream {
     test_ident();
     test_underscore();
     test_duplicate();
+    test_fancy_repetition();
+    test_nested_fancy_repetition();
+    test_duplicate_name_repetition();
+    test_duplicate_name_repetition_no_copy();
+    test_btreeset_repetition();
+    test_variable_name_conflict();
+    test_nonrep_in_repetition();
     test_empty_quote();
     test_box_str();
     test_cow();
@@ -34,6 +44,7 @@ pub fn run_tests(_: TokenStream) -> TokenStream {
     test_inner_block_comment();
     test_outer_attr();
     test_inner_attr();
+    test_star_after_repetition();
     test_quote_raw_id();
 
     TokenStream::new()
@@ -49,20 +60,9 @@ pub fn run_tests(_: TokenStream) -> TokenStream {
 //   - fn test_type_inference_for_span
 //   - wrong-type-span.rs
 // - format_ident:
+//   - fn test_closure
 //   - fn test_format_ident
 //   - fn test_format_ident_strip_raw
-// - repetition:
-//   - fn test_iter
-//   - fn test_array
-//   - fn test_fancy_repetition
-//   - fn test_nested_fancy_repetition
-//   - fn test_duplicate_name_repetition
-//   - fn test_duplicate_name_repetition_no_copy
-//   - fn test_btreeset_repetition
-//   - fn test_variable_name_conflict
-//   - fn test_nonrep_in_repetition
-//   - fn test_closure
-//   - fn test_star_after_repetition
 
 struct X;
 
@@ -99,6 +99,39 @@ fn test_substitution() {
     assert_eq!(expected, tokens.to_string());
 }
 
+fn test_iter() {
+    let primes = &[X, X, X, X];
+
+    assert_eq!("X X X X", quote!($($primes)*).to_string());
+
+    assert_eq!("X, X, X, X,", quote!($($primes,)*).to_string());
+
+    assert_eq!("X, X, X, X", quote!($($primes),*).to_string());
+}
+
+fn test_array() {
+    let array: [u8; 40] = [0; 40];
+    let _ = quote!($($array $array)*);
+
+    let ref_array: &[u8; 40] = &[0; 40];
+    let _ = quote!($($ref_array $ref_array)*);
+
+    let ref_slice: &[u8] = &[0; 40];
+    let _ = quote!($($ref_slice $ref_slice)*);
+
+    let array: [X; 2] = [X, X]; // !Copy
+    let _ = quote!($($array $array)*);
+
+    let ref_array: &[X; 2] = &[X, X];
+    let _ = quote!($($ref_array $ref_array)*);
+
+    let ref_slice: &[X] = &[X, X];
+    let _ = quote!($($ref_slice $ref_slice)*);
+
+    let array_of_array: [[u8; 2]; 2] = [[0; 2]; 2];
+    let _ = quote!($($($array_of_array)*)*);
+}
+
 fn test_advanced() {
     let generics = quote!( <'a, T> );
 
@@ -279,6 +312,88 @@ fn test_duplicate() {
     assert_eq!(expected, tokens.to_string());
 }
 
+fn test_fancy_repetition() {
+    let foo = vec!["a", "b"];
+    let bar = vec![true, false];
+
+    let tokens = quote! {
+        $($foo: $bar),*
+    };
+
+    let expected = r#""a" : true, "b" : false"#;
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_nested_fancy_repetition() {
+    let nested = vec![vec!['a', 'b', 'c'], vec!['x', 'y', 'z']];
+
+    let tokens = quote! {
+        $(
+            $($nested)*
+        ),*
+    };
+
+    let expected = "'a' 'b' 'c', 'x' 'y' 'z'";
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_duplicate_name_repetition() {
+    let foo = &["a", "b"];
+
+    let tokens = quote! {
+        $($foo: $foo),*
+        $($foo: $foo),*
+    };
+
+    let expected = r#""a" : "a", "b" : "b" "a" : "a", "b" : "b""#;
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_duplicate_name_repetition_no_copy() {
+    let foo = vec!["a".to_owned(), "b".to_owned()];
+
+    let tokens = quote! {
+        $($foo: $foo),*
+    };
+
+    let expected = r#""a" : "a", "b" : "b""#;
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_btreeset_repetition() {
+    let mut set = BTreeSet::new();
+    set.insert("a".to_owned());
+    set.insert("b".to_owned());
+
+    let tokens = quote! {
+        $($set: $set),*
+    };
+
+    let expected = r#""a" : "a", "b" : "b""#;
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_variable_name_conflict() {
+    // The implementation of `#(...),*` uses the variable `_i` but it should be
+    // fine, if a little confusing when debugging.
+    let _i = vec!['a', 'b'];
+    let tokens = quote! { $($_i),* };
+    let expected = "'a', 'b'";
+    assert_eq!(expected, tokens.to_string());
+}
+
+fn test_nonrep_in_repetition() {
+    let rep = vec!["a", "b"];
+    let nonrep = "c";
+
+    let tokens = quote! {
+        $($rep $rep : $nonrep $nonrep),*
+    };
+
+    let expected = r#""a" "a" : "c" "c", "b" "b" : "c" "c""#;
+    assert_eq!(expected, tokens.to_string());
+}
+
 fn test_empty_quote() {
     let tokens = quote!();
     assert_eq!("", tokens.to_string());
@@ -355,6 +470,19 @@ fn test_inner_attr() {
     assert_eq!(expected, tokens.to_string());
 }
 
+// https://github.com/dtolnay/quote/issues/130
+fn test_star_after_repetition() {
+    let c = vec!['0', '1'];
+    let tokens = quote! {
+        $(
+            f($c);
+        )*
+        *out = None;
+    };
+    let expected = "f('0'); f('1'); * out = None;";
+    assert_eq!(expected, tokens.to_string());
+}
+
 fn test_quote_raw_id() {
     let id = quote!(r#raw_id);
     assert_eq!(id.to_string(), "r#raw_id");
diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.rs b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.rs
index 2f67ae1bc6e..418e3dd444d 100644
--- a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.rs
+++ b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.rs
@@ -1,7 +1,3 @@
-// FIXME(quote): `proc_macro::quote!` doesn't support repetition at the moment, so the stderr is
-// expected to be incorrect.
-//@ known-bug: #54722
-
 #![feature(proc_macro_quote)]
 
 extern crate proc_macro;
@@ -13,5 +9,5 @@ fn main() {
 
     // Without some protection against repetitions with no iterator somewhere
     // inside, this would loop infinitely.
-    quote!($($nonrep $nonrep)*);
+    quote!($($nonrep $nonrep)*); //~ ERROR mismatched types
 }
diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.stderr b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.stderr
index 5f28a46f318..ecb12c1df3b 100644
--- a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.stderr
+++ b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated-dup.stderr
@@ -1,10 +1,13 @@
-error: proc macro panicked
-  --> $DIR/does-not-have-iter-interpolated-dup.rs:16:5
+error[E0308]: mismatched types
+  --> $DIR/does-not-have-iter-interpolated-dup.rs:12:5
    |
 LL |     quote!($($nonrep $nonrep)*);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = help: message: `$` must be followed by an ident or `$` in `quote!`
+   |     |
+   |     expected `HasIterator`, found `ThereIsNoIteratorInRepetition`
+   |     expected due to this
+   |     here the type of `has_iter` is inferred to be `ThereIsNoIteratorInRepetition`
 
 error: aborting due to 1 previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.rs b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.rs
index 1efb3eac642..507936770aa 100644
--- a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.rs
+++ b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.rs
@@ -1,7 +1,3 @@
-// FIXME(quote): `proc_macro::quote!` doesn't support repetition at the moment, so the stderr is
-// expected to be incorrect.
-//@ known-bug: #54722
-
 #![feature(proc_macro_quote)]
 
 extern crate proc_macro;
@@ -13,5 +9,5 @@ fn main() {
 
     // Without some protection against repetitions with no iterator somewhere
     // inside, this would loop infinitely.
-    quote!($($nonrep)*);
+    quote!($($nonrep)*); //~ ERROR mismatched types
 }
diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.stderr b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.stderr
index 595aa858763..093e2ebc098 100644
--- a/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.stderr
+++ b/tests/ui/proc-macro/quote/does-not-have-iter-interpolated.stderr
@@ -1,10 +1,13 @@
-error: proc macro panicked
-  --> $DIR/does-not-have-iter-interpolated.rs:16:5
+error[E0308]: mismatched types
+  --> $DIR/does-not-have-iter-interpolated.rs:12:5
    |
 LL |     quote!($($nonrep)*);
    |     ^^^^^^^^^^^^^^^^^^^
-   |
-   = help: message: `$` must be followed by an ident or `$` in `quote!`
+   |     |
+   |     expected `HasIterator`, found `ThereIsNoIteratorInRepetition`
+   |     expected due to this
+   |     here the type of `has_iter` is inferred to be `ThereIsNoIteratorInRepetition`
 
 error: aborting due to 1 previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-separated.rs b/tests/ui/proc-macro/quote/does-not-have-iter-separated.rs
index 5f2ddabc390..7e41b08f263 100644
--- a/tests/ui/proc-macro/quote/does-not-have-iter-separated.rs
+++ b/tests/ui/proc-macro/quote/does-not-have-iter-separated.rs
@@ -1,7 +1,3 @@
-// FIXME(quote): `proc_macro::quote!` doesn't support repetition at the moment, so the stderr is
-// expected to be incorrect.
-//@ known-bug: #54722
-
 #![feature(proc_macro_quote)]
 
 extern crate proc_macro;
@@ -9,5 +5,5 @@ extern crate proc_macro;
 use proc_macro::quote;
 
 fn main() {
-    quote!($(a b),*);
+    quote!($(a b),*); //~ ERROR mismatched types
 }
diff --git a/tests/ui/proc-macro/quote/does-not-have-iter-separated.stderr b/tests/ui/proc-macro/quote/does-not-have-iter-separated.stderr
index f6f5d7e007d..937209e675e 100644
--- a/tests/ui/proc-macro/quote/does-not-have-iter-separated.stderr
+++ b/tests/ui/proc-macro/quote/does-not-have-iter-separated.stderr
@@ -1,10 +1,12 @@
-error: proc macro panicked
-  --> $DIR/does-not-have-iter-separated.rs:12:5
+error[E0308]: mismatched types
+  --> $DIR/does-not-have-iter-separated.rs:8:5
    |
 LL |     quote!($(a b),*);
    |     ^^^^^^^^^^^^^^^^
-   |
-   = help: message: `$` must be followed by an ident or `$` in `quote!`
+   |     |
+   |     expected `HasIterator`, found `ThereIsNoIteratorInRepetition`
+   |     expected due to this
 
 error: aborting due to 1 previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/proc-macro/quote/does-not-have-iter.rs b/tests/ui/proc-macro/quote/does-not-have-iter.rs
index 25ffd786cc6..038851ff76e 100644
--- a/tests/ui/proc-macro/quote/does-not-have-iter.rs
+++ b/tests/ui/proc-macro/quote/does-not-have-iter.rs
@@ -1,7 +1,3 @@
-// FIXME(quote): `proc_macro::quote!` doesn't support repetition at the moment, so the stderr is
-// expected to be incorrect.
-//@ known-bug: #54722
-
 #![feature(proc_macro_quote)]
 
 extern crate proc_macro;
@@ -9,5 +5,5 @@ extern crate proc_macro;
 use proc_macro::quote;
 
 fn main() {
-    quote!($(a b)*);
+    quote!($(a b)*); //~ ERROR mismatched types
 }
diff --git a/tests/ui/proc-macro/quote/does-not-have-iter.stderr b/tests/ui/proc-macro/quote/does-not-have-iter.stderr
index 0ed1daffc8c..e74ea334899 100644
--- a/tests/ui/proc-macro/quote/does-not-have-iter.stderr
+++ b/tests/ui/proc-macro/quote/does-not-have-iter.stderr
@@ -1,10 +1,12 @@
-error: proc macro panicked
-  --> $DIR/does-not-have-iter.rs:12:5
+error[E0308]: mismatched types
+  --> $DIR/does-not-have-iter.rs:8:5
    |
 LL |     quote!($(a b)*);
    |     ^^^^^^^^^^^^^^^
-   |
-   = help: message: `$` must be followed by an ident or `$` in `quote!`
+   |     |
+   |     expected `HasIterator`, found `ThereIsNoIteratorInRepetition`
+   |     expected due to this
 
 error: aborting due to 1 previous error
 
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/proc-macro/quote/not-quotable.stderr b/tests/ui/proc-macro/quote/not-quotable.stderr
index 62a02638e54..d1c3d06f2b6 100644
--- a/tests/ui/proc-macro/quote/not-quotable.stderr
+++ b/tests/ui/proc-macro/quote/not-quotable.stderr
@@ -15,8 +15,8 @@ LL |     let _ = quote! { $ip };
              Cow<'_, T>
              Option<T>
              Rc<T>
-             bool
-           and 24 others
+             RepInterp<T>
+           and 25 others
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/proc-macro/quote/not-repeatable.rs b/tests/ui/proc-macro/quote/not-repeatable.rs
index d115da73181..0291e4ddf88 100644
--- a/tests/ui/proc-macro/quote/not-repeatable.rs
+++ b/tests/ui/proc-macro/quote/not-repeatable.rs
@@ -1,7 +1,3 @@
-// FIXME(quote): `proc_macro::quote!` doesn't support repetition at the moment, so the stderr is
-// expected to be incorrect.
-//@ known-bug: #54722
-
 #![feature(proc_macro_quote)]
 
 extern crate proc_macro;
@@ -12,5 +8,5 @@ struct Ipv4Addr;
 
 fn main() {
     let ip = Ipv4Addr;
-    let _ = quote! { $($ip)* };
+    let _ = quote! { $($ip)* }; //~ ERROR the method `quote_into_iter` exists for struct `Ipv4Addr`, but its trait bounds were not satisfied
 }
diff --git a/tests/ui/proc-macro/quote/not-repeatable.stderr b/tests/ui/proc-macro/quote/not-repeatable.stderr
index 18fbcd73798..aeda08d7de6 100644
--- a/tests/ui/proc-macro/quote/not-repeatable.stderr
+++ b/tests/ui/proc-macro/quote/not-repeatable.stderr
@@ -1,10 +1,25 @@
-error: proc macro panicked
-  --> $DIR/not-repeatable.rs:15:13
+error[E0599]: the method `quote_into_iter` exists for struct `Ipv4Addr`, but its trait bounds were not satisfied
+  --> $DIR/not-repeatable.rs:11:13
    |
+LL | struct Ipv4Addr;
+   | --------------- method `quote_into_iter` not found for this struct because it doesn't satisfy `Ipv4Addr: Iterator`, `Ipv4Addr: ToTokens`, `Ipv4Addr: proc_macro::ext::RepIteratorExt` or `Ipv4Addr: proc_macro::ext::RepToTokensExt`
+...
 LL |     let _ = quote! { $($ip)* };
-   |             ^^^^^^^^^^^^^^^^^^
+   |             ^^^^^^^^^^^^^^^^^^ method cannot be called on `Ipv4Addr` due to unsatisfied trait bounds
    |
-   = help: message: `$` must be followed by an ident or `$` in `quote!`
+   = note: the following trait bounds were not satisfied:
+           `Ipv4Addr: Iterator`
+           which is required by `Ipv4Addr: proc_macro::ext::RepIteratorExt`
+           `&Ipv4Addr: Iterator`
+           which is required by `&Ipv4Addr: proc_macro::ext::RepIteratorExt`
+           `Ipv4Addr: ToTokens`
+           which is required by `Ipv4Addr: proc_macro::ext::RepToTokensExt`
+           `&mut Ipv4Addr: Iterator`
+           which is required by `&mut Ipv4Addr: proc_macro::ext::RepIteratorExt`
+note: the traits `Iterator` and `ToTokens` must be implemented
+  --> $SRC_DIR/proc_macro/src/to_tokens.rs:LL:COL
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
 
 error: aborting due to 1 previous error
 
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/repr/repr.stderr b/tests/ui/repr/repr.stderr
index e0bec666381..f3b11398eaa 100644
--- a/tests/ui/repr/repr.stderr
+++ b/tests/ui/repr/repr.stderr
@@ -1,20 +1,30 @@
-error: malformed `repr` attribute input
+error[E0539]: malformed `repr` attribute input
   --> $DIR/repr.rs:1:1
    |
 LL | #[repr]
-   | ^^^^^^^ help: must be of the form: `#[repr(C)]`
+   | ^^^^^^^
+   | |
+   | expected this to be a list
+   | help: must be of the form: `#[repr(C)]`
 
-error: malformed `repr` attribute input
+error[E0539]: malformed `repr` attribute input
   --> $DIR/repr.rs:4:1
    |
 LL | #[repr = "B"]
-   | ^^^^^^^^^^^^^ help: must be of the form: `#[repr(C)]`
+   | ^^^^^^^^^^^^^
+   | |
+   | expected this to be a list
+   | help: must be of the form: `#[repr(C)]`
 
-error: malformed `repr` attribute input
+error[E0539]: malformed `repr` attribute input
   --> $DIR/repr.rs:7:1
    |
 LL | #[repr = "C"]
-   | ^^^^^^^^^^^^^ help: must be of the form: `#[repr(C)]`
+   | ^^^^^^^^^^^^^
+   | |
+   | expected this to be a list
+   | help: must be of the form: `#[repr(C)]`
 
 error: aborting due to 3 previous errors
 
+For more information about this error, try `rustc --explain E0539`.
diff --git a/tests/ui/sized-hierarchy/alias-bounds.rs b/tests/ui/sized-hierarchy/alias-bounds.rs
new file mode 100644
index 00000000000..87b4bab11b7
--- /dev/null
+++ b/tests/ui/sized-hierarchy/alias-bounds.rs
@@ -0,0 +1,28 @@
+//@ check-pass
+//@ compile-flags: --crate-type=lib
+//@ revisions: old next
+//@[next] compile-flags: -Znext-solver
+#![feature(sized_hierarchy)]
+
+use std::marker::{PointeeSized, MetaSized};
+
+trait Id: PointeeSized {
+    type This: PointeeSized;
+}
+
+impl<T: PointeeSized> Id for T {
+    type This = T;
+}
+
+fn requires_metasized<T: MetaSized>() {}
+
+fn foo<T>()
+where
+    T: PointeeSized,
+    <T as Id>::This: Sized
+{
+    // `T: Sized` from where bounds (`T: PointeeSized` removes any default bounds and
+    // `<T as Id>::This: Sized` normalizes to `T: Sized`). This should trivially satisfy
+    // `T: MetaSized`.
+    requires_metasized::<T>();
+}
diff --git a/tests/ui/sized-hierarchy/auxiliary/pretty-print-dep.rs b/tests/ui/sized-hierarchy/auxiliary/pretty-print-dep.rs
new file mode 100644
index 00000000000..a7d18d90368
--- /dev/null
+++ b/tests/ui/sized-hierarchy/auxiliary/pretty-print-dep.rs
@@ -0,0 +1,19 @@
+#![feature(sized_hierarchy)]
+
+use std::marker::{MetaSized, PointeeSized};
+
+pub trait SizedTr {}
+
+impl<T: Sized> SizedTr for T {}
+
+pub trait NegSizedTr {}
+
+impl<T: ?Sized> NegSizedTr for T {}
+
+pub trait MetaSizedTr {}
+
+impl<T: MetaSized> MetaSizedTr for T {}
+
+pub trait PointeeSizedTr: PointeeSized {}
+
+impl<T: PointeeSized> PointeeSizedTr for T {}
diff --git a/tests/ui/sized-hierarchy/auxiliary/pretty-print-no-feat-dep.rs b/tests/ui/sized-hierarchy/auxiliary/pretty-print-no-feat-dep.rs
new file mode 100644
index 00000000000..3314b0f356f
--- /dev/null
+++ b/tests/ui/sized-hierarchy/auxiliary/pretty-print-no-feat-dep.rs
@@ -0,0 +1,7 @@
+pub trait SizedTr {}
+
+impl<T: Sized> SizedTr for T {}
+
+pub trait NegSizedTr {}
+
+impl<T: ?Sized> NegSizedTr for T {}
diff --git a/tests/ui/sized-hierarchy/default-bound.rs b/tests/ui/sized-hierarchy/default-bound.rs
new file mode 100644
index 00000000000..12b2eb2b5c1
--- /dev/null
+++ b/tests/ui/sized-hierarchy/default-bound.rs
@@ -0,0 +1,49 @@
+//@ check-fail
+#![feature(extern_types, sized_hierarchy)]
+
+use std::marker::{MetaSized, PointeeSized};
+
+fn bare<T>() {}
+
+
+fn sized<T: Sized>() {}
+
+fn neg_sized<T: ?Sized>() {}
+
+
+fn metasized<T: MetaSized>() {}
+
+fn neg_metasized<T: ?MetaSized>() {}
+//~^ ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+
+
+fn pointeesized<T: PointeeSized>() { }
+
+fn neg_pointeesized<T: ?PointeeSized>() { }
+//~^ ERROR relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+
+
+fn main() {
+    // Functions which should have a `T: Sized` bound - check for an error given a non-Sized type:
+
+    bare::<[u8]>();
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    sized::<[u8]>();
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    metasized::<[u8]>();
+    pointeesized::<[u8]>();
+
+    // Functions which should have a `T: MetaSized` bound - check for an error given a
+    // non-MetaSized type:
+    unsafe extern "C" {
+        type Foo;
+    }
+
+    bare::<Foo>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known
+    sized::<Foo>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known
+    metasized::<Foo>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known
+    pointeesized::<Foo>();
+}
diff --git a/tests/ui/sized-hierarchy/default-bound.stderr b/tests/ui/sized-hierarchy/default-bound.stderr
new file mode 100644
index 00000000000..22f0fa29d3e
--- /dev/null
+++ b/tests/ui/sized-hierarchy/default-bound.stderr
@@ -0,0 +1,88 @@
+error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+  --> $DIR/default-bound.rs:16:21
+   |
+LL | fn neg_metasized<T: ?MetaSized>() {}
+   |                     ^^^^^^^^^^
+
+error: relaxing a default bound only does something for `?Sized`; all other traits are not bound by default
+  --> $DIR/default-bound.rs:22:24
+   |
+LL | fn neg_pointeesized<T: ?PointeeSized>() { }
+   |                        ^^^^^^^^^^^^^
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/default-bound.rs:29:12
+   |
+LL |     bare::<[u8]>();
+   |            ^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by an implicit `Sized` bound in `bare`
+  --> $DIR/default-bound.rs:6:9
+   |
+LL | fn bare<T>() {}
+   |         ^ required by the implicit `Sized` requirement on this type parameter in `bare`
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | fn bare<T: ?Sized>() {}
+   |          ++++++++
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/default-bound.rs:31:13
+   |
+LL |     sized::<[u8]>();
+   |             ^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `sized`
+  --> $DIR/default-bound.rs:9:13
+   |
+LL | fn sized<T: Sized>() {}
+   |             ^^^^^ required by this bound in `sized`
+
+error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
+  --> $DIR/default-bound.rs:42:12
+   |
+LL |     bare::<Foo>();
+   |            ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `main::Foo`
+note: required by an implicit `Sized` bound in `bare`
+  --> $DIR/default-bound.rs:6:9
+   |
+LL | fn bare<T>() {}
+   |         ^ required by the implicit `Sized` requirement on this type parameter in `bare`
+help: consider relaxing the implicit `Sized` restriction
+   |
+LL | fn bare<T: ?Sized>() {}
+   |          ++++++++
+
+error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
+  --> $DIR/default-bound.rs:44:13
+   |
+LL |     sized::<Foo>();
+   |             ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `main::Foo`
+note: required by a bound in `sized`
+  --> $DIR/default-bound.rs:9:13
+   |
+LL | fn sized<T: Sized>() {}
+   |             ^^^^^ required by this bound in `sized`
+
+error[E0277]: the size for values of type `main::Foo` cannot be known
+  --> $DIR/default-bound.rs:46:17
+   |
+LL |     metasized::<Foo>();
+   |                 ^^^ doesn't have a known size
+   |
+   = help: the trait `MetaSized` is not implemented for `main::Foo`
+note: required by a bound in `metasized`
+  --> $DIR/default-bound.rs:14:17
+   |
+LL | fn metasized<T: MetaSized>() {}
+   |                 ^^^^^^^^^ required by this bound in `metasized`
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/sized-hierarchy/default-supertrait.rs b/tests/ui/sized-hierarchy/default-supertrait.rs
new file mode 100644
index 00000000000..b25acf9e6ea
--- /dev/null
+++ b/tests/ui/sized-hierarchy/default-supertrait.rs
@@ -0,0 +1,61 @@
+//@ check-fail
+#![feature(sized_hierarchy)]
+
+use std::marker::{MetaSized, PointeeSized};
+
+trait Sized_: Sized { }
+
+trait NegSized: ?Sized { }
+//~^ ERROR `?Trait` is not permitted in supertraits
+
+trait MetaSized_: MetaSized { }
+
+trait NegMetaSized: ?MetaSized { }
+//~^ ERROR `?Trait` is not permitted in supertraits
+
+
+trait PointeeSized_: PointeeSized { }
+
+trait NegPointeeSized: ?PointeeSized { }
+//~^ ERROR `?Trait` is not permitted in supertraits
+
+trait Bare {}
+
+fn requires_sized<T: Sized>() {}
+fn requires_metasized<T: MetaSized>() {}
+fn requires_pointeesized<T: PointeeSized>() {}
+
+fn with_sized_supertrait<T: PointeeSized + Sized_>() {
+    requires_sized::<T>();
+    requires_metasized::<T>();
+    requires_pointeesized::<T>();
+}
+
+fn with_metasized_supertrait<T: PointeeSized + MetaSized_>() {
+    requires_sized::<T>();
+    //~^ ERROR the size for values of type `T` cannot be known at compilation time
+    requires_metasized::<T>();
+    requires_pointeesized::<T>();
+}
+
+// It isn't really possible to write this one..
+fn with_pointeesized_supertrait<T: PointeeSized + PointeeSized_>() {
+    requires_sized::<T>();
+    //~^ ERROR the size for values of type `T` cannot be known
+    requires_metasized::<T>();
+    //~^ ERROR the size for values of type `T` cannot be known
+    requires_pointeesized::<T>();
+}
+
+// `T` won't inherit the `const MetaSized` implicit supertrait of `Bare`, so there is an error on
+// the bound, which is expected.
+fn with_bare_trait<T: PointeeSized + Bare>() {
+//~^ ERROR the size for values of type `T` cannot be known
+    requires_sized::<T>();
+    //~^ ERROR the size for values of type `T` cannot be known
+    requires_metasized::<T>();
+    //~^ ERROR the size for values of type `T` cannot be known
+    requires_pointeesized::<T>();
+}
+
+fn main() { }
diff --git a/tests/ui/sized-hierarchy/default-supertrait.stderr b/tests/ui/sized-hierarchy/default-supertrait.stderr
new file mode 100644
index 00000000000..de23936b900
--- /dev/null
+++ b/tests/ui/sized-hierarchy/default-supertrait.stderr
@@ -0,0 +1,125 @@
+error[E0658]: `?Trait` is not permitted in supertraits
+  --> $DIR/default-supertrait.rs:8:17
+   |
+LL | trait NegSized: ?Sized { }
+   |                 ^^^^^^
+   |
+   = note: traits are `?Sized` by default
+   = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` is not permitted in supertraits
+  --> $DIR/default-supertrait.rs:13:21
+   |
+LL | trait NegMetaSized: ?MetaSized { }
+   |                     ^^^^^^^^^^
+   |
+   = note: traits are `?MetaSized` by default
+   = help: add `#![feature(more_maybe_bounds)]` 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]: `?Trait` is not permitted in supertraits
+  --> $DIR/default-supertrait.rs:19:24
+   |
+LL | trait NegPointeeSized: ?PointeeSized { }
+   |                        ^^^^^^^^^^^^^
+   |
+   = note: traits are `?PointeeSized` by default
+   = help: add `#![feature(more_maybe_bounds)]` 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[E0277]: the size for values of type `T` cannot be known
+  --> $DIR/default-supertrait.rs:52:38
+   |
+LL | fn with_bare_trait<T: PointeeSized + Bare>() {
+   |                                      ^^^^ doesn't have a known size
+   |
+note: required by a bound in `Bare`
+  --> $DIR/default-supertrait.rs:22:1
+   |
+LL | trait Bare {}
+   | ^^^^^^^^^^^^^ required by this bound in `Bare`
+help: consider further restricting type parameter `T` with unstable trait `MetaSized`
+   |
+LL | fn with_bare_trait<T: PointeeSized + Bare + std::marker::MetaSized>() {
+   |                                           ++++++++++++++++++++++++
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/default-supertrait.rs:35:22
+   |
+LL | fn with_metasized_supertrait<T: PointeeSized + MetaSized_>() {
+   |                              - this type parameter needs to be `Sized`
+LL |     requires_sized::<T>();
+   |                      ^ doesn't have a size known at compile-time
+   |
+note: required by a bound in `requires_sized`
+  --> $DIR/default-supertrait.rs:24:22
+   |
+LL | fn requires_sized<T: Sized>() {}
+   |                      ^^^^^ required by this bound in `requires_sized`
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/default-supertrait.rs:43:22
+   |
+LL | fn with_pointeesized_supertrait<T: PointeeSized + PointeeSized_>() {
+   |                                 - this type parameter needs to be `Sized`
+LL |     requires_sized::<T>();
+   |                      ^ doesn't have a size known at compile-time
+   |
+note: required by a bound in `requires_sized`
+  --> $DIR/default-supertrait.rs:24:22
+   |
+LL | fn requires_sized<T: Sized>() {}
+   |                      ^^^^^ required by this bound in `requires_sized`
+
+error[E0277]: the size for values of type `T` cannot be known
+  --> $DIR/default-supertrait.rs:45:26
+   |
+LL |     requires_metasized::<T>();
+   |                          ^ doesn't have a known size
+   |
+note: required by a bound in `requires_metasized`
+  --> $DIR/default-supertrait.rs:25:26
+   |
+LL | fn requires_metasized<T: MetaSized>() {}
+   |                          ^^^^^^^^^ required by this bound in `requires_metasized`
+help: consider further restricting type parameter `T` with unstable trait `MetaSized`
+   |
+LL | fn with_pointeesized_supertrait<T: PointeeSized + PointeeSized_ + std::marker::MetaSized>() {
+   |                                                                 ++++++++++++++++++++++++
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/default-supertrait.rs:54:22
+   |
+LL | fn with_bare_trait<T: PointeeSized + Bare>() {
+   |                    - this type parameter needs to be `Sized`
+LL |
+LL |     requires_sized::<T>();
+   |                      ^ doesn't have a size known at compile-time
+   |
+note: required by a bound in `requires_sized`
+  --> $DIR/default-supertrait.rs:24:22
+   |
+LL | fn requires_sized<T: Sized>() {}
+   |                      ^^^^^ required by this bound in `requires_sized`
+
+error[E0277]: the size for values of type `T` cannot be known
+  --> $DIR/default-supertrait.rs:56:26
+   |
+LL |     requires_metasized::<T>();
+   |                          ^ doesn't have a known size
+   |
+note: required by a bound in `requires_metasized`
+  --> $DIR/default-supertrait.rs:25:26
+   |
+LL | fn requires_metasized<T: MetaSized>() {}
+   |                          ^^^^^^^^^ required by this bound in `requires_metasized`
+help: consider further restricting type parameter `T` with unstable trait `MetaSized`
+   |
+LL | fn with_bare_trait<T: PointeeSized + Bare + std::marker::MetaSized>() {
+   |                                           ++++++++++++++++++++++++
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0277, E0658.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/sized-hierarchy/elaboration-opt-regions-1.rs b/tests/ui/sized-hierarchy/elaboration-opt-regions-1.rs
new file mode 100644
index 00000000000..d59227beae8
--- /dev/null
+++ b/tests/ui/sized-hierarchy/elaboration-opt-regions-1.rs
@@ -0,0 +1,18 @@
+//@ check-pass
+//@ compile-flags: --crate-type=lib
+//@ revisions: old next
+//@[next] compile-flags: -Znext-solver
+#![feature(sized_hierarchy)]
+
+use std::marker::{PhantomData, MetaSized, PointeeSized};
+
+struct Foo<'a, T: PointeeSized>(*mut &'a (), T);
+
+fn requires_metasized<'a, T: MetaSized>(f: &'a T) {}
+
+fn foo<'a, T: PointeeSized>(f: &Foo<'a, T>)
+where
+    Foo<'a, T>: Sized
+{
+    requires_metasized(f);
+}
diff --git a/tests/ui/sized-hierarchy/elaboration-opt-regions.rs b/tests/ui/sized-hierarchy/elaboration-opt-regions.rs
new file mode 100644
index 00000000000..66e600f3dc9
--- /dev/null
+++ b/tests/ui/sized-hierarchy/elaboration-opt-regions.rs
@@ -0,0 +1,18 @@
+//@ check-pass
+//@ compile-flags: --crate-type=lib
+//@ revisions: old next
+//@[next] compile-flags: -Znext-solver
+#![feature(sized_hierarchy)]
+
+use std::marker::{PhantomData, MetaSized, PointeeSized};
+
+struct Foo<'a, T: PointeeSized>(PhantomData<&'a T>, T);
+
+fn requires_metasized<T: MetaSized>() {}
+
+fn foo<'a, T: 'a + PointeeSized>()
+where
+    Foo<'a, T>: Sized
+{
+    requires_metasized::<Foo<'_, T>>();
+}
diff --git a/tests/ui/sized-hierarchy/extern-type-behind-ptr.rs b/tests/ui/sized-hierarchy/extern-type-behind-ptr.rs
new file mode 100644
index 00000000000..70a84aabf2c
--- /dev/null
+++ b/tests/ui/sized-hierarchy/extern-type-behind-ptr.rs
@@ -0,0 +1,20 @@
+//@ check-pass
+#![feature(extern_types, sized_hierarchy)]
+
+use std::marker::{MetaSized, PointeeSized};
+
+pub fn hash<T: PointeeSized>(_: *const T) {
+    unimplemented!();
+}
+
+unsafe extern "C" {
+    type Foo;
+}
+
+fn get() -> *const Foo {
+    unimplemented!()
+}
+
+fn main() {
+    hash::<Foo>(get());
+}
diff --git a/tests/ui/sized-hierarchy/impls.rs b/tests/ui/sized-hierarchy/impls.rs
new file mode 100644
index 00000000000..46697e47c4b
--- /dev/null
+++ b/tests/ui/sized-hierarchy/impls.rs
@@ -0,0 +1,310 @@
+//@ check-fail
+//@ edition: 2024
+
+#![allow(incomplete_features, internal_features)]
+#![feature(sized_hierarchy)]
+#![feature(coroutines, dyn_star, extern_types, f16, never_type, unsized_fn_params)]
+
+use std::fmt::Debug;
+use std::marker::{MetaSized, PointeeSized};
+
+// This test checks that `Sized` and `MetaSized` are automatically implemented appropriately.
+
+fn needs_sized<T: Sized>() { }
+fn takes_sized<T: Sized>(_t: T) { }
+
+fn needs_metasized<T: MetaSized>() { }
+fn takes_metasized<T: MetaSized>(_t: T) { }
+
+fn needs_pointeesized<T: PointeeSized>() { }
+fn takes_pointeesized<T: PointeeSized>(_t: T) { }
+
+fn main() {
+    // `bool`
+    needs_sized::<bool>();
+    needs_metasized::<bool>();
+    needs_pointeesized::<bool>();
+
+    // `char`
+    needs_sized::<char>();
+    needs_metasized::<char>();
+    needs_pointeesized::<char>();
+
+    // `i8`
+    needs_sized::<i8>();
+    needs_metasized::<i8>();
+    needs_pointeesized::<i8>();
+
+    // `i16`
+    needs_sized::<i16>();
+    needs_metasized::<i16>();
+    needs_pointeesized::<i16>();
+
+    // `i32`
+    needs_sized::<i32>();
+    needs_metasized::<i32>();
+    needs_pointeesized::<i32>();
+
+    // `i64`
+    needs_sized::<i64>();
+    needs_metasized::<i64>();
+    needs_pointeesized::<i64>();
+
+    // `i128`
+    needs_sized::<i128>();
+    needs_metasized::<i128>();
+    needs_pointeesized::<i128>();
+
+    // `u8`
+    needs_sized::<u8>();
+    needs_metasized::<u8>();
+    needs_pointeesized::<u8>();
+
+    // `u16`
+    needs_sized::<u16>();
+    needs_metasized::<u16>();
+    needs_pointeesized::<u16>();
+
+    // `u32`
+    needs_sized::<u32>();
+    needs_metasized::<u32>();
+    needs_pointeesized::<u32>();
+
+    // `u64`
+    needs_sized::<u64>();
+    needs_metasized::<u64>();
+    needs_pointeesized::<u64>();
+
+    // `u128`
+    needs_sized::<u128>();
+    needs_metasized::<u128>();
+    needs_pointeesized::<u128>();
+
+    // `f16`
+    needs_sized::<f16>();
+    needs_metasized::<f16>();
+    needs_pointeesized::<f16>();
+
+    // `f32`
+    needs_sized::<f32>();
+    needs_metasized::<f32>();
+    needs_pointeesized::<f32>();
+
+    // `f64`
+    needs_sized::<f64>();
+    needs_metasized::<f64>();
+    needs_pointeesized::<f64>();
+
+    // `*const`
+    needs_sized::<*const u8>();
+    needs_metasized::<*const u8>();
+    needs_pointeesized::<*const u8>();
+
+    // `*mut`
+    needs_sized::<*mut u8>();
+    needs_metasized::<*mut u8>();
+    needs_pointeesized::<*mut u8>();
+
+    // `&`
+    needs_sized::<&u8>();
+    needs_metasized::<&u8>();
+    needs_pointeesized::<&u8>();
+
+    // `&mut`
+    needs_sized::<&mut u8>();
+    needs_metasized::<&mut u8>();
+    needs_pointeesized::<&mut u8>();
+
+    // fn-def
+    fn foo(x: u8) -> u8 { x }
+    takes_sized(foo);
+    takes_metasized(foo);
+    takes_pointeesized(foo);
+
+    // fn-ptr
+    takes_sized::<fn(u8) -> u8>(foo);
+    takes_metasized::<fn(u8) -> u8>(foo);
+    takes_pointeesized::<fn(u8) -> u8>(foo);
+
+    // `[T; x]`
+    needs_sized::<[u8; 1]>();
+    needs_metasized::<[u8; 1]>();
+    needs_pointeesized::<[u8; 1]>();
+
+    // `|a| { a }`
+    takes_sized(|a| { a });
+    takes_metasized(|a| { a });
+    takes_pointeesized(|a| { a });
+
+    // `async |a| { a }`
+    takes_sized(async |a| { a });
+    takes_metasized(async |a| { a });
+    takes_pointeesized(async |a| { a });
+
+    // `|a| { yield a }`
+    takes_sized(#[coroutine] |a| { yield a });
+    takes_metasized(#[coroutine] |a| { yield a });
+    takes_pointeesized(#[coroutine] |a| { yield a });
+
+    // `!`
+    needs_sized::<!>();
+    needs_metasized::<!>();
+    needs_pointeesized::<!>();
+
+    // `dyn*`
+    needs_sized::<dyn* Debug>();
+    needs_metasized::<dyn* Debug>();
+    needs_pointeesized::<dyn* Debug>();
+
+    // `str`
+    needs_sized::<str>();
+    //~^ ERROR the size for values of type `str` cannot be known at compilation time
+    needs_metasized::<str>();
+    needs_pointeesized::<str>();
+
+    // `[T]`
+    needs_sized::<[u8]>();
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    needs_metasized::<[u8]>();
+    needs_pointeesized::<[u8]>();
+
+    // `dyn Debug`
+    needs_sized::<dyn Debug>();
+    //~^ ERROR the size for values of type `dyn Debug` cannot be known at compilation time
+    needs_metasized::<dyn Debug>();
+    needs_pointeesized::<dyn Debug>();
+
+    // `extern type`
+    unsafe extern "C" {
+        type Foo;
+    }
+    needs_sized::<Foo>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known at compilation time
+    needs_metasized::<Foo>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known
+    needs_pointeesized::<Foo>();
+
+    // empty tuple
+    needs_sized::<()>();
+    needs_metasized::<()>();
+    needs_pointeesized::<()>();
+
+    // tuple w/ all elements sized
+    needs_sized::<(u32, u32)>();
+    needs_metasized::<(u32, u32)>();
+    needs_pointeesized::<(u32, u32)>();
+
+    // tuple w/ all elements metasized
+    needs_sized::<([u8], [u8])>();
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    needs_metasized::<([u8], [u8])>();
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    needs_pointeesized::<([u8], [u8])>();
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+
+    // tuple w/ all elements pointeesized
+    needs_sized::<(Foo, Foo)>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known at compilation time
+    needs_metasized::<(Foo, Foo)>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known at compilation time
+    //~| ERROR the size for values of type `main::Foo` cannot be known
+    needs_pointeesized::<(Foo, Foo)>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known at compilation time
+
+    // tuple w/ last element metasized
+    needs_sized::<(u32, [u8])>();
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    needs_metasized::<(u32, [u8])>();
+    needs_pointeesized::<(u32, [u8])>();
+
+    // tuple w/ last element pointeesized
+    needs_sized::<(u32, Foo)>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known at compilation time
+    needs_metasized::<(u32, Foo)>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known
+    needs_pointeesized::<(u32, Foo)>();
+
+    // struct w/ no fields
+    struct StructEmpty {}
+    needs_sized::<StructEmpty>();
+    needs_metasized::<StructEmpty>();
+    needs_pointeesized::<StructEmpty>();
+
+    // struct w/ all fields sized
+    struct StructAllFieldsSized { x: u32, y: u32 }
+    needs_sized::<StructAllFieldsSized>();
+    needs_metasized::<StructAllFieldsSized>();
+    needs_pointeesized::<StructAllFieldsSized>();
+
+    // struct w/ all fields metasized
+    struct StructAllFieldsMetaSized { x: [u8], y: [u8] }
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    needs_sized::<StructAllFieldsMetaSized>();
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    needs_metasized::<StructAllFieldsMetaSized>();
+    needs_pointeesized::<StructAllFieldsMetaSized>();
+
+    // struct w/ all fields unsized
+    struct StructAllFieldsUnsized { x: Foo, y: Foo }
+    //~^ ERROR the size for values of type `main::Foo` cannot be known at compilation time
+    needs_sized::<StructAllFieldsUnsized>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known at compilation time
+    needs_metasized::<StructAllFieldsUnsized>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known
+    needs_pointeesized::<StructAllFieldsUnsized>();
+
+    // struct w/ last fields metasized
+    struct StructLastFieldMetaSized { x: u32, y: [u8] }
+    needs_sized::<StructLastFieldMetaSized>();
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    needs_metasized::<StructLastFieldMetaSized>();
+    needs_pointeesized::<StructLastFieldMetaSized>();
+
+    // struct w/ last fields unsized
+    struct StructLastFieldUnsized { x: u32, y: Foo }
+    needs_sized::<StructLastFieldUnsized>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known at compilation time
+    needs_metasized::<StructLastFieldUnsized>();
+    //~^ ERROR the size for values of type `main::Foo` cannot be known
+    needs_pointeesized::<StructLastFieldUnsized>();
+
+    // enum w/ no fields
+    enum EnumEmpty {}
+    needs_sized::<EnumEmpty>();
+    needs_metasized::<EnumEmpty>();
+    needs_pointeesized::<EnumEmpty>();
+
+    // enum w/ all variant fields sized
+    enum EnumAllFieldsSized { Qux { x: u32, y: u32 } }
+    needs_sized::<StructAllFieldsSized>();
+    needs_metasized::<StructAllFieldsSized>();
+    needs_pointeesized::<StructAllFieldsSized>();
+
+    // enum w/ all variant fields metasized
+    enum EnumAllFieldsMetaSized { Qux { x: [u8], y: [u8] } }
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    needs_sized::<EnumAllFieldsMetaSized>();
+    needs_metasized::<EnumAllFieldsMetaSized>();
+    needs_pointeesized::<EnumAllFieldsMetaSized>();
+
+    // enum w/ all variant fields unsized
+    enum EnumAllFieldsUnsized { Qux { x: Foo, y: Foo } }
+    //~^ ERROR the size for values of type `main::Foo` cannot be known at compilation time
+    needs_sized::<EnumAllFieldsUnsized>();
+    needs_metasized::<EnumAllFieldsUnsized>();
+    needs_pointeesized::<EnumAllFieldsUnsized>();
+
+    // enum w/ last variant fields metasized
+    enum EnumLastFieldMetaSized { Qux { x: u32, y: [u8] } }
+    //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time
+    needs_sized::<EnumLastFieldMetaSized>();
+    needs_metasized::<EnumLastFieldMetaSized>();
+    needs_pointeesized::<EnumLastFieldMetaSized>();
+
+    // enum w/ last variant fields unsized
+    enum EnumLastFieldUnsized { Qux { x: u32, y: Foo } }
+    //~^ ERROR the size for values of type `main::Foo` cannot be known at compilation time
+    needs_sized::<EnumLastFieldUnsized>();
+    needs_metasized::<EnumLastFieldUnsized>();
+    needs_pointeesized::<EnumLastFieldUnsized>();
+}
diff --git a/tests/ui/sized-hierarchy/impls.stderr b/tests/ui/sized-hierarchy/impls.stderr
new file mode 100644
index 00000000000..eebe4e0d706
--- /dev/null
+++ b/tests/ui/sized-hierarchy/impls.stderr
@@ -0,0 +1,394 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/impls.rs:240:42
+   |
+LL |     struct StructAllFieldsMetaSized { x: [u8], y: [u8] }
+   |                                          ^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: only the last field of a struct may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     struct StructAllFieldsMetaSized { x: &[u8], y: [u8] }
+   |                                          +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     struct StructAllFieldsMetaSized { x: Box<[u8]>, y: [u8] }
+   |                                          ++++    +
+
+error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
+  --> $DIR/impls.rs:248:40
+   |
+LL |     struct StructAllFieldsUnsized { x: Foo, y: Foo }
+   |                                        ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `main::Foo`
+   = note: only the last field of a struct may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     struct StructAllFieldsUnsized { x: &Foo, y: Foo }
+   |                                        +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     struct StructAllFieldsUnsized { x: Box<Foo>, y: Foo }
+   |                                        ++++   +
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/impls.rs:284:44
+   |
+LL |     enum EnumAllFieldsMetaSized { Qux { x: [u8], y: [u8] } }
+   |                                            ^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     enum EnumAllFieldsMetaSized { Qux { x: &[u8], y: [u8] } }
+   |                                            +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     enum EnumAllFieldsMetaSized { Qux { x: Box<[u8]>, y: [u8] } }
+   |                                            ++++    +
+
+error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
+  --> $DIR/impls.rs:291:42
+   |
+LL |     enum EnumAllFieldsUnsized { Qux { x: Foo, y: Foo } }
+   |                                          ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `main::Foo`
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     enum EnumAllFieldsUnsized { Qux { x: &Foo, y: Foo } }
+   |                                          +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     enum EnumAllFieldsUnsized { Qux { x: Box<Foo>, y: Foo } }
+   |                                          ++++   +
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/impls.rs:298:52
+   |
+LL |     enum EnumLastFieldMetaSized { Qux { x: u32, y: [u8] } }
+   |                                                    ^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     enum EnumLastFieldMetaSized { Qux { x: u32, y: &[u8] } }
+   |                                                    +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     enum EnumLastFieldMetaSized { Qux { x: u32, y: Box<[u8]> } }
+   |                                                    ++++    +
+
+error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
+  --> $DIR/impls.rs:305:50
+   |
+LL |     enum EnumLastFieldUnsized { Qux { x: u32, y: Foo } }
+   |                                                  ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `main::Foo`
+   = note: no field of an enum variant may have a dynamically sized type
+   = help: change the field's type to have a statically known size
+help: borrowed types always have a statically known size
+   |
+LL |     enum EnumLastFieldUnsized { Qux { x: u32, y: &Foo } }
+   |                                                  +
+help: the `Box` type always has a statically known size and allocates its contents in the heap
+   |
+LL |     enum EnumLastFieldUnsized { Qux { x: u32, y: Box<Foo> } }
+   |                                                  ++++   +
+
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/impls.rs:160:19
+   |
+LL |     needs_sized::<str>();
+   |                   ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
+note: required by a bound in `needs_sized`
+  --> $DIR/impls.rs:13:19
+   |
+LL | fn needs_sized<T: Sized>() { }
+   |                   ^^^^^ required by this bound in `needs_sized`
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/impls.rs:166:19
+   |
+LL |     needs_sized::<[u8]>();
+   |                   ^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+note: required by a bound in `needs_sized`
+  --> $DIR/impls.rs:13:19
+   |
+LL | fn needs_sized<T: Sized>() { }
+   |                   ^^^^^ required by this bound in `needs_sized`
+
+error[E0277]: the size for values of type `dyn Debug` cannot be known at compilation time
+  --> $DIR/impls.rs:172:19
+   |
+LL |     needs_sized::<dyn Debug>();
+   |                   ^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `dyn Debug`
+note: required by a bound in `needs_sized`
+  --> $DIR/impls.rs:13:19
+   |
+LL | fn needs_sized<T: Sized>() { }
+   |                   ^^^^^ required by this bound in `needs_sized`
+
+error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
+  --> $DIR/impls.rs:181:19
+   |
+LL |     needs_sized::<Foo>();
+   |                   ^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `main::Foo`
+note: required by a bound in `needs_sized`
+  --> $DIR/impls.rs:13:19
+   |
+LL | fn needs_sized<T: Sized>() { }
+   |                   ^^^^^ required by this bound in `needs_sized`
+
+error[E0277]: the size for values of type `main::Foo` cannot be known
+  --> $DIR/impls.rs:183:23
+   |
+LL |     needs_metasized::<Foo>();
+   |                       ^^^ doesn't have a known size
+   |
+   = help: the trait `MetaSized` is not implemented for `main::Foo`
+note: required by a bound in `needs_metasized`
+  --> $DIR/impls.rs:16:23
+   |
+LL | fn needs_metasized<T: MetaSized>() { }
+   |                       ^^^^^^^^^ required by this bound in `needs_metasized`
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/impls.rs:198:19
+   |
+LL |     needs_sized::<([u8], [u8])>();
+   |                   ^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: only the last element of a tuple may have a dynamically sized type
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/impls.rs:200:23
+   |
+LL |     needs_metasized::<([u8], [u8])>();
+   |                       ^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: only the last element of a tuple may have a dynamically sized type
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/impls.rs:202:26
+   |
+LL |     needs_pointeesized::<([u8], [u8])>();
+   |                          ^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u8]`
+   = note: only the last element of a tuple may have a dynamically sized type
+
+error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
+  --> $DIR/impls.rs:206:19
+   |
+LL |     needs_sized::<(Foo, Foo)>();
+   |                   ^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `main::Foo`
+   = note: only the last element of a tuple may have a dynamically sized type
+
+error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
+  --> $DIR/impls.rs:208:23
+   |
+LL |     needs_metasized::<(Foo, Foo)>();
+   |                       ^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `main::Foo`
+   = note: only the last element of a tuple may have a dynamically sized type
+
+error[E0277]: the size for values of type `main::Foo` cannot be known
+  --> $DIR/impls.rs:208:23
+   |
+LL |     needs_metasized::<(Foo, Foo)>();
+   |                       ^^^^^^^^^^ doesn't have a known size
+   |
+   = help: within `(main::Foo, main::Foo)`, the trait `MetaSized` is not implemented for `main::Foo`
+   = note: required because it appears within the type `(main::Foo, main::Foo)`
+note: required by a bound in `needs_metasized`
+  --> $DIR/impls.rs:16:23
+   |
+LL | fn needs_metasized<T: MetaSized>() { }
+   |                       ^^^^^^^^^ required by this bound in `needs_metasized`
+
+error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
+  --> $DIR/impls.rs:211:26
+   |
+LL |     needs_pointeesized::<(Foo, Foo)>();
+   |                          ^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `main::Foo`
+   = note: only the last element of a tuple may have a dynamically sized type
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/impls.rs:215:19
+   |
+LL |     needs_sized::<(u32, [u8])>();
+   |                   ^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: within `(u32, [u8])`, the trait `Sized` is not implemented for `[u8]`
+   = note: required because it appears within the type `(u32, [u8])`
+note: required by a bound in `needs_sized`
+  --> $DIR/impls.rs:13:19
+   |
+LL | fn needs_sized<T: Sized>() { }
+   |                   ^^^^^ required by this bound in `needs_sized`
+
+error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
+  --> $DIR/impls.rs:221:19
+   |
+LL |     needs_sized::<(u32, Foo)>();
+   |                   ^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: within `(u32, main::Foo)`, the trait `Sized` is not implemented for `main::Foo`
+   = note: required because it appears within the type `(u32, main::Foo)`
+note: required by a bound in `needs_sized`
+  --> $DIR/impls.rs:13:19
+   |
+LL | fn needs_sized<T: Sized>() { }
+   |                   ^^^^^ required by this bound in `needs_sized`
+
+error[E0277]: the size for values of type `main::Foo` cannot be known
+  --> $DIR/impls.rs:223:23
+   |
+LL |     needs_metasized::<(u32, Foo)>();
+   |                       ^^^^^^^^^^ doesn't have a known size
+   |
+   = help: within `(u32, main::Foo)`, the trait `MetaSized` is not implemented for `main::Foo`
+   = note: required because it appears within the type `(u32, main::Foo)`
+note: required by a bound in `needs_metasized`
+  --> $DIR/impls.rs:16:23
+   |
+LL | fn needs_metasized<T: MetaSized>() { }
+   |                       ^^^^^^^^^ required by this bound in `needs_metasized`
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/impls.rs:242:19
+   |
+LL |     needs_sized::<StructAllFieldsMetaSized>();
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: within `StructAllFieldsMetaSized`, the trait `Sized` is not implemented for `[u8]`
+note: required because it appears within the type `StructAllFieldsMetaSized`
+  --> $DIR/impls.rs:240:12
+   |
+LL |     struct StructAllFieldsMetaSized { x: [u8], y: [u8] }
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `needs_sized`
+  --> $DIR/impls.rs:13:19
+   |
+LL | fn needs_sized<T: Sized>() { }
+   |                   ^^^^^ required by this bound in `needs_sized`
+
+error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
+  --> $DIR/impls.rs:250:19
+   |
+LL |     needs_sized::<StructAllFieldsUnsized>();
+   |                   ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: within `StructAllFieldsUnsized`, the trait `Sized` is not implemented for `main::Foo`
+note: required because it appears within the type `StructAllFieldsUnsized`
+  --> $DIR/impls.rs:248:12
+   |
+LL |     struct StructAllFieldsUnsized { x: Foo, y: Foo }
+   |            ^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `needs_sized`
+  --> $DIR/impls.rs:13:19
+   |
+LL | fn needs_sized<T: Sized>() { }
+   |                   ^^^^^ required by this bound in `needs_sized`
+
+error[E0277]: the size for values of type `main::Foo` cannot be known
+  --> $DIR/impls.rs:252:23
+   |
+LL |     needs_metasized::<StructAllFieldsUnsized>();
+   |                       ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a known size
+   |
+   = help: within `StructAllFieldsUnsized`, the trait `MetaSized` is not implemented for `main::Foo`
+note: required because it appears within the type `StructAllFieldsUnsized`
+  --> $DIR/impls.rs:248:12
+   |
+LL |     struct StructAllFieldsUnsized { x: Foo, y: Foo }
+   |            ^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `needs_metasized`
+  --> $DIR/impls.rs:16:23
+   |
+LL | fn needs_metasized<T: MetaSized>() { }
+   |                       ^^^^^^^^^ required by this bound in `needs_metasized`
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/impls.rs:258:19
+   |
+LL |     needs_sized::<StructLastFieldMetaSized>();
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: within `StructLastFieldMetaSized`, the trait `Sized` is not implemented for `[u8]`
+note: required because it appears within the type `StructLastFieldMetaSized`
+  --> $DIR/impls.rs:257:12
+   |
+LL |     struct StructLastFieldMetaSized { x: u32, y: [u8] }
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `needs_sized`
+  --> $DIR/impls.rs:13:19
+   |
+LL | fn needs_sized<T: Sized>() { }
+   |                   ^^^^^ required by this bound in `needs_sized`
+
+error[E0277]: the size for values of type `main::Foo` cannot be known at compilation time
+  --> $DIR/impls.rs:265:19
+   |
+LL |     needs_sized::<StructLastFieldUnsized>();
+   |                   ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: within `StructLastFieldUnsized`, the trait `Sized` is not implemented for `main::Foo`
+note: required because it appears within the type `StructLastFieldUnsized`
+  --> $DIR/impls.rs:264:12
+   |
+LL |     struct StructLastFieldUnsized { x: u32, y: Foo }
+   |            ^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `needs_sized`
+  --> $DIR/impls.rs:13:19
+   |
+LL | fn needs_sized<T: Sized>() { }
+   |                   ^^^^^ required by this bound in `needs_sized`
+
+error[E0277]: the size for values of type `main::Foo` cannot be known
+  --> $DIR/impls.rs:267:23
+   |
+LL |     needs_metasized::<StructLastFieldUnsized>();
+   |                       ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a known size
+   |
+   = help: within `StructLastFieldUnsized`, the trait `MetaSized` is not implemented for `main::Foo`
+note: required because it appears within the type `StructLastFieldUnsized`
+  --> $DIR/impls.rs:264:12
+   |
+LL |     struct StructLastFieldUnsized { x: u32, y: Foo }
+   |            ^^^^^^^^^^^^^^^^^^^^^^
+note: required by a bound in `needs_metasized`
+  --> $DIR/impls.rs:16:23
+   |
+LL | fn needs_metasized<T: MetaSized>() { }
+   |                       ^^^^^^^^^ required by this bound in `needs_metasized`
+
+error: aborting due to 27 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/sized-hierarchy/overflow.current.stderr b/tests/ui/sized-hierarchy/overflow.current.stderr
new file mode 100644
index 00000000000..e90548aa78c
--- /dev/null
+++ b/tests/ui/sized-hierarchy/overflow.current.stderr
@@ -0,0 +1,45 @@
+error[E0275]: overflow evaluating the requirement `Element: MetaSized`
+  --> $DIR/overflow.rs:16:16
+   |
+LL | struct Element(<Box<Box<Element>> as ParseTokens>::Output);
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: required for `Box<Element>` to implement `ParseTokens`
+  --> $DIR/overflow.rs:12:31
+   |
+LL | impl<T: ParseTokens + ?Sized> ParseTokens for Box<T> {
+   |      -                        ^^^^^^^^^^^     ^^^^^^
+   |      |
+   |      unsatisfied trait bound introduced here
+   = note: 1 redundant requirement hidden
+   = note: required for `Box<Box<Element>>` to implement `ParseTokens`
+
+error[E0275]: overflow evaluating the requirement `Box<Element>: ParseTokens`
+  --> $DIR/overflow.rs:18:22
+   |
+LL | impl ParseTokens for Element {
+   |                      ^^^^^^^
+   |
+note: required for `Box<Box<Element>>` to implement `ParseTokens`
+  --> $DIR/overflow.rs:12:31
+   |
+LL | impl<T: ParseTokens + ?Sized> ParseTokens for Box<T> {
+   |         -----------           ^^^^^^^^^^^     ^^^^^^
+   |         |
+   |         unsatisfied trait bound introduced here
+note: required because it appears within the type `Element`
+  --> $DIR/overflow.rs:16:8
+   |
+LL | struct Element(<Box<Box<Element>> as ParseTokens>::Output);
+   |        ^^^^^^^
+note: required by a bound in `ParseTokens`
+  --> $DIR/overflow.rs:9:1
+   |
+LL | / trait ParseTokens {
+LL | |     type Output;
+LL | | }
+   | |_^ required by this bound in `ParseTokens`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/sized-hierarchy/overflow.rs b/tests/ui/sized-hierarchy/overflow.rs
new file mode 100644
index 00000000000..e1af4885e53
--- /dev/null
+++ b/tests/ui/sized-hierarchy/overflow.rs
@@ -0,0 +1,21 @@
+//@ compile-flags: --crate-type=lib
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] check-pass
+//@[next] compile-flags: -Znext-solver
+
+use std::marker::PhantomData;
+
+trait ParseTokens {
+    type Output;
+}
+impl<T: ParseTokens + ?Sized> ParseTokens for Box<T> {
+    type Output = ();
+}
+
+struct Element(<Box<Box<Element>> as ParseTokens>::Output);
+//[current]~^ ERROR overflow evaluating
+impl ParseTokens for Element {
+//[current]~^ ERROR overflow evaluating
+    type Output = ();
+}
diff --git a/tests/ui/sized-hierarchy/pointee-supertrait.rs b/tests/ui/sized-hierarchy/pointee-supertrait.rs
new file mode 100644
index 00000000000..4bf486890bf
--- /dev/null
+++ b/tests/ui/sized-hierarchy/pointee-supertrait.rs
@@ -0,0 +1,28 @@
+//@ check-pass
+#![feature(sized_hierarchy)]
+
+// This is a reduction of some code in `library/core/src/cmp.rs` that would ICE if a default
+// `Pointee` bound is added - motivating the current status quo of `PointeeSized` being syntactic
+// sugar for an absense of any bounds whatsoever.
+
+use std::marker::PhantomData;
+
+pub trait Bar<'a> {
+    type Foo;
+}
+
+pub struct Foo<'a, T: Bar<'a>> {
+    phantom: PhantomData<&'a T>,
+}
+
+impl<'a, 'b, T> PartialEq<Foo<'b, T>> for Foo<'a, T>
+    where
+        T: for<'c> Bar<'c>,
+        <T as Bar<'a>>::Foo: PartialEq<<T as Bar<'b>>::Foo>,
+{
+    fn eq(&self, _: &Foo<'b, T>) -> bool {
+        loop {}
+    }
+}
+
+fn main() { }
diff --git a/tests/ui/sized-hierarchy/pretty-print-no-feat-dep-has-feat.rs b/tests/ui/sized-hierarchy/pretty-print-no-feat-dep-has-feat.rs
new file mode 100644
index 00000000000..0412ff651ce
--- /dev/null
+++ b/tests/ui/sized-hierarchy/pretty-print-no-feat-dep-has-feat.rs
@@ -0,0 +1,26 @@
+//@ aux-build:pretty-print-dep.rs
+//@ compile-flags: --crate-type=lib
+
+extern crate pretty_print_dep;
+use pretty_print_dep::{SizedTr, NegSizedTr, MetaSizedTr, PointeeSizedTr};
+
+// Test that printing the sizedness trait bounds in the conflicting impl error without enabling
+// `sized_hierarchy` will continue to print `?Sized`, even if the dependency is compiled with
+// `sized_hierarchy`.
+//
+// It isn't possible to write a test that matches the multiline note containing the important
+// diagnostic output being tested - so check the stderr changes carefully!
+
+struct X<T>(T);
+
+impl<T: Sized> SizedTr for X<T> {}
+//~^ ERROR conflicting implementations of trait `SizedTr` for type `X<_>`
+
+impl<T: ?Sized> NegSizedTr for X<T> {}
+//~^ ERROR conflicting implementations of trait `NegSizedTr` for type `X<_>`
+
+impl<T: ?Sized> MetaSizedTr for X<T> {}
+//~^ ERROR conflicting implementations of trait `MetaSizedTr` for type `X<_>`
+
+impl<T: ?Sized> PointeeSizedTr for X<T> {}
+//~^ ERROR conflicting implementations of trait `PointeeSizedTr` for type `X<_>`
diff --git a/tests/ui/sized-hierarchy/pretty-print-no-feat-dep-has-feat.stderr b/tests/ui/sized-hierarchy/pretty-print-no-feat-dep-has-feat.stderr
new file mode 100644
index 00000000000..cb9bfd178f8
--- /dev/null
+++ b/tests/ui/sized-hierarchy/pretty-print-no-feat-dep-has-feat.stderr
@@ -0,0 +1,42 @@
+error[E0119]: conflicting implementations of trait `SizedTr` for type `X<_>`
+  --> $DIR/pretty-print-no-feat-dep-has-feat.rs:16:1
+   |
+LL | impl<T: Sized> SizedTr for X<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `pretty_print_dep`:
+           - impl<T> SizedTr for T;
+
+error[E0119]: conflicting implementations of trait `NegSizedTr` for type `X<_>`
+  --> $DIR/pretty-print-no-feat-dep-has-feat.rs:19:1
+   |
+LL | impl<T: ?Sized> NegSizedTr for X<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `pretty_print_dep`:
+           - impl<T> NegSizedTr for T
+             where T: ?Sized;
+
+error[E0119]: conflicting implementations of trait `MetaSizedTr` for type `X<_>`
+  --> $DIR/pretty-print-no-feat-dep-has-feat.rs:22:1
+   |
+LL | impl<T: ?Sized> MetaSizedTr for X<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `pretty_print_dep`:
+           - impl<T> MetaSizedTr for T
+             where T: ?Sized;
+
+error[E0119]: conflicting implementations of trait `PointeeSizedTr` for type `X<_>`
+  --> $DIR/pretty-print-no-feat-dep-has-feat.rs:25:1
+   |
+LL | impl<T: ?Sized> PointeeSizedTr for X<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `pretty_print_dep`:
+           - impl<T> PointeeSizedTr for T
+             where T: ?Sized;
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/sized-hierarchy/pretty-print-no-feat.rs b/tests/ui/sized-hierarchy/pretty-print-no-feat.rs
new file mode 100644
index 00000000000..d5800be5828
--- /dev/null
+++ b/tests/ui/sized-hierarchy/pretty-print-no-feat.rs
@@ -0,0 +1,19 @@
+//@ aux-build:pretty-print-no-feat-dep.rs
+//@ compile-flags: --crate-type=lib
+
+extern crate pretty_print_no_feat_dep;
+use pretty_print_no_feat_dep::{SizedTr, NegSizedTr};
+
+// Test that printing the sizedness trait bounds in the conflicting impl error without enabling
+// `sized_hierarchy` will continue to print `?Sized`.
+//
+// It isn't possible to write a test that matches the multiline note containing the important
+// diagnostic output being tested - so check the stderr changes carefully!
+
+struct X<T>(T);
+
+impl<T: Sized> SizedTr for X<T> {}
+//~^ ERROR conflicting implementations of trait `SizedTr` for type `X<_>`
+
+impl<T: ?Sized> NegSizedTr for X<T> {}
+//~^ ERROR conflicting implementations of trait `NegSizedTr` for type `X<_>`
diff --git a/tests/ui/sized-hierarchy/pretty-print-no-feat.stderr b/tests/ui/sized-hierarchy/pretty-print-no-feat.stderr
new file mode 100644
index 00000000000..1d50f0145fe
--- /dev/null
+++ b/tests/ui/sized-hierarchy/pretty-print-no-feat.stderr
@@ -0,0 +1,22 @@
+error[E0119]: conflicting implementations of trait `SizedTr` for type `X<_>`
+  --> $DIR/pretty-print-no-feat.rs:15:1
+   |
+LL | impl<T: Sized> SizedTr for X<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `pretty_print_no_feat_dep`:
+           - impl<T> SizedTr for T;
+
+error[E0119]: conflicting implementations of trait `NegSizedTr` for type `X<_>`
+  --> $DIR/pretty-print-no-feat.rs:18:1
+   |
+LL | impl<T: ?Sized> NegSizedTr for X<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `pretty_print_no_feat_dep`:
+           - impl<T> NegSizedTr for T
+             where T: ?Sized;
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/sized-hierarchy/pretty-print-opaque-no-feat.rs b/tests/ui/sized-hierarchy/pretty-print-opaque-no-feat.rs
new file mode 100644
index 00000000000..955108a2074
--- /dev/null
+++ b/tests/ui/sized-hierarchy/pretty-print-opaque-no-feat.rs
@@ -0,0 +1,13 @@
+//@ compile-flags: --crate-type=lib
+
+pub trait Tr {}
+impl Tr for u32 {}
+
+pub fn foo() -> Box<impl Tr + ?Sized> {
+    if true {
+        let x = foo();
+        let y: Box<dyn Tr> = x;
+//~^ ERROR: the size for values of type `impl Tr + ?Sized` cannot be known
+    }
+    Box::new(1u32)
+}
diff --git a/tests/ui/sized-hierarchy/pretty-print-opaque-no-feat.stderr b/tests/ui/sized-hierarchy/pretty-print-opaque-no-feat.stderr
new file mode 100644
index 00000000000..bbe19870937
--- /dev/null
+++ b/tests/ui/sized-hierarchy/pretty-print-opaque-no-feat.stderr
@@ -0,0 +1,12 @@
+error[E0277]: the size for values of type `impl Tr + ?Sized` cannot be known at compilation time
+  --> $DIR/pretty-print-opaque-no-feat.rs:9:30
+   |
+LL |         let y: Box<dyn Tr> = x;
+   |                              ^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `impl Tr + ?Sized`
+   = note: required for the cast from `Box<impl Tr + ?Sized>` to `Box<dyn Tr>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/sized-hierarchy/pretty-print-opaque.rs b/tests/ui/sized-hierarchy/pretty-print-opaque.rs
new file mode 100644
index 00000000000..2aceee23a01
--- /dev/null
+++ b/tests/ui/sized-hierarchy/pretty-print-opaque.rs
@@ -0,0 +1,45 @@
+//@ compile-flags: --crate-type=lib
+#![feature(sized_hierarchy)]
+
+use std::marker::{MetaSized, PointeeSized};
+
+pub trait Tr: PointeeSized {}
+impl Tr for u32 {}
+
+pub fn sized() -> Box<impl Tr + Sized> {
+    if true {
+        let x = sized();
+        let y: Box<dyn Tr> = x;
+    }
+    Box::new(1u32)
+}
+
+pub fn neg_sized() -> Box<impl Tr + ?Sized> {
+    if true {
+        let x = neg_sized();
+        let y: Box<dyn Tr> = x;
+//~^ ERROR: the size for values of type `impl Tr + MetaSized` cannot be known
+    }
+    Box::new(1u32)
+}
+
+pub fn metasized() -> Box<impl Tr + MetaSized> {
+    if true {
+        let x = metasized();
+        let y: Box<dyn Tr> = x;
+//~^ ERROR: the size for values of type `impl Tr + MetaSized` cannot be known
+    }
+    Box::new(1u32)
+}
+
+pub fn pointeesized() -> Box<impl Tr + PointeeSized> {
+//~^ ERROR: the size for values of type `impl Tr + PointeeSized` cannot be known
+    if true {
+        let x = pointeesized();
+//~^ ERROR: the size for values of type `impl Tr + PointeeSized` cannot be known
+        let y: Box<dyn Tr> = x;
+//~^ ERROR: the size for values of type `impl Tr + PointeeSized` cannot be known
+//~| ERROR: the size for values of type `impl Tr + PointeeSized` cannot be known
+    }
+    Box::new(1u32)
+}
diff --git a/tests/ui/sized-hierarchy/pretty-print-opaque.stderr b/tests/ui/sized-hierarchy/pretty-print-opaque.stderr
new file mode 100644
index 00000000000..ecf4d912be8
--- /dev/null
+++ b/tests/ui/sized-hierarchy/pretty-print-opaque.stderr
@@ -0,0 +1,59 @@
+error[E0277]: the size for values of type `impl Tr + PointeeSized` cannot be known
+  --> $DIR/pretty-print-opaque.rs:35:26
+   |
+LL | pub fn pointeesized() -> Box<impl Tr + PointeeSized> {
+   |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a known size
+   |
+   = help: the trait `MetaSized` is not implemented for `impl Tr + PointeeSized`
+note: required by a bound in `Box`
+  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+
+error[E0277]: the size for values of type `impl Tr + MetaSized` cannot be known at compilation time
+  --> $DIR/pretty-print-opaque.rs:20:30
+   |
+LL |         let y: Box<dyn Tr> = x;
+   |                              ^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `impl Tr + MetaSized`
+   = note: required for the cast from `Box<impl Tr + MetaSized>` to `Box<dyn Tr>`
+
+error[E0277]: the size for values of type `impl Tr + MetaSized` cannot be known at compilation time
+  --> $DIR/pretty-print-opaque.rs:29:30
+   |
+LL |         let y: Box<dyn Tr> = x;
+   |                              ^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `impl Tr + MetaSized`
+   = note: required for the cast from `Box<impl Tr + MetaSized>` to `Box<dyn Tr>`
+
+error[E0277]: the size for values of type `impl Tr + PointeeSized` cannot be known
+  --> $DIR/pretty-print-opaque.rs:38:17
+   |
+LL |         let x = pointeesized();
+   |                 ^^^^^^^^^^^^^^ doesn't have a known size
+   |
+   = help: the trait `MetaSized` is not implemented for `impl Tr + PointeeSized`
+note: required by a bound in `Box`
+  --> $SRC_DIR/alloc/src/boxed.rs:LL:COL
+
+error[E0277]: the size for values of type `impl Tr + PointeeSized` cannot be known at compilation time
+  --> $DIR/pretty-print-opaque.rs:40:30
+   |
+LL |         let y: Box<dyn Tr> = x;
+   |                              ^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `impl Tr + PointeeSized`
+   = note: required for the cast from `Box<impl Tr + PointeeSized>` to `Box<dyn Tr>`
+
+error[E0277]: the size for values of type `impl Tr + PointeeSized` cannot be known
+  --> $DIR/pretty-print-opaque.rs:40:30
+   |
+LL |         let y: Box<dyn Tr> = x;
+   |                              ^ doesn't have a known size
+   |
+   = help: the trait `MetaSized` is not implemented for `impl Tr + PointeeSized`
+   = note: required for the cast from `Box<impl Tr + PointeeSized>` to `Box<dyn Tr>`
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/sized-hierarchy/pretty-print.rs b/tests/ui/sized-hierarchy/pretty-print.rs
new file mode 100644
index 00000000000..0908e76490c
--- /dev/null
+++ b/tests/ui/sized-hierarchy/pretty-print.rs
@@ -0,0 +1,28 @@
+//@ aux-build:pretty-print-dep.rs
+//@ compile-flags: --crate-type=lib
+#![feature(sized_hierarchy)]
+
+// Test that printing the sizedness trait bounds in the conflicting impl error with
+// `sized_hierarchy` enabled prints all of the appropriate bounds.
+//
+// It isn't possible to write a test that matches the multiline note containing the important
+// diagnostic output being tested - so check the stderr changes carefully!
+
+use std::marker::{MetaSized, PointeeSized};
+
+extern crate pretty_print_dep;
+use pretty_print_dep::{SizedTr, MetaSizedTr, PointeeSizedTr};
+
+struct X<T>(T);
+
+impl<T: Sized> SizedTr for X<T> {}
+//~^ ERROR conflicting implementations of trait `SizedTr` for type `X<_>`
+
+impl<T: ?Sized> pretty_print_dep::NegSizedTr for X<T> {}
+//~^ ERROR conflicting implementations of trait `NegSizedTr` for type `X<_>`
+
+impl<T: MetaSized> MetaSizedTr for X<T> {}
+//~^ ERROR conflicting implementations of trait `MetaSizedTr` for type `X<_>`
+
+impl<T: PointeeSized> PointeeSizedTr for X<T> {}
+//~^ ERROR conflicting implementations of trait `PointeeSizedTr` for type `X<_>`
diff --git a/tests/ui/sized-hierarchy/pretty-print.stderr b/tests/ui/sized-hierarchy/pretty-print.stderr
new file mode 100644
index 00000000000..3602c804945
--- /dev/null
+++ b/tests/ui/sized-hierarchy/pretty-print.stderr
@@ -0,0 +1,43 @@
+error[E0119]: conflicting implementations of trait `SizedTr` for type `X<_>`
+  --> $DIR/pretty-print.rs:18:1
+   |
+LL | impl<T: Sized> SizedTr for X<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `pretty_print_dep`:
+           - impl<T> SizedTr for T
+             where T: Sized;
+
+error[E0119]: conflicting implementations of trait `NegSizedTr` for type `X<_>`
+  --> $DIR/pretty-print.rs:21:1
+   |
+LL | impl<T: ?Sized> pretty_print_dep::NegSizedTr for X<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `pretty_print_dep`:
+           - impl<T> NegSizedTr for T
+             where T: MetaSized;
+
+error[E0119]: conflicting implementations of trait `MetaSizedTr` for type `X<_>`
+  --> $DIR/pretty-print.rs:24:1
+   |
+LL | impl<T: MetaSized> MetaSizedTr for X<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `pretty_print_dep`:
+           - impl<T> MetaSizedTr for T
+             where T: MetaSized;
+
+error[E0119]: conflicting implementations of trait `PointeeSizedTr` for type `X<_>`
+  --> $DIR/pretty-print.rs:27:1
+   |
+LL | impl<T: PointeeSized> PointeeSizedTr for X<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: conflicting implementation in crate `pretty_print_dep`:
+           - impl<T> PointeeSizedTr for T
+             where T: PointeeSized;
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/sized-hierarchy/trait-aliases.rs b/tests/ui/sized-hierarchy/trait-aliases.rs
new file mode 100644
index 00000000000..ffec302adaa
--- /dev/null
+++ b/tests/ui/sized-hierarchy/trait-aliases.rs
@@ -0,0 +1,9 @@
+//@ check-pass
+//@ compile-flags: --crate-type=lib
+#![feature(trait_alias)]
+
+// Checks that `?Sized` in a trait alias doesn't trigger an ICE.
+
+use std::ops::{Index, IndexMut};
+
+pub trait SlicePrereq<T> = ?Sized + IndexMut<usize, Output = <[T] as Index<usize>>::Output>;
diff --git a/tests/ui/span/E0535.rs b/tests/ui/span/E0535.rs
deleted file mode 100644
index e26334e9bbd..00000000000
--- a/tests/ui/span/E0535.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-#[inline(unknown)] //~ ERROR E0535
-pub fn something() {}
-
-fn main() {
-    something();
-}
diff --git a/tests/ui/span/E0535.stderr b/tests/ui/span/E0535.stderr
deleted file mode 100644
index 9060b687f50..00000000000
--- a/tests/ui/span/E0535.stderr
+++ /dev/null
@@ -1,11 +0,0 @@
-error[E0535]: invalid argument
-  --> $DIR/E0535.rs:1:10
-   |
-LL | #[inline(unknown)]
-   |          ^^^^^^^
-   |
-   = help: valid inline arguments are `always` and `never`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0535`.
diff --git a/tests/ui/span/E0539.rs b/tests/ui/span/E0539.rs
new file mode 100644
index 00000000000..e0c6dbfc591
--- /dev/null
+++ b/tests/ui/span/E0539.rs
@@ -0,0 +1,6 @@
+#[inline(unknown)] //~ ERROR malformed `inline` attribute
+pub fn something() {}
+
+fn main() {
+    something();
+}
diff --git a/tests/ui/span/E0539.stderr b/tests/ui/span/E0539.stderr
new file mode 100644
index 00000000000..01f091a2676
--- /dev/null
+++ b/tests/ui/span/E0539.stderr
@@ -0,0 +1,20 @@
+error[E0539]: malformed `inline` attribute input
+  --> $DIR/E0539.rs:1:1
+   |
+LL | #[inline(unknown)]
+   | ^^^^^^^^^-------^^
+   |          |
+   |          valid arguments are `always` or `never`
+   |
+help: try changing it to one of the following valid forms of the attribute
+   |
+LL - #[inline(unknown)]
+LL + #[inline(always|never)]
+   |
+LL - #[inline(unknown)]
+LL + #[inline]
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0539`.
diff --git a/tests/ui/stability-attribute/stability-attribute-sanity-2.rs b/tests/ui/stability-attribute/stability-attribute-sanity-2.rs
index de3ea4eaca9..92e300d33d6 100644
--- a/tests/ui/stability-attribute/stability-attribute-sanity-2.rs
+++ b/tests/ui/stability-attribute/stability-attribute-sanity-2.rs
@@ -4,7 +4,7 @@
 
 #![stable(feature = "stable_test_feature", since = "1.0.0")]
 
-#[stable(feature = "a", feature = "b", since = "1.0.0")] //~ ERROR multiple 'feature' items
+#[stable(feature = "a", feature = "b", since = "1.0.0")] //~ ERROR malformed `stable` attribute input [E0538]
 fn f1() { }
 
 #[stable(feature = "a", sinse = "1.0.0")] //~ ERROR unknown meta item 'sinse'
diff --git a/tests/ui/stability-attribute/stability-attribute-sanity-2.stderr b/tests/ui/stability-attribute/stability-attribute-sanity-2.stderr
index 8dbcc6c97ef..5b35a51cad7 100644
--- a/tests/ui/stability-attribute/stability-attribute-sanity-2.stderr
+++ b/tests/ui/stability-attribute/stability-attribute-sanity-2.stderr
@@ -1,8 +1,11 @@
-error[E0538]: multiple 'feature' items
-  --> $DIR/stability-attribute-sanity-2.rs:7:25
+error[E0538]: malformed `stable` attribute input
+  --> $DIR/stability-attribute-sanity-2.rs:7:1
    |
 LL | #[stable(feature = "a", feature = "b", since = "1.0.0")]
-   |                         ^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^^^^-------^^^^^^^^^^^^^^^^^^^^^^^^^
+   | |                       |
+   | |                       found `feature` used as a key more than once
+   | help: must be of the form: `#[stable(feature = "name", since = "version")]`
 
 error[E0541]: unknown meta item 'sinse'
   --> $DIR/stability-attribute-sanity-2.rs:10:25
diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.rs b/tests/ui/stability-attribute/stability-attribute-sanity.rs
index f46e35e1a72..c4c86e12d26 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 expected a quoted string literal [E0539]
+    #[stable(feature = "a", since)] //~ ERROR malformed `stable` attribute input [E0539]
     fn f2() { }
 
-    #[stable(feature, since = "3.3.3")] //~ ERROR expected a quoted string literal [E0539]
+    #[stable(feature, since = "3.3.3")] //~ ERROR malformed `stable` attribute input [E0539]
     fn f3() { }
 
-    #[stable(feature = "a", since(b))] //~ ERROR expected a quoted string literal [E0539]
+    #[stable(feature = "a", since(b))] //~ ERROR malformed `stable` attribute input [E0539]
     fn f5() { }
 
-    #[stable(feature(b), since = "3.3.3")] //~ ERROR expected a quoted string literal [E0539]
+    #[stable(feature(b), since = "3.3.3")] //~ ERROR malformed `stable` attribute input [E0539]
     fn f6() { }
 }
 
diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.stderr b/tests/ui/stability-attribute/stability-attribute-sanity.stderr
index 2e2b5b509c8..ae948237d7e 100644
--- a/tests/ui/stability-attribute/stability-attribute-sanity.stderr
+++ b/tests/ui/stability-attribute/stability-attribute-sanity.stderr
@@ -4,29 +4,41 @@ error[E0541]: unknown meta item 'reason'
 LL |     #[stable(feature = "a", since = "4.4.4", reason)]
    |                                              ^^^^^^ expected one of `feature`, `since`
 
-error[E0539]: expected a quoted string literal
-  --> $DIR/stability-attribute-sanity.rs:11:29
+error[E0539]: malformed `stable` attribute input
+  --> $DIR/stability-attribute-sanity.rs:11:5
    |
 LL |     #[stable(feature = "a", since)]
-   |                             ^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^-----^^
+   |     |                       |
+   |     |                       expected this to be of the form `since = "..."`
+   |     help: must be of the form: `#[stable(feature = "name", since = "version")]`
 
-error[E0539]: expected a quoted string literal
-  --> $DIR/stability-attribute-sanity.rs:14:14
+error[E0539]: malformed `stable` attribute input
+  --> $DIR/stability-attribute-sanity.rs:14:5
    |
 LL |     #[stable(feature, since = "3.3.3")]
-   |              ^^^^^^^
+   |     ^^^^^^^^^-------^^^^^^^^^^^^^^^^^^^
+   |     |        |
+   |     |        expected this to be of the form `feature = "..."`
+   |     help: must be of the form: `#[stable(feature = "name", since = "version")]`
 
-error[E0539]: expected a quoted string literal
-  --> $DIR/stability-attribute-sanity.rs:17:29
+error[E0539]: malformed `stable` attribute input
+  --> $DIR/stability-attribute-sanity.rs:17:5
    |
 LL |     #[stable(feature = "a", since(b))]
-   |                             ^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^--------^^
+   |     |                       |
+   |     |                       expected this to be of the form `since = "..."`
+   |     help: must be of the form: `#[stable(feature = "name", since = "version")]`
 
-error[E0539]: expected a quoted string literal
-  --> $DIR/stability-attribute-sanity.rs:20:14
+error[E0539]: malformed `stable` attribute input
+  --> $DIR/stability-attribute-sanity.rs:20:5
    |
 LL |     #[stable(feature(b), since = "3.3.3")]
-   |              ^^^^^^^^^^
+   |     ^^^^^^^^^----------^^^^^^^^^^^^^^^^^^^
+   |     |        |
+   |     |        expected this to be of the form `feature = "..."`
+   |     help: must be of the form: `#[stable(feature = "name", since = "version")]`
 
 error[E0546]: missing 'feature'
   --> $DIR/stability-attribute-sanity.rs:25:5
diff --git a/tests/ui/stack-protector/warn-stack-protector-unsupported.rs b/tests/ui/stack-protector/warn-stack-protector-unsupported.rs
index dc61e35a089..a635976c842 100644
--- a/tests/ui/stack-protector/warn-stack-protector-unsupported.rs
+++ b/tests/ui/stack-protector/warn-stack-protector-unsupported.rs
@@ -11,8 +11,15 @@
 #![no_std]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+trait Sized: MetaSized {}
+
 #[lang = "copy"]
 trait Copy {}
 
diff --git a/tests/ui/structs/default-field-values/failures.rs b/tests/ui/structs/default-field-values/failures.rs
index dee6566bd0e..9c5b7172929 100644
--- a/tests/ui/structs/default-field-values/failures.rs
+++ b/tests/ui/structs/default-field-values/failures.rs
@@ -49,6 +49,12 @@ enum E {
     Variant {} //~ ERROR the `#[default]` attribute may only be used on unit enum variants
 }
 
+union U
+{
+    x: i32 = 1,  //~ ERROR unions cannot have default field values
+    y: f32 = 2., //~ ERROR unions cannot have default field values
+}
+
 fn main () {
     let _ = Foo { .. }; // ok
     let _ = Foo::default(); // ok
diff --git a/tests/ui/structs/default-field-values/failures.stderr b/tests/ui/structs/default-field-values/failures.stderr
index aaa75fd3180..5e3d4c89c2a 100644
--- a/tests/ui/structs/default-field-values/failures.stderr
+++ b/tests/ui/structs/default-field-values/failures.stderr
@@ -12,6 +12,18 @@ error: default fields are not supported in tuple structs
 LL | pub struct Rak(i32 = 42);
    |                      ^^ default fields are only supported on structs
 
+error: unions cannot have default field values
+  --> $DIR/failures.rs:54:14
+   |
+LL |     x: i32 = 1,
+   |              ^
+
+error: unions cannot have default field values
+  --> $DIR/failures.rs:55:14
+   |
+LL |     y: f32 = 2.,
+   |              ^^
+
 error[E0277]: the trait bound `S: Default` is not satisfied
   --> $DIR/failures.rs:16:5
    |
@@ -28,19 +40,19 @@ LL | pub struct S;
    |
 
 error: missing field `bar` in initializer
-  --> $DIR/failures.rs:55:19
+  --> $DIR/failures.rs:61:19
    |
 LL |     let _ = Bar { .. };
    |                   ^ fields that do not have a defaulted value must be provided explicitly
 
 error: missing field `bar` in initializer
-  --> $DIR/failures.rs:56:27
+  --> $DIR/failures.rs:62:27
    |
 LL |     let _ = Bar { baz: 0, .. };
    |                           ^ fields that do not have a defaulted value must be provided explicitly
 
 error[E0308]: mismatched types
-  --> $DIR/failures.rs:60:17
+  --> $DIR/failures.rs:66:17
    |
 LL |     let _ = Rak(..);
    |             --- ^^ expected `i32`, found `RangeFull`
@@ -53,19 +65,19 @@ note: tuple struct defined here
 LL | pub struct Rak(i32 = 42);
    |            ^^^
 help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal
-  --> $DIR/failures.rs:60:17
+  --> $DIR/failures.rs:66:17
    |
 LL |     let _ = Rak(..);
    |                 ^^
 
 error[E0061]: this struct takes 1 argument but 2 arguments were supplied
-  --> $DIR/failures.rs:62:13
+  --> $DIR/failures.rs:68:13
    |
 LL |     let _ = Rak(0, ..);
    |             ^^^    -- unexpected argument #2 of type `RangeFull`
    |
 help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal
-  --> $DIR/failures.rs:62:20
+  --> $DIR/failures.rs:68:20
    |
 LL |     let _ = Rak(0, ..);
    |                    ^^
@@ -81,13 +93,13 @@ LL +     let _ = Rak(0);
    |
 
 error[E0061]: this struct takes 1 argument but 2 arguments were supplied
-  --> $DIR/failures.rs:64:13
+  --> $DIR/failures.rs:70:13
    |
 LL |     let _ = Rak(.., 0);
    |             ^^^ -- unexpected argument #1 of type `RangeFull`
    |
 help: you might have meant to use `..` to skip providing a value for expected fields, but this is only supported on non-tuple struct literals; it is instead interpreted as a `std::ops::RangeFull` literal
-  --> $DIR/failures.rs:64:17
+  --> $DIR/failures.rs:70:17
    |
 LL |     let _ = Rak(.., 0);
    |                 ^^
@@ -102,7 +114,7 @@ LL -     let _ = Rak(.., 0);
 LL +     let _ = Rak(0);
    |
 
-error: aborting due to 8 previous errors
+error: aborting due to 10 previous errors
 
 Some errors have detailed explanations: E0061, E0277, E0308.
 For more information about an error, try `rustc --explain E0061`.
diff --git a/tests/ui/symbol-names/foreign-types.rs b/tests/ui/symbol-names/foreign-types.rs
index 2a9aadfcb83..b863e8c1759 100644
--- a/tests/ui/symbol-names/foreign-types.rs
+++ b/tests/ui/symbol-names/foreign-types.rs
@@ -2,13 +2,16 @@
 //@ compile-flags: -C symbol-mangling-version=v0
 
 #![feature(extern_types)]
+#![feature(sized_hierarchy)]
 #![feature(rustc_attrs)]
 
+use std::marker::PointeeSized;
+
 extern "C" {
     type ForeignType;
 }
 
-struct Check<T: ?Sized>(T);
+struct Check<T: PointeeSized>(T);
 
 #[rustc_symbol_name]
 //~^ ERROR symbol-name(_RMCs
diff --git a/tests/ui/symbol-names/foreign-types.stderr b/tests/ui/symbol-names/foreign-types.stderr
index 63044991485..4640ceae811 100644
--- a/tests/ui/symbol-names/foreign-types.stderr
+++ b/tests/ui/symbol-names/foreign-types.stderr
@@ -1,17 +1,17 @@
 error: symbol-name(_RMCsCRATE_HASH_13foreign_typesINtB<REF>_5CheckNtB<REF>_11ForeignTypeE)
-  --> $DIR/foreign-types.rs:13:1
+  --> $DIR/foreign-types.rs:16:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(<foreign_types[fcdd87e190ad88e3]::Check<foreign_types[fcdd87e190ad88e3]::ForeignType>>)
-  --> $DIR/foreign-types.rs:13:1
+  --> $DIR/foreign-types.rs:16:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(<foreign_types::Check<foreign_types::ForeignType>>)
-  --> $DIR/foreign-types.rs:13:1
+  --> $DIR/foreign-types.rs:16:1
    |
 LL | #[rustc_symbol_name]
    | ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/target-cpu/explicit-target-cpu.rs b/tests/ui/target-cpu/explicit-target-cpu.rs
index cd4c2384bc1..e4ae73b513b 100644
--- a/tests/ui/target-cpu/explicit-target-cpu.rs
+++ b/tests/ui/target-cpu/explicit-target-cpu.rs
@@ -29,6 +29,12 @@
 #![feature(no_core, lang_items)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang="sized"]
 trait Sized {}
 
diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.rs b/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.rs
index 270874a9f58..41d5de89ae6 100644
--- a/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.rs
+++ b/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.rs
@@ -5,8 +5,14 @@
 #![no_core]
 #![deny(aarch64_softfloat_neon)]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-pub trait Sized {}
+pub trait Sized: MetaSized {}
 
 #[target_feature(enable = "neon")]
 //~^ERROR: enabling the `neon` target feature on the current target is unsound
diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.stderr b/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.stderr
index bf745291a5a..a8a7063daeb 100644
--- a/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.stderr
+++ b/tests/ui/target-feature/abi-incompatible-target-feature-attribute-fcw.stderr
@@ -1,5 +1,5 @@
 error: enabling the `neon` target feature on the current target is unsound due to ABI issues
-  --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:11:18
+  --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:17:18
    |
 LL | #[target_feature(enable = "neon")]
    |                  ^^^^^^^^^^^^^^^
@@ -16,7 +16,7 @@ error: aborting due to 1 previous error
 
 Future incompatibility report: Future breakage diagnostic:
 error: enabling the `neon` target feature on the current target is unsound due to ABI issues
-  --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:11:18
+  --> $DIR/abi-incompatible-target-feature-attribute-fcw.rs:17:18
    |
 LL | #[target_feature(enable = "neon")]
    |                  ^^^^^^^^^^^^^^^
diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-attribute.riscv.stderr b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.riscv.stderr
index 49c5479275f..1b9b8e0a789 100644
--- a/tests/ui/target-feature/abi-incompatible-target-feature-attribute.riscv.stderr
+++ b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.riscv.stderr
@@ -1,5 +1,5 @@
 error: target feature `d` cannot be enabled with `#[target_feature]`: this feature is incompatible with the target ABI
-  --> $DIR/abi-incompatible-target-feature-attribute.rs:15:90
+  --> $DIR/abi-incompatible-target-feature-attribute.rs:21:90
    |
 LL | #[cfg_attr(x86, target_feature(enable = "soft-float"))] #[cfg_attr(riscv, target_feature(enable = "d"))]
    |                                                                                          ^^^^^^^^^^^^
diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-attribute.rs b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.rs
index a8733440759..c07b6c448e9 100644
--- a/tests/ui/target-feature/abi-incompatible-target-feature-attribute.rs
+++ b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.rs
@@ -9,6 +9,12 @@
 #![feature(no_core, lang_items, riscv_target_feature, x87_target_feature)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
 pub trait Sized {}
 
diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-attribute.x86.stderr b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.x86.stderr
index 81471fd7e30..e1409497232 100644
--- a/tests/ui/target-feature/abi-incompatible-target-feature-attribute.x86.stderr
+++ b/tests/ui/target-feature/abi-incompatible-target-feature-attribute.x86.stderr
@@ -1,5 +1,5 @@
 error: target feature `soft-float` cannot be enabled with `#[target_feature]`: this feature is incompatible with the target ABI
-  --> $DIR/abi-incompatible-target-feature-attribute.rs:15:32
+  --> $DIR/abi-incompatible-target-feature-attribute.rs:21:32
    |
 LL | #[cfg_attr(x86, target_feature(enable = "soft-float"))] #[cfg_attr(riscv, target_feature(enable = "d"))]
    |                                ^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs
index 68e1d3b9ddc..302cceccf69 100644
--- a/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs
+++ b/tests/ui/target-feature/abi-incompatible-target-feature-flag-enable.rs
@@ -11,6 +11,12 @@
 #![feature(no_core, lang_items, riscv_target_feature)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
 pub trait Sized {}
 #[lang = "freeze"]
diff --git a/tests/ui/target-feature/abi-irrelevant-target-feature-flag-disable.rs b/tests/ui/target-feature/abi-irrelevant-target-feature-flag-disable.rs
index 0013d033b9c..876134002ed 100644
--- a/tests/ui/target-feature/abi-irrelevant-target-feature-flag-disable.rs
+++ b/tests/ui/target-feature/abi-irrelevant-target-feature-flag-disable.rs
@@ -8,7 +8,13 @@
 #![feature(no_core, lang_items)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-pub trait Sized {}
+pub trait Sized: MetaSized {}
 
 //~? WARN unstable feature specified for `-Ctarget-feature`: `x87`
diff --git a/tests/ui/target-feature/abi-required-target-feature-attribute.rs b/tests/ui/target-feature/abi-required-target-feature-attribute.rs
index 95723c57f94..5eb9e85f85f 100644
--- a/tests/ui/target-feature/abi-required-target-feature-attribute.rs
+++ b/tests/ui/target-feature/abi-required-target-feature-attribute.rs
@@ -6,8 +6,14 @@
 #![feature(no_core, lang_items, x87_target_feature)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-pub trait Sized {}
+pub trait Sized: MetaSized {}
 
 #[target_feature(enable = "x87")]
 pub unsafe fn my_fun() {}
diff --git a/tests/ui/target-feature/abi-required-target-feature-flag-disable.rs b/tests/ui/target-feature/abi-required-target-feature-flag-disable.rs
index 98723e99c36..89736afe718 100644
--- a/tests/ui/target-feature/abi-required-target-feature-flag-disable.rs
+++ b/tests/ui/target-feature/abi-required-target-feature-flag-disable.rs
@@ -20,6 +20,12 @@
 #![feature(no_core, lang_items)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
 pub trait Sized {}
 
diff --git a/tests/ui/target-feature/feature-hierarchy.rs b/tests/ui/target-feature/feature-hierarchy.rs
index 315ec983a19..ccf32a35f72 100644
--- a/tests/ui/target-feature/feature-hierarchy.rs
+++ b/tests/ui/target-feature/feature-hierarchy.rs
@@ -12,10 +12,18 @@
 // Tests vetting "feature hierarchies" in the cases where we impose them.
 
 // Supporting minimal rust core code
+#[lang = "pointee_sized"]
+trait PointeeSized {}
+
+#[lang = "meta_sized"]
+trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+trait Sized: MetaSized {}
+
 #[lang = "copy"]
 trait Copy {}
+
 impl Copy for bool {}
 
 #[stable(feature = "test", since = "1.0.0")]
diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.rs
index 215e64979f7..e96e17a4212 100644
--- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.rs
+++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.rs
@@ -4,8 +4,14 @@
 #![feature(no_core, lang_items, riscv_target_feature)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-pub trait Sized {}
+pub trait Sized: MetaSized {}
 
 #[target_feature(enable = "d")]
 //~^ERROR: cannot be enabled with
diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.stderr
index 84d27463b38..9406c3bbfdc 100644
--- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.stderr
+++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-e-d.stderr
@@ -1,5 +1,5 @@
 error: target feature `d` cannot be enabled with `#[target_feature]`: this feature is incompatible with the target ABI
-  --> $DIR/forbidden-hardfloat-target-feature-attribute-e-d.rs:10:18
+  --> $DIR/forbidden-hardfloat-target-feature-attribute-e-d.rs:16:18
    |
 LL | #[target_feature(enable = "d")]
    |                  ^^^^^^^^^^^^
diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.rs
index d74f4a1d4b1..70075b1bb78 100644
--- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.rs
+++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.rs
@@ -4,6 +4,12 @@
 #![feature(no_core, lang_items, riscv_target_feature)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
 pub trait Sized {}
 
diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.stderr
index af0e53f34f2..8c98d847e17 100644
--- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.stderr
+++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-attribute-f-zfinx.stderr
@@ -1,5 +1,5 @@
 error: target feature `zfinx` cannot be enabled with `#[target_feature]`: this feature is incompatible with the target ABI
-  --> $DIR/forbidden-hardfloat-target-feature-attribute-f-zfinx.rs:10:18
+  --> $DIR/forbidden-hardfloat-target-feature-attribute-f-zfinx.rs:16:18
    |
 LL | #[target_feature(enable = "zdinx")]
    |                  ^^^^^^^^^^^^^^^^
diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-cfg.rs b/tests/ui/target-feature/forbidden-hardfloat-target-feature-cfg.rs
new file mode 100644
index 00000000000..2692cf802f2
--- /dev/null
+++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-cfg.rs
@@ -0,0 +1,20 @@
+//@ compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=lib
+//@ needs-llvm-components: x86
+//@ check-pass
+#![feature(no_core, lang_items)]
+#![no_core]
+#![allow(unexpected_cfgs)]
+
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
+#[lang = "sized"]
+pub trait Sized: MetaSized {}
+
+// The compile_error macro does not exist, so if the `cfg` evaluates to `true` this
+// complains about the missing macro rather than showing the error... but that's good enough.
+#[cfg(not(target_feature = "x87"))]
+compile_error!("the x87 feature *should* be exposed in `cfg`");
diff --git a/tests/ui/target-feature/forbidden-target-feature-attribute.rs b/tests/ui/target-feature/forbidden-target-feature-attribute.rs
index 6bb6f8aaffb..a59747ec80f 100644
--- a/tests/ui/target-feature/forbidden-target-feature-attribute.rs
+++ b/tests/ui/target-feature/forbidden-target-feature-attribute.rs
@@ -4,8 +4,14 @@
 #![feature(no_core, lang_items)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-pub trait Sized {}
+pub trait Sized: MetaSized {}
 
 #[target_feature(enable = "forced-atomics")]
 //~^ERROR: cannot be enabled with
diff --git a/tests/ui/target-feature/forbidden-target-feature-attribute.stderr b/tests/ui/target-feature/forbidden-target-feature-attribute.stderr
index f8ea0c0e793..65814e8edcf 100644
--- a/tests/ui/target-feature/forbidden-target-feature-attribute.stderr
+++ b/tests/ui/target-feature/forbidden-target-feature-attribute.stderr
@@ -1,5 +1,5 @@
 error: target feature `forced-atomics` cannot be enabled with `#[target_feature]`: unsound because it changes the ABI of atomic operations
-  --> $DIR/forbidden-target-feature-attribute.rs:10:18
+  --> $DIR/forbidden-target-feature-attribute.rs:16:18
    |
 LL | #[target_feature(enable = "forced-atomics")]
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/target-feature/forbidden-target-feature-cfg.rs b/tests/ui/target-feature/forbidden-target-feature-cfg.rs
index e848ffde018..c21eb63257a 100644
--- a/tests/ui/target-feature/forbidden-target-feature-cfg.rs
+++ b/tests/ui/target-feature/forbidden-target-feature-cfg.rs
@@ -6,8 +6,14 @@
 #![no_core]
 #![allow(unexpected_cfgs)]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-pub trait Sized {}
+pub trait Sized: MetaSized {}
 
 // The compile_error macro does not exist, so if the `cfg` evaluates to `true` this
 // complains about the missing macro rather than showing the error... but that's good enough.
diff --git a/tests/ui/target-feature/forbidden-target-feature-flag-disable.rs b/tests/ui/target-feature/forbidden-target-feature-flag-disable.rs
index d394dbe7b15..4d4d833caab 100644
--- a/tests/ui/target-feature/forbidden-target-feature-flag-disable.rs
+++ b/tests/ui/target-feature/forbidden-target-feature-flag-disable.rs
@@ -8,7 +8,13 @@
 #![feature(no_core, lang_items)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-pub trait Sized {}
+pub trait Sized: MetaSized {}
 
 //~? WARN target feature `forced-atomics` cannot be disabled with `-Ctarget-feature`: unsound because it changes the ABI of atomic operations
diff --git a/tests/ui/target-feature/forbidden-target-feature-flag.rs b/tests/ui/target-feature/forbidden-target-feature-flag.rs
index a04d7e34753..6e3e60e0409 100644
--- a/tests/ui/target-feature/forbidden-target-feature-flag.rs
+++ b/tests/ui/target-feature/forbidden-target-feature-flag.rs
@@ -8,7 +8,13 @@
 #![feature(no_core, lang_items)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-pub trait Sized {}
+pub trait Sized: MetaSized {}
 
 //~? WARN target feature `forced-atomics` cannot be enabled with `-Ctarget-feature`: unsound because it changes the ABI of atomic operations
diff --git a/tests/ui/target-feature/target-cpu-lacks-required-target-feature.rs b/tests/ui/target-feature/target-cpu-lacks-required-target-feature.rs
index be6cd2b6faf..fcb8c382741 100644
--- a/tests/ui/target-feature/target-cpu-lacks-required-target-feature.rs
+++ b/tests/ui/target-feature/target-cpu-lacks-required-target-feature.rs
@@ -7,7 +7,13 @@
 #![feature(no_core, lang_items)]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-pub trait Sized {}
+pub trait Sized: MetaSized {}
 
 //~? WARN target feature `sse2` must be enabled to ensure that the ABI of the current target can be implemented correctly
diff --git a/tests/ui/target-feature/tied-features-cli.rs b/tests/ui/target-feature/tied-features-cli.rs
index ce1dc3224a1..e9de4561ced 100644
--- a/tests/ui/target-feature/tied-features-cli.rs
+++ b/tests/ui/target-feature/tied-features-cli.rs
@@ -14,8 +14,14 @@
 #![feature(no_core, lang_items)]
 #![no_core]
 
-#[lang="sized"]
-trait Sized {}
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
+#[lang = "sized"]
+pub trait Sized: MetaSized {}
 
 fn main() {}
 
diff --git a/tests/ui/target-feature/tied-features-no-implication-1.rs b/tests/ui/target-feature/tied-features-no-implication-1.rs
index 63a1d77dae9..6c6e9e06b6e 100644
--- a/tests/ui/target-feature/tied-features-no-implication-1.rs
+++ b/tests/ui/target-feature/tied-features-no-implication-1.rs
@@ -6,8 +6,14 @@
 #![feature(no_core, lang_items)]
 #![no_core]
 
-#[lang="sized"]
-trait Sized {}
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
+#[lang = "sized"]
+pub trait Sized: MetaSized {}
 
 // In this test, demonstrate that +paca and +pacg both result in the tied feature error if there
 // isn't something causing an error.
diff --git a/tests/ui/target-feature/tied-features-no-implication.pacg.stderr b/tests/ui/target-feature/tied-features-no-implication.pacg.stderr
index 4ff42d31e94..8b034c098d0 100644
--- a/tests/ui/target-feature/tied-features-no-implication.pacg.stderr
+++ b/tests/ui/target-feature/tied-features-no-implication.pacg.stderr
@@ -1,5 +1,5 @@
 error[E0428]: the name `foo` is defined multiple times
-  --> $DIR/tied-features-no-implication.rs:27:1
+  --> $DIR/tied-features-no-implication.rs:33:1
    |
 LL | fn foo() {}
    | -------- previous definition of the value `foo` here
diff --git a/tests/ui/target-feature/tied-features-no-implication.rs b/tests/ui/target-feature/tied-features-no-implication.rs
index 1625f71431a..5e38d5329f3 100644
--- a/tests/ui/target-feature/tied-features-no-implication.rs
+++ b/tests/ui/target-feature/tied-features-no-implication.rs
@@ -7,8 +7,14 @@
 #![feature(no_core, lang_items)]
 #![no_core]
 
-#[lang="sized"]
-trait Sized {}
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
+#[lang = "sized"]
+pub trait Sized: MetaSized {}
 
 // Can't use `compile_error!` here without `core`/`std` but requiring these makes this test only
 // work if you have libcore built in the sysroot for `aarch64-unknown-linux-gnu`. Can't run this
diff --git a/tests/ui/traits/cache-reached-depth-ice.rs b/tests/ui/traits/cache-reached-depth-ice.rs
index 8c2391113d7..bc62adf4842 100644
--- a/tests/ui/traits/cache-reached-depth-ice.rs
+++ b/tests/ui/traits/cache-reached-depth-ice.rs
@@ -1,4 +1,5 @@
-#![feature(rustc_attrs)]
+#![feature(rustc_attrs, sized_hierarchy)]
+use std::marker::PointeeSized;
 
 // Test for a particular corner case where the evaluation
 // cache can get out of date. The problem here is that
@@ -37,7 +38,7 @@ struct C {
 }
 
 #[rustc_evaluate_where_clauses]
-fn test<X: ?Sized + Send>() {}
+fn test<X: PointeeSized + Send>() {}
 
 fn main() {
     test::<A>();
diff --git a/tests/ui/traits/cache-reached-depth-ice.stderr b/tests/ui/traits/cache-reached-depth-ice.stderr
index e84ebc91ae1..fd76dc92dfb 100644
--- a/tests/ui/traits/cache-reached-depth-ice.stderr
+++ b/tests/ui/traits/cache-reached-depth-ice.stderr
@@ -1,8 +1,8 @@
 error: evaluate(Binder { value: TraitPredicate(<A as std::marker::Send>, polarity:Positive), bound_vars: [] }) = Ok(EvaluatedToOk)
-  --> $DIR/cache-reached-depth-ice.rs:43:5
+  --> $DIR/cache-reached-depth-ice.rs:44:5
    |
-LL | fn test<X: ?Sized + Send>() {}
-   |                     ---- predicate
+LL | fn test<X: PointeeSized + Send>() {}
+   |                           ---- predicate
 ...
 LL |     test::<A>();
    |     ^^^^^^^^^
diff --git a/tests/ui/traits/const-traits/auxiliary/minicore.rs b/tests/ui/traits/const-traits/auxiliary/minicore.rs
index 08d7817548d..073337b2ac6 100644
--- a/tests/ui/traits/const-traits/auxiliary/minicore.rs
+++ b/tests/ui/traits/const-traits/auxiliary/minicore.rs
@@ -12,20 +12,27 @@
     fundamental,
     marker_trait_attr,
     const_trait_impl,
-    const_destruct
+    const_destruct,
 )]
 #![allow(internal_features, incomplete_features)]
 #![no_std]
 #![no_core]
 
+#[lang = "pointee_sized"]
+pub trait PointeeSized {}
+
+#[lang = "meta_sized"]
+pub trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-pub trait Sized {}
+pub trait Sized: MetaSized {}
+
 #[lang = "copy"]
 pub trait Copy {}
 
 impl Copy for bool {}
 impl Copy for u8 {}
-impl<T: ?Sized> Copy for &T {}
+impl<T: PointeeSized> Copy for &T {}
 
 #[lang = "add"]
 #[const_trait]
@@ -106,17 +113,17 @@ pub trait Tuple {}
 #[lang = "legacy_receiver"]
 pub trait LegacyReceiver {}
 
-impl<T: ?Sized> LegacyReceiver for &T {}
+impl<T: PointeeSized> LegacyReceiver for &T {}
 
-impl<T: ?Sized> LegacyReceiver for &mut T {}
+impl<T: PointeeSized> LegacyReceiver for &mut T {}
 
 #[lang = "receiver"]
 pub trait Receiver {
     #[lang = "receiver_target"]
-    type Target: ?Sized;
+    type Target: MetaSized;
 }
 
-impl<T: Deref + ?Sized> Receiver for T {
+impl<T: Deref + MetaSized> Receiver for T {
     type Target = <T as Deref>::Target;
 }
 
@@ -162,15 +169,15 @@ fn panic_fmt() {}
 
 #[lang = "index"]
 #[const_trait]
-pub trait Index<Idx: ?Sized> {
-    type Output: ?Sized;
+pub trait Index<Idx: PointeeSized> {
+    type Output: MetaSized;
 
     fn index(&self, index: Idx) -> &Self::Output;
 }
 
 #[const_trait]
-pub unsafe trait SliceIndex<T: ?Sized> {
-    type Output: ?Sized;
+pub unsafe trait SliceIndex<T: PointeeSized> {
+    type Output: MetaSized;
     fn index(self, slice: &T) -> &Self::Output;
 }
 
@@ -199,23 +206,23 @@ where
 }
 
 #[lang = "unsize"]
-pub trait Unsize<T: ?Sized> {}
+pub trait Unsize<T: PointeeSized>: PointeeSized {}
 
 #[lang = "coerce_unsized"]
-pub trait CoerceUnsized<T: ?Sized> {}
+pub trait CoerceUnsized<T: PointeeSized> {}
 
-impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
+impl<'a, 'b: 'a, T: PointeeSized + Unsize<U>, U: PointeeSized> CoerceUnsized<&'a U> for &'b T {}
 
 #[lang = "deref"]
 #[const_trait]
 pub trait Deref {
     #[lang = "deref_target"]
-    type Target: ?Sized;
+    type Target: MetaSized;
 
     fn deref(&self) -> &Self::Target;
 }
 
-impl<T: ?Sized> const Deref for &T {
+impl<T: MetaSized> const Deref for &T {
     type Target = T;
 
     fn deref(&self) -> &T {
@@ -223,7 +230,7 @@ impl<T: ?Sized> const Deref for &T {
     }
 }
 
-impl<T: ?Sized> const Deref for &mut T {
+impl<T: MetaSized> const Deref for &mut T {
     type Target = T;
 
     fn deref(&self) -> &T {
@@ -307,14 +314,14 @@ fn from_str(s: &str) -> Result<bool, ()> {
 
 #[lang = "eq"]
 #[const_trait]
-pub trait PartialEq<Rhs: ?Sized = Self> {
+pub trait PartialEq<Rhs: PointeeSized = Self>: PointeeSized {
     fn eq(&self, other: &Rhs) -> bool;
     fn ne(&self, other: &Rhs) -> bool {
         !self.eq(other)
     }
 }
 
-impl<A: ?Sized, B: ?Sized> const PartialEq<&B> for &A
+impl<A: PointeeSized, B: PointeeSized> const PartialEq<&B> for &A
 where
     A: ~const PartialEq<B>,
 {
@@ -357,7 +364,7 @@ impl<P> Pin<P> {
     }
 }
 
-impl<'a, T: ?Sized> Pin<&'a T> {
+impl<'a, T: PointeeSized> Pin<&'a T> {
     const fn get_ref(self) -> &'a T {
         self.pointer
     }
@@ -372,7 +379,7 @@ impl<P: Deref> Pin<P> {
     }
 }
 
-impl<'a, T: ?Sized> Pin<&'a mut T> {
+impl<'a, T: PointeeSized> Pin<&'a mut T> {
     const unsafe fn get_unchecked_mut(self) -> &'a mut T {
         self.pointer
     }
@@ -418,7 +425,7 @@ impl<T: Clone> Clone for RefCell<T> {
     }
 }
 
-struct RefCell<T: ?Sized> {
+struct RefCell<T: PointeeSized> {
     borrow: UnsafeCell<()>,
     value: UnsafeCell<T>,
 }
@@ -427,7 +434,7 @@ impl<T> RefCell<T> {
         loop {}
     }
 }
-impl<T: ?Sized> RefCell<T> {
+impl<T: PointeeSized> RefCell<T> {
     fn borrow(&self) -> Ref<'_, T> {
         loop {}
     }
@@ -435,16 +442,16 @@ impl<T: ?Sized> RefCell<T> {
 
 #[lang = "unsafe_cell"]
 #[repr(transparent)]
-struct UnsafeCell<T: ?Sized> {
+struct UnsafeCell<T: PointeeSized> {
     value: T,
 }
 
-struct Ref<'b, T: ?Sized + 'b> {
+struct Ref<'b, T: PointeeSized + 'b> {
     value: *const T,
     borrow: &'b UnsafeCell<()>,
 }
 
-impl<T: ?Sized> Deref for Ref<'_, T> {
+impl<T: MetaSized> Deref for Ref<'_, T> {
     type Target = T;
 
     #[inline]
diff --git a/tests/ui/traits/default_auto_traits/backward-compatible-lazy-bounds-pass.rs b/tests/ui/traits/default_auto_traits/backward-compatible-lazy-bounds-pass.rs
index 3818456d3a6..745b6ee9bc5 100644
--- a/tests/ui/traits/default_auto_traits/backward-compatible-lazy-bounds-pass.rs
+++ b/tests/ui/traits/default_auto_traits/backward-compatible-lazy-bounds-pass.rs
@@ -5,8 +5,14 @@
 #![no_std]
 #![no_core]
 
+#[lang = "pointee_sized"]
+trait PointeeSized {}
+
+#[lang = "meta_sized"]
+trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+trait Sized: MetaSized {}
 
 #[lang = "default_trait1"]
 auto trait DefaultTrait1 {}
diff --git a/tests/ui/traits/default_auto_traits/default-bounds.rs b/tests/ui/traits/default_auto_traits/default-bounds.rs
index 64733a40034..8535f82fc01 100644
--- a/tests/ui/traits/default_auto_traits/default-bounds.rs
+++ b/tests/ui/traits/default_auto_traits/default-bounds.rs
@@ -11,8 +11,14 @@
 #![no_std]
 #![no_core]
 
+#[lang = "pointee_sized"]
+trait PointeeSized {}
+
+#[lang = "meta_sized"]
+trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+trait Sized: MetaSized {}
 
 #[lang = "copy"]
 pub trait Copy {}
diff --git a/tests/ui/traits/default_auto_traits/default-bounds.stderr b/tests/ui/traits/default_auto_traits/default-bounds.stderr
index 10fdcc43417..318fc57fc9c 100644
--- a/tests/ui/traits/default_auto_traits/default-bounds.stderr
+++ b/tests/ui/traits/default_auto_traits/default-bounds.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `Forbidden: SyncDrop` is not satisfied
-  --> $DIR/default-bounds.rs:37:9
+  --> $DIR/default-bounds.rs:43:9
    |
 LL |     bar(Forbidden);
    |     --- ^^^^^^^^^ the trait `SyncDrop` is not implemented for `Forbidden`
@@ -7,13 +7,13 @@ LL |     bar(Forbidden);
    |     required by a bound introduced by this call
    |
 note: required by a bound in `bar`
-  --> $DIR/default-bounds.rs:33:8
+  --> $DIR/default-bounds.rs:39:8
    |
 LL | fn bar<T: Leak>(_: T) {}
    |        ^ required by this bound in `bar`
 
 error[E0277]: the trait bound `Forbidden: Leak` is not satisfied
-  --> $DIR/default-bounds.rs:37:9
+  --> $DIR/default-bounds.rs:43:9
    |
 LL |     bar(Forbidden);
    |     --- ^^^^^^^^^ the trait `Leak` is not implemented for `Forbidden`
@@ -21,7 +21,7 @@ LL |     bar(Forbidden);
    |     required by a bound introduced by this call
    |
 note: required by a bound in `bar`
-  --> $DIR/default-bounds.rs:33:11
+  --> $DIR/default-bounds.rs:39:11
    |
 LL | fn bar<T: Leak>(_: T) {}
    |           ^^^^ required by this bound in `bar`
diff --git a/tests/ui/traits/default_auto_traits/extern-types.current.stderr b/tests/ui/traits/default_auto_traits/extern-types.current.stderr
index e1bd99b900f..593204382e3 100644
--- a/tests/ui/traits/default_auto_traits/extern-types.current.stderr
+++ b/tests/ui/traits/default_auto_traits/extern-types.current.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `extern_non_leak::Opaque: Leak` is not satisfied
-  --> $DIR/extern-types.rs:44:13
+  --> $DIR/extern-types.rs:50:13
    |
 LL |         foo(x);
    |         --- ^ the trait `Leak` is not implemented for `extern_non_leak::Opaque`
@@ -7,9 +7,9 @@ LL |         foo(x);
    |         required by a bound introduced by this call
    |
 note: required by a bound in `foo`
-  --> $DIR/extern-types.rs:20:8
+  --> $DIR/extern-types.rs:26:8
    |
-LL | fn foo<T: ?Sized>(_: &T) {}
+LL | fn foo<T: PointeeSized>(_: &T) {}
    |        ^ required by this bound in `foo`
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/traits/default_auto_traits/extern-types.next.stderr b/tests/ui/traits/default_auto_traits/extern-types.next.stderr
index e1bd99b900f..593204382e3 100644
--- a/tests/ui/traits/default_auto_traits/extern-types.next.stderr
+++ b/tests/ui/traits/default_auto_traits/extern-types.next.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `extern_non_leak::Opaque: Leak` is not satisfied
-  --> $DIR/extern-types.rs:44:13
+  --> $DIR/extern-types.rs:50:13
    |
 LL |         foo(x);
    |         --- ^ the trait `Leak` is not implemented for `extern_non_leak::Opaque`
@@ -7,9 +7,9 @@ LL |         foo(x);
    |         required by a bound introduced by this call
    |
 note: required by a bound in `foo`
-  --> $DIR/extern-types.rs:20:8
+  --> $DIR/extern-types.rs:26:8
    |
-LL | fn foo<T: ?Sized>(_: &T) {}
+LL | fn foo<T: PointeeSized>(_: &T) {}
    |        ^ required by this bound in `foo`
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/traits/default_auto_traits/extern-types.rs b/tests/ui/traits/default_auto_traits/extern-types.rs
index 822d4c0637f..df106d83171 100644
--- a/tests/ui/traits/default_auto_traits/extern-types.rs
+++ b/tests/ui/traits/default_auto_traits/extern-types.rs
@@ -7,8 +7,14 @@
 #![no_std]
 #![no_core]
 
+#[lang = "pointee_sized"]
+trait PointeeSized {}
+
+#[lang = "meta_sized"]
+trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+trait Sized: MetaSized {}
 
 #[lang = "copy"]
 pub trait Copy {}
@@ -17,7 +23,7 @@ pub trait Copy {}
 auto trait Leak {}
 
 // implicit T: Leak here
-fn foo<T: ?Sized>(_: &T) {}
+fn foo<T: PointeeSized>(_: &T) {}
 
 mod extern_leak {
     use crate::*;
diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs
index 49f2faba146..5069cd256b2 100644
--- a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs
+++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.rs
@@ -12,8 +12,14 @@
 #![no_std]
 #![no_core]
 
+#[lang = "pointee_sized"]
+trait PointeeSized {}
+
+#[lang = "meta_sized"]
+trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+trait Sized: MetaSized {}
 
 #[lang = "copy"]
 pub trait Copy {}
diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr
index b7ffb66e60b..48745e40268 100644
--- a/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr
+++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-dyn-traits.stderr
@@ -1,5 +1,5 @@
 error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied
-  --> $DIR/maybe-bounds-in-dyn-traits.rs:53:25
+  --> $DIR/maybe-bounds-in-dyn-traits.rs:59:25
    |
 LL |     let _: &dyn Trait = &NonLeakS;
    |                         ^^^^^^^^^ the trait `Leak` is not implemented for `NonLeakS`
@@ -7,13 +7,13 @@ LL |     let _: &dyn Trait = &NonLeakS;
    = note: required for the cast from `&NonLeakS` to `&dyn Trait + Leak`
 
 error[E0277]: the trait bound `dyn Trait: Leak` is not satisfied
-  --> $DIR/maybe-bounds-in-dyn-traits.rs:58:7
+  --> $DIR/maybe-bounds-in-dyn-traits.rs:64:7
    |
 LL |     x.leak_foo();
    |       ^^^^^^^^ the trait `Leak` is not implemented for `dyn Trait`
    |
 note: required by a bound in `Trait::leak_foo`
-  --> $DIR/maybe-bounds-in-dyn-traits.rs:45:5
+  --> $DIR/maybe-bounds-in-dyn-traits.rs:51:5
    |
 LL |     fn leak_foo(&self) {}
    |     ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait::leak_foo`
diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs
index 4cb38bc8e79..b3801baaf70 100644
--- a/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs
+++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.rs
@@ -14,8 +14,14 @@
 #![no_std]
 #![no_core]
 
+#[lang = "pointee_sized"]
+trait PointeeSized {}
+
+#[lang = "meta_sized"]
+trait MetaSized: PointeeSized {}
+
 #[lang = "sized"]
-trait Sized {}
+trait Sized: MetaSized {}
 
 #[lang = "legacy_receiver"]
 trait LegacyReceiver {}
diff --git a/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr
index 3dd8418b100..bc797c9d976 100644
--- a/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr
+++ b/tests/ui/traits/default_auto_traits/maybe-bounds-in-traits.stderr
@@ -1,23 +1,23 @@
 error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied
-  --> $DIR/maybe-bounds-in-traits.rs:61:22
+  --> $DIR/maybe-bounds-in-traits.rs:67:22
    |
 LL |         type Leak2 = NonLeakS;
    |                      ^^^^^^^^ the trait `Leak` is not implemented for `NonLeakS`
    |
 note: required by a bound in `Test3::Leak2`
-  --> $DIR/maybe-bounds-in-traits.rs:61:9
+  --> $DIR/maybe-bounds-in-traits.rs:67:9
    |
 LL |         type Leak2 = NonLeakS;
    |         ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Test3::Leak2`
 
 error[E0277]: the trait bound `Self: Leak` is not satisfied
-  --> $DIR/maybe-bounds-in-traits.rs:49:29
+  --> $DIR/maybe-bounds-in-traits.rs:55:29
    |
 LL |         type MaybeLeakSelf: TestBase1<Self> where Self: ?Leak;
    |                             ^^^^^^^^^^^^^^^ the trait `Leak` is not implemented for `Self`
    |
 note: required by a bound in `TestBase1`
-  --> $DIR/maybe-bounds-in-traits.rs:45:21
+  --> $DIR/maybe-bounds-in-traits.rs:51:21
    |
 LL |     trait TestBase1<T: ?Sized> {}
    |                     ^ required by this bound in `TestBase1`
@@ -27,7 +27,7 @@ LL |     trait Test1<T>: Leak {
    |                   ++++++
 
 error[E0658]: `&mut Self` cannot be used as the type of `self` without the `arbitrary_self_types` feature
-  --> $DIR/maybe-bounds-in-traits.rs:99:31
+  --> $DIR/maybe-bounds-in-traits.rs:105:31
    |
 LL |         fn mut_maybe_leak_foo(&mut self) where Self: ?Leak {}
    |                               ^^^^^^^^^
@@ -38,13 +38,13 @@ LL |         fn mut_maybe_leak_foo(&mut self) where Self: ?Leak {}
    = help: consider changing to `self`, `&self`, `&mut self`, or a type implementing `Receiver` such as `self: Box<Self>`, `self: Rc<Self>`, or `self: Arc<Self>`
 
 error[E0277]: the trait bound `Self: Leak` is not satisfied
-  --> $DIR/maybe-bounds-in-traits.rs:86:43
+  --> $DIR/maybe-bounds-in-traits.rs:92:43
    |
 LL |         const CNonLeak: usize = size_of::<Self>() where Self: ?Leak;
    |                                           ^^^^ the trait `Leak` is not implemented for `Self`
    |
 note: required by a bound in `size_of`
-  --> $DIR/maybe-bounds-in-traits.rs:80:22
+  --> $DIR/maybe-bounds-in-traits.rs:86:22
    |
 LL |     const fn size_of<T: ?Sized>() -> usize {
    |                      ^ required by this bound in `size_of`
@@ -54,13 +54,13 @@ LL |     trait Trait: Leak {
    |                ++++++
 
 error[E0277]: the trait bound `NonLeakS: Leak` is not satisfied
-  --> $DIR/maybe-bounds-in-traits.rs:109:18
+  --> $DIR/maybe-bounds-in-traits.rs:115:18
    |
 LL |         NonLeakS.leak_foo();
    |                  ^^^^^^^^ the trait `Leak` is not implemented for `NonLeakS`
    |
 note: required by a bound in `methods::Trait::leak_foo`
-  --> $DIR/maybe-bounds-in-traits.rs:95:9
+  --> $DIR/maybe-bounds-in-traits.rs:101:9
    |
 LL |         fn leak_foo(&self) {}
    |         ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Trait::leak_foo`
diff --git a/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.current.stderr b/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.current.stderr
index dd9393fae85..d99a4cbd378 100644
--- a/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.current.stderr
+++ b/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.current.stderr
@@ -1,20 +1,5 @@
-error[E0308]: mismatched types
-  --> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:13:23
-   |
-LL |     (MyType<'a, T>,): Sized,
-   |                       ^^^^^ lifetime mismatch
-   |
-   = note: expected trait `<MyType<'a, T> as Sized>`
-              found trait `<MyType<'static, T> as Sized>`
-note: the lifetime `'a` as defined here...
-  --> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:11:8
-   |
-LL | fn foo<'a, T: ?Sized>()
-   |        ^^
-   = note: ...does not necessarily outlive the static lifetime
-
 error: lifetime may not live long enough
-  --> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:22:5
+  --> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:20:5
    |
 LL | fn foo<'a, T: ?Sized>()
    |        -- lifetime `'a` defined here
@@ -22,6 +7,5 @@ LL | fn foo<'a, T: ?Sized>()
 LL |     is_sized::<(MyType<'a, T>,)>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
 
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.next.stderr b/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.next.stderr
index 05861877d41..d99a4cbd378 100644
--- a/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.next.stderr
+++ b/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.next.stderr
@@ -1,18 +1,5 @@
-error[E0478]: lifetime bound not satisfied
-  --> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:13:23
-   |
-LL |     (MyType<'a, T>,): Sized,
-   |                       ^^^^^
-   |
-note: lifetime parameter instantiated with the lifetime `'a` as defined here
-  --> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:11:8
-   |
-LL | fn foo<'a, T: ?Sized>()
-   |        ^^
-   = note: but lifetime parameter must outlive the static lifetime
-
 error: lifetime may not live long enough
-  --> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:22:5
+  --> $DIR/lifetime-incomplete-prefer-sized-builtin-over-wc.rs:20:5
    |
 LL | fn foo<'a, T: ?Sized>()
    |        -- lifetime `'a` defined here
@@ -20,6 +7,5 @@ LL | fn foo<'a, T: ?Sized>()
 LL |     is_sized::<(MyType<'a, T>,)>();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
 
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0478`.
diff --git a/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.rs b/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.rs
index ae7a6c9bba3..6ddc0628dd1 100644
--- a/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.rs
+++ b/tests/ui/traits/lifetime-incomplete-prefer-sized-builtin-over-wc.rs
@@ -11,8 +11,6 @@ fn is_sized<T>() {}
 fn foo<'a, T: ?Sized>()
 where
     (MyType<'a, T>,): Sized,
-    //[current]~^ ERROR mismatched types
-    //[next]~^^ ERROR lifetime bound not satisfied
     MyType<'static, T>: Sized,
 {
     // Preferring the builtin `Sized` impl of tuples
diff --git a/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr
index 8901805a20f..1eb445f4848 100644
--- a/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr
+++ b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr
@@ -12,6 +12,13 @@ LL | impl<T: Bound, U> Trait<U> for T {
    |         -----     ^^^^^^^^     ^
    |         |
    |         unsatisfied trait bound introduced here
+note: required by a bound in `Bound`
+  --> $DIR/normalizes-to-is-not-productive.rs:8:1
+   |
+LL | / trait Bound {
+LL | |     fn method();
+LL | | }
+   | |_^ required by this bound in `Bound`
 
 error[E0277]: the trait bound `Foo: Bound` is not satisfied
   --> $DIR/normalizes-to-is-not-productive.rs:47:19
diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr
index d179c805962..8d8909625ff 100644
--- a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr
+++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr
@@ -19,6 +19,23 @@ error[E0275]: overflow evaluating the requirement `<() as A<T>>::Assoc: A<T>`
 LL |         Self::Assoc: A<T>,
    |                      ^^^^
 
+error[E0275]: overflow evaluating the requirement `<() as A<T>>::Assoc: MetaSized`
+  --> $DIR/normalize-param-env-2.rs:24:22
+   |
+LL |         Self::Assoc: A<T>,
+   |                      ^^^^
+   |
+note: required by a bound in `A`
+  --> $DIR/normalize-param-env-2.rs:9:1
+   |
+LL | / trait A<T> {
+LL | |     type Assoc;
+LL | |
+LL | |     fn f()
+...  |
+LL | | }
+   | |_^ required by this bound in `A`
+
 error[E0275]: overflow evaluating the requirement `<() as A<T>>::Assoc well-formed`
   --> $DIR/normalize-param-env-2.rs:24:22
    |
@@ -46,6 +63,6 @@ LL |     where
 LL |         Self::Assoc: A<T>,
    |                      ^^^^ required by this bound in `A::f`
 
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr
index f5fd9ce9864..9f7f74f9466 100644
--- a/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr
+++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr
@@ -4,6 +4,20 @@ error[E0275]: overflow evaluating the requirement `<T as Trait>::Assoc: Trait`
 LL |     <T as Trait>::Assoc: Trait,
    |                          ^^^^^
 
-error: aborting due to 1 previous error
+error[E0275]: overflow evaluating the requirement `<T as Trait>::Assoc: MetaSized`
+  --> $DIR/normalize-param-env-4.rs:19:26
+   |
+LL |     <T as Trait>::Assoc: Trait,
+   |                          ^^^^^
+   |
+note: required by a bound in `Trait`
+  --> $DIR/normalize-param-env-4.rs:7:1
+   |
+LL | / trait Trait {
+LL | |     type Assoc;
+LL | | }
+   | |_^ required by this bound in `Trait`
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/traits/non_lifetime_binders/basic.rs b/tests/ui/traits/non_lifetime_binders/basic.rs
index 533891bf830..09c0244ec95 100644
--- a/tests/ui/traits/non_lifetime_binders/basic.rs
+++ b/tests/ui/traits/non_lifetime_binders/basic.rs
@@ -1,12 +1,15 @@
 //@ check-pass
 // Basic test that show's we can successfully typeck a `for<T>` where clause.
 
+#![feature(sized_hierarchy)]
 #![feature(non_lifetime_binders)]
 //~^ WARN the feature `non_lifetime_binders` is incomplete
 
-trait Trait {}
+use std::marker::PointeeSized;
 
-impl<T: ?Sized> Trait for T {}
+trait Trait: PointeeSized {}
+
+impl<T: PointeeSized> Trait for T {}
 
 fn foo()
 where
diff --git a/tests/ui/traits/non_lifetime_binders/basic.stderr b/tests/ui/traits/non_lifetime_binders/basic.stderr
index 0fd16c5d0ee..9f2df2238d1 100644
--- a/tests/ui/traits/non_lifetime_binders/basic.stderr
+++ b/tests/ui/traits/non_lifetime_binders/basic.stderr
@@ -1,5 +1,5 @@
 warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/basic.rs:4:12
+  --> $DIR/basic.rs:5:12
    |
 LL | #![feature(non_lifetime_binders)]
    |            ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.rs b/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.rs
index 74c23a59bee..22044c2e662 100644
--- a/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.rs
+++ b/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.rs
@@ -1,11 +1,14 @@
 // Make sure not to construct predicates with escaping bound vars in `diagnostic_hir_wf_check`.
 // Regression test for <https://github.com/rust-lang/rust/issues/139330>.
 
+#![feature(sized_hierarchy)]
 #![feature(non_lifetime_binders)]
 //~^ WARN the feature `non_lifetime_binders` is incomplete
 
-trait A<T: ?Sized> {}
-impl<T: ?Sized> A<T> for () {}
+use std::marker::PointeeSized;
+
+trait A<T: PointeeSized> {}
+impl<T: PointeeSized> A<T> for () {}
 
 trait B {}
 struct W<T: B>(T);
diff --git a/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.stderr b/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.stderr
index df99f4a67ab..8270fbeef0f 100644
--- a/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.stderr
+++ b/tests/ui/traits/non_lifetime_binders/diagnostic-hir-wf-check.stderr
@@ -1,5 +1,5 @@
 warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/diagnostic-hir-wf-check.rs:4:12
+  --> $DIR/diagnostic-hir-wf-check.rs:5:12
    |
 LL | #![feature(non_lifetime_binders)]
    |            ^^^^^^^^^^^^^^^^^^^^
@@ -8,24 +8,24 @@ LL | #![feature(non_lifetime_binders)]
    = note: `#[warn(incomplete_features)]` on by default
 
 error[E0277]: the trait bound `(): B` is not satisfied
-  --> $DIR/diagnostic-hir-wf-check.rs:13:12
+  --> $DIR/diagnostic-hir-wf-check.rs:16:12
    |
 LL | fn b() -> (W<()>, impl for<C> A<C>) { (W(()), ()) }
    |            ^^^^^ the trait `B` is not implemented for `()`
    |
 help: this trait has no implementations, consider adding one
-  --> $DIR/diagnostic-hir-wf-check.rs:10:1
+  --> $DIR/diagnostic-hir-wf-check.rs:13:1
    |
 LL | trait B {}
    | ^^^^^^^
 note: required by a bound in `W`
-  --> $DIR/diagnostic-hir-wf-check.rs:11:13
+  --> $DIR/diagnostic-hir-wf-check.rs:14:13
    |
 LL | struct W<T: B>(T);
    |             ^ required by this bound in `W`
 
 error[E0277]: the trait bound `(): B` is not satisfied
-  --> $DIR/diagnostic-hir-wf-check.rs:13:42
+  --> $DIR/diagnostic-hir-wf-check.rs:16:42
    |
 LL | fn b() -> (W<()>, impl for<C> A<C>) { (W(()), ()) }
    |                                        - ^^ the trait `B` is not implemented for `()`
@@ -33,29 +33,29 @@ LL | fn b() -> (W<()>, impl for<C> A<C>) { (W(()), ()) }
    |                                        required by a bound introduced by this call
    |
 help: this trait has no implementations, consider adding one
-  --> $DIR/diagnostic-hir-wf-check.rs:10:1
+  --> $DIR/diagnostic-hir-wf-check.rs:13:1
    |
 LL | trait B {}
    | ^^^^^^^
 note: required by a bound in `W`
-  --> $DIR/diagnostic-hir-wf-check.rs:11:13
+  --> $DIR/diagnostic-hir-wf-check.rs:14:13
    |
 LL | struct W<T: B>(T);
    |             ^ required by this bound in `W`
 
 error[E0277]: the trait bound `(): B` is not satisfied
-  --> $DIR/diagnostic-hir-wf-check.rs:13:40
+  --> $DIR/diagnostic-hir-wf-check.rs:16:40
    |
 LL | fn b() -> (W<()>, impl for<C> A<C>) { (W(()), ()) }
    |                                        ^^^^^ the trait `B` is not implemented for `()`
    |
 help: this trait has no implementations, consider adding one
-  --> $DIR/diagnostic-hir-wf-check.rs:10:1
+  --> $DIR/diagnostic-hir-wf-check.rs:13:1
    |
 LL | trait B {}
    | ^^^^^^^
 note: required by a bound in `W`
-  --> $DIR/diagnostic-hir-wf-check.rs:11:13
+  --> $DIR/diagnostic-hir-wf-check.rs:14:13
    |
 LL | struct W<T: B>(T);
    |             ^ required by this bound in `W`
diff --git a/tests/ui/traits/non_lifetime_binders/on-rpit.rs b/tests/ui/traits/non_lifetime_binders/on-rpit.rs
index 4d1cacb1890..1364f63a373 100644
--- a/tests/ui/traits/non_lifetime_binders/on-rpit.rs
+++ b/tests/ui/traits/non_lifetime_binders/on-rpit.rs
@@ -1,11 +1,14 @@
 //@ check-pass
 
+#![feature(sized_hierarchy)]
 #![feature(non_lifetime_binders)]
 //~^ WARN the feature `non_lifetime_binders` is incomplete
 
-trait Trait<T: ?Sized> {}
+use std::marker::PointeeSized;
 
-impl<T: ?Sized> Trait<T> for i32 {}
+trait Trait<T: PointeeSized> {}
+
+impl<T: PointeeSized> Trait<T> for i32 {}
 
 fn produce() -> impl for<T> Trait<T> {
     16
diff --git a/tests/ui/traits/non_lifetime_binders/on-rpit.stderr b/tests/ui/traits/non_lifetime_binders/on-rpit.stderr
index 34c56068c5c..c8396c38548 100644
--- a/tests/ui/traits/non_lifetime_binders/on-rpit.stderr
+++ b/tests/ui/traits/non_lifetime_binders/on-rpit.stderr
@@ -1,5 +1,5 @@
 warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/on-rpit.rs:3:12
+  --> $DIR/on-rpit.rs:4:12
    |
 LL | #![feature(non_lifetime_binders)]
    |            ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs
index 96345732f0f..aab5479334e 100644
--- a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs
+++ b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs
@@ -1,19 +1,22 @@
+#![feature(sized_hierarchy)]
 #![feature(non_lifetime_binders)]
 //~^ WARN the feature `non_lifetime_binders` is incomplete
 
+use std::marker::PointeeSized;
+
 trait Foo: for<T> Bar<T> {}
 
-trait Bar<T: ?Sized> {
+trait Bar<T: PointeeSized>: PointeeSized {
     fn method(&self) {}
 }
 
-fn needs_bar(x: &(impl Bar<i32> + ?Sized)) {
+fn needs_bar(x: &(impl Bar<i32> + PointeeSized)) {
     x.method();
 }
 
 impl Foo for () {}
 
-impl<T: ?Sized> Bar<T> for () {}
+impl<T: PointeeSized> Bar<T> for () {}
 
 fn main() {
     let x: &dyn Foo = &();
diff --git a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr
index aead19c4527..b32915ff549 100644
--- a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr
+++ b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr
@@ -1,5 +1,5 @@
 warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/supertrait-dyn-compatibility.rs:1:12
+  --> $DIR/supertrait-dyn-compatibility.rs:2:12
    |
 LL | #![feature(non_lifetime_binders)]
    |            ^^^^^^^^^^^^^^^^^^^^
@@ -8,14 +8,14 @@ LL | #![feature(non_lifetime_binders)]
    = note: `#[warn(incomplete_features)]` on by default
 
 error[E0038]: the trait `Foo` is not dyn compatible
-  --> $DIR/supertrait-dyn-compatibility.rs:19:17
+  --> $DIR/supertrait-dyn-compatibility.rs:22:17
    |
 LL |     let x: &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/supertrait-dyn-compatibility.rs:4:12
+  --> $DIR/supertrait-dyn-compatibility.rs:7:12
    |
 LL | trait Foo: for<T> Bar<T> {}
    |       ---  ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables
diff --git a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.current.stderr b/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.current.stderr
index 3e5854ea1c8..6551253d2e9 100644
--- a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.current.stderr
+++ b/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.current.stderr
@@ -1,5 +1,5 @@
 warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/unifying-placeholders-in-query-response-2.rs:6:12
+  --> $DIR/unifying-placeholders-in-query-response-2.rs:7:12
    |
 LL | #![feature(non_lifetime_binders)]
    |            ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.next.stderr b/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.next.stderr
index 3e5854ea1c8..6551253d2e9 100644
--- a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.next.stderr
+++ b/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.next.stderr
@@ -1,5 +1,5 @@
 warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/unifying-placeholders-in-query-response-2.rs:6:12
+  --> $DIR/unifying-placeholders-in-query-response-2.rs:7:12
    |
 LL | #![feature(non_lifetime_binders)]
    |            ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.rs b/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.rs
index 2066887ea59..d900bd429e6 100644
--- a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.rs
+++ b/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response-2.rs
@@ -3,19 +3,22 @@
 //@[next] compile-flags: -Znext-solver
 //@ check-pass
 
+#![feature(sized_hierarchy)]
 #![feature(non_lifetime_binders)]
 //~^ WARN the feature `non_lifetime_binders` is incomplete
 
-trait Id {
-    type Output: ?Sized;
+use std::marker::PointeeSized;
+
+trait Id: PointeeSized {
+    type Output: PointeeSized;
 }
 
-impl<T: ?Sized> Id for T {
+impl<T: PointeeSized> Id for T {
     type Output = T;
 }
 
-trait Everyone {}
-impl<T: ?Sized> Everyone for T {}
+trait Everyone: PointeeSized {}
+impl<T: PointeeSized> Everyone for T {}
 
 fn hello() where for<T> <T as Id>::Output: Everyone {}
 
diff --git a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.current.stderr b/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.current.stderr
index 0224e5763e0..fecdc860f8e 100644
--- a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.current.stderr
+++ b/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.current.stderr
@@ -1,5 +1,5 @@
 warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/unifying-placeholders-in-query-response.rs:6:12
+  --> $DIR/unifying-placeholders-in-query-response.rs:7:12
    |
 LL | #![feature(non_lifetime_binders)]
    |            ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.next.stderr b/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.next.stderr
index 0224e5763e0..fecdc860f8e 100644
--- a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.next.stderr
+++ b/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.next.stderr
@@ -1,5 +1,5 @@
 warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/unifying-placeholders-in-query-response.rs:6:12
+  --> $DIR/unifying-placeholders-in-query-response.rs:7:12
    |
 LL | #![feature(non_lifetime_binders)]
    |            ^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.rs b/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.rs
index 5334118e9ac..04e34531f4d 100644
--- a/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.rs
+++ b/tests/ui/traits/non_lifetime_binders/unifying-placeholders-in-query-response.rs
@@ -3,15 +3,18 @@
 //@[next] compile-flags: -Znext-solver
 //@ check-pass
 
+#![feature(sized_hierarchy)]
 #![feature(non_lifetime_binders)]
 //~^ WARN the feature `non_lifetime_binders` is incomplete
 
-pub trait Foo<T: ?Sized> {
-    type Bar<K: ?Sized>: ?Sized;
+use std::marker::PointeeSized;
+
+pub trait Foo<T: PointeeSized> {
+    type Bar<K: PointeeSized>: PointeeSized;
 }
 
 impl Foo<usize> for () {
-    type Bar<K: ?Sized> = K;
+    type Bar<K: PointeeSized> = K;
 }
 
 pub fn f<T1, T2>(a: T1, b: T2)
diff --git a/tests/ui/traits/non_lifetime_binders/universe-error1.rs b/tests/ui/traits/non_lifetime_binders/universe-error1.rs
index eadee6b711e..b4e8e3a8aad 100644
--- a/tests/ui/traits/non_lifetime_binders/universe-error1.rs
+++ b/tests/ui/traits/non_lifetime_binders/universe-error1.rs
@@ -1,12 +1,15 @@
+#![feature(sized_hierarchy)]
 #![feature(non_lifetime_binders)]
 //~^ WARN the feature `non_lifetime_binders` is incomplete
 
-trait Other<U: ?Sized> {}
+use std::marker::PointeeSized;
 
-impl<U: ?Sized> Other<U> for U {}
+trait Other<U: PointeeSized>: PointeeSized {}
+
+impl<U: PointeeSized> Other<U> for U {}
 
 #[rustfmt::skip]
-fn foo<U: ?Sized>()
+fn foo<U: PointeeSized>()
 where
     for<T> T: Other<U> {}
 
diff --git a/tests/ui/traits/non_lifetime_binders/universe-error1.stderr b/tests/ui/traits/non_lifetime_binders/universe-error1.stderr
index ecc97e283be..b997e7379e2 100644
--- a/tests/ui/traits/non_lifetime_binders/universe-error1.stderr
+++ b/tests/ui/traits/non_lifetime_binders/universe-error1.stderr
@@ -1,5 +1,5 @@
 warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes
-  --> $DIR/universe-error1.rs:1:12
+  --> $DIR/universe-error1.rs:2:12
    |
 LL | #![feature(non_lifetime_binders)]
    |            ^^^^^^^^^^^^^^^^^^^^
@@ -8,15 +8,15 @@ LL | #![feature(non_lifetime_binders)]
    = note: `#[warn(incomplete_features)]` on by default
 
 error[E0277]: the trait bound `T: Other<_>` is not satisfied
-  --> $DIR/universe-error1.rs:14:11
+  --> $DIR/universe-error1.rs:17:11
    |
 LL |     foo::<_>();
    |           ^ the trait `Other<_>` is not implemented for `T`
    |
 note: required by a bound in `foo`
-  --> $DIR/universe-error1.rs:11:15
+  --> $DIR/universe-error1.rs:14:15
    |
-LL | fn foo<U: ?Sized>()
+LL | fn foo<U: PointeeSized>()
    |    --- required by a bound in this function
 LL | where
 LL |     for<T> T: Other<U> {}
diff --git a/tests/ui/traits/resolve-impl-before-constrain-check.rs b/tests/ui/traits/resolve-impl-before-constrain-check.rs
index 87f9c241e40..50d1a874551 100644
--- a/tests/ui/traits/resolve-impl-before-constrain-check.rs
+++ b/tests/ui/traits/resolve-impl-before-constrain-check.rs
@@ -15,6 +15,7 @@ use foo::*;
 
 fn test() -> impl Sized {
     <() as Callable>::call()
+//~^ ERROR: type annotations needed
 }
 
 fn main() {}
diff --git a/tests/ui/traits/resolve-impl-before-constrain-check.stderr b/tests/ui/traits/resolve-impl-before-constrain-check.stderr
index e8e569ba625..13fbfdb855c 100644
--- a/tests/ui/traits/resolve-impl-before-constrain-check.stderr
+++ b/tests/ui/traits/resolve-impl-before-constrain-check.stderr
@@ -4,6 +4,13 @@ error[E0207]: the type parameter `V` is not constrained by the impl trait, self
 LL |     impl<V: ?Sized> Callable for () {
    |          ^ unconstrained type parameter
 
-error: aborting due to 1 previous error
+error[E0282]: type annotations needed
+  --> $DIR/resolve-impl-before-constrain-check.rs:17:6
+   |
+LL |     <() as Callable>::call()
+   |      ^^ cannot infer type for type parameter `V`
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0207`.
+Some errors have detailed explanations: E0207, E0282.
+For more information about an error, try `rustc --explain E0207`.
diff --git a/tests/ui/traits/unconstrained-projection-normalization-2.next.stderr b/tests/ui/traits/unconstrained-projection-normalization-2.next.stderr
index 2bb389c6ec1..3eacab33e46 100644
--- a/tests/ui/traits/unconstrained-projection-normalization-2.next.stderr
+++ b/tests/ui/traits/unconstrained-projection-normalization-2.next.stderr
@@ -4,6 +4,13 @@ error[E0207]: the type parameter `T` is not constrained by the impl trait, self
 LL | impl<T: ?Sized> Every for Thing {
    |      ^ unconstrained type parameter
 
-error: aborting due to 1 previous error
+error[E0282]: type annotations needed
+  --> $DIR/unconstrained-projection-normalization-2.rs:19:11
+   |
+LL | fn foo(_: <Thing as Every>::Assoc) {}
+   |           ^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for associated type `<Thing as Every>::Assoc`
+
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0207`.
+Some errors have detailed explanations: E0207, E0282.
+For more information about an error, try `rustc --explain E0207`.
diff --git a/tests/ui/traits/unconstrained-projection-normalization-2.rs b/tests/ui/traits/unconstrained-projection-normalization-2.rs
index 6b584c436c6..9d95c73eea7 100644
--- a/tests/ui/traits/unconstrained-projection-normalization-2.rs
+++ b/tests/ui/traits/unconstrained-projection-normalization-2.rs
@@ -17,5 +17,6 @@ impl<T: ?Sized> Every for Thing {
 }
 
 fn foo(_: <Thing as Every>::Assoc) {}
+//[next]~^ ERROR: type annotations needed
 
 fn main() {}